4 #include <vulkan/vulkan.h>
9 #include <vulkan/vulkan_win32.h>
11 /*#include <vulkan/vulkan_xlib.h>*/
12 #include <X11/Xlib-xcb.h>
13 #include <vulkan/vulkan_xcb.h>
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);
29 static VkPhysicalDevice vkpdev;
30 static int vkqfam_idx, vkqfam_maxq;
31 static VkDevice vkdev;
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;
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;
44 static VkPhysicalDevice *pdev_list;
45 static uint32_t num_pdev;
47 static int have_raytrace, have_debug_report;
49 void vk_init_xwin(Display *d, Window w)
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;
66 vkDestroyInstance(vk, 0);
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"
87 } known_instext_list[] = {
88 {"VK_KHR_surface", 1},
90 {"VK_KHR_win32_surface", 1},
92 /*{"VK_KHR_xlib_surface", 1},*/
93 {"VK_KHR_xcb_surface", 1},
95 {"VK_KHR_debug_report", 0}
101 } known_devext_list[] = {
102 {"VK_KHR_swapchain", 1},
103 {"VK_KHR_acceleration_structure", 0},
104 {"VK_KHR_ray_tracing_pipeline", 0}
107 static int create_instance(void)
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)];
116 vkEnumerateInstanceVersion(&apiver);
117 printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
118 (apiver >> 12) & 0x3ff, apiver & 0xfff);
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;
126 vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
127 inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
128 vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
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);
135 for(i=0; i<inst_layers_count; i++) {
136 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
138 printf("Instance extensions:\n");
139 for(i=0; i<inst_ext_count; i++) {
140 printf(" - %s\n", inst_ext[i].extensionName);
143 have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
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];
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);
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");
175 static int create_surface(void)
178 VkXlibSurfaceCreateInfoKHR xinf = {0};
179 xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
183 if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
184 fprintf(stderr, "failed to create Xlib window surface\n");
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;
193 if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
194 fprintf(stderr, "failed to create XCB window surface\n");
200 int choose_phys_dev(void)
202 uint32_t i, num_pdev, num_qfam, score, best_score, best_dev;
203 VkPhysicalDevice *pdev;
204 VkPhysicalDeviceProperties pdevprop;
205 VkQueueFamilyProperties *qfam;
207 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
209 fprintf(stderr, "no vulkan devices found\n");
212 pdev = malloc_nf(num_pdev * sizeof *pdev);
213 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
215 printf("Found %d physical devices\n", num_pdev);
219 for(i=0; i<num_pdev; i++) {
220 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
225 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
226 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
229 fprintf(stderr, "no suitable vulkan device found\n");
233 vkpdev = pdev[best_dev];
235 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
236 qfam = malloc_nf(num_qfam * sizeof *qfam);
237 vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
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;
255 static int create_device(void)
258 VkDeviceQueueCreateInfo qinf = {0};
259 VkPhysicalDeviceFeatures feat = {0};
260 VkDeviceCreateInfo devinf = {0};
261 const char *ext[ARRSZ(known_devext_list)];
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);
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);
278 qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
279 qinf.queueFamilyIndex = vkqfam_idx;
281 qinf.pQueuePriorities = &prio;
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;
290 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
291 fprintf(stderr, "failed to create vulkan device\n");
295 vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
299 static int create_swapchain(void)
302 VkSwapchainCreateInfoKHR scinf;
304 vksc_extent.width = win_width;
305 vksc_extent.height = win_height;
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;
322 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
323 fprintf(stderr, "failed to create swapchain\n");
327 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
328 vksc_img = malloc_nf(num * sizeof *vksc_img);
329 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
336 static int eval_pdev_score(VkPhysicalDevice dev)
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;
346 vkGetPhysicalDeviceProperties(dev, &prop);
347 vkGetPhysicalDeviceFeatures(dev, &feat);
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);
354 if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
359 /* populate format and present modes arrays, and make sure we have some of each */
360 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
365 sfmt = malloc_nf(num_fmt * sizeof *sfmt);
366 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
368 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
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);
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) {
391 static int choose_pixfmt(void)
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
401 VkSurfaceFormatKHR *sfmt;
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);
409 for(i=0; i<num_fmt; i++) {
410 if(sfmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
413 for(j=0; j<sizeof pref / sizeof *pref; j++) {
414 if(sfmt[i].format == pref[j]) {
426 static int have_inst_layer(const char *name)
429 for(i=0; i<inst_layers_count; i++) {
430 if(strcmp(inst_layers[i].layerName, name) == 0) {
437 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
440 for(i=0; i<next; i++) {
441 if(strcmp(ext[i].extensionName, name) == 0) {