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 create_swapchain(void);
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);
31 static VkPhysicalDevice vkpdev;
32 static int vkqfam_idx, vkqfam_maxq;
33 static VkDevice vkdev;
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;
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;
49 static VkPhysicalDevice *pdev_list;
50 static uint32_t num_pdev;
52 static int have_raytrace, have_debug_report;
54 void vk_init_xwin(Display *d, Window w)
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;
78 for(i=0; i<vksc_numimg; i++) {
79 vkDestroyImageView(vkdev, vksc_view[i], 0);
84 vkDestroySwapchainKHR(vkdev, vksc, 0);
88 vkDestroyDevice(vkdev, 0);
92 vkDestroySurfaceKHR(vk, vksurf, 0);
96 vkDestroyInstance(vk, 0);
109 int vk_reshape(int xsz, int ysz)
113 if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
118 for(i=0; i<vksc_numimg; i++) {
119 vkDestroyImageView(vkdev, vksc_view[i], 0);
122 if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
124 vksc_extent.width = xsz;
125 vksc_extent.height = ysz;
127 return create_swapchain();
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"
144 } known_instext_list[] = {
145 {"VK_KHR_surface", 1},
147 {"VK_KHR_win32_surface", 1},
149 /*{"VK_KHR_xlib_surface", 1},*/
150 {"VK_KHR_xcb_surface", 1},
152 {"VK_KHR_debug_report", 0}
158 } known_devext_list[] = {
159 {"VK_KHR_swapchain", 1},
160 {"VK_KHR_acceleration_structure", 0},
161 {"VK_KHR_ray_tracing_pipeline", 0}
164 static int create_instance(void)
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)];
173 vkEnumerateInstanceVersion(&apiver);
174 printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
175 (apiver >> 12) & 0x3ff, apiver & 0xfff);
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;
183 vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
184 inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
185 vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
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);
192 for(i=0; i<inst_layers_count; i++) {
193 printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
195 printf("Instance extensions:\n");
196 for(i=0; i<inst_ext_count; i++) {
197 printf(" - %s\n", inst_ext[i].extensionName);
200 have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
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];
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);
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");
232 static int create_surface(void)
235 VkXlibSurfaceCreateInfoKHR xinf = {0};
236 xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
240 if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
241 fprintf(stderr, "failed to create Xlib window surface\n");
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;
250 if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
251 fprintf(stderr, "failed to create XCB window surface\n");
257 int choose_phys_dev(void)
259 uint32_t i, num_pdev, num_qfam, score, best_score, best_dev;
260 VkPhysicalDevice *pdev;
261 VkPhysicalDeviceProperties pdevprop;
262 VkQueueFamilyProperties *qfam;
265 vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
267 fprintf(stderr, "no vulkan devices found\n");
270 pdev = malloc_nf(num_pdev * sizeof *pdev);
271 vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
273 printf("Found %d physical devices\n", num_pdev);
277 for(i=0; i<num_pdev; i++) {
278 if((score = eval_pdev_score(pdev[i])) && score > best_score) {
283 vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
284 printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
287 fprintf(stderr, "no suitable vulkan device found\n");
291 vkpdev = pdev[best_dev];
293 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
294 qfam = malloc_nf(num_qfam * sizeof *qfam);
295 vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
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;
313 static int create_device(void)
316 VkDeviceQueueCreateInfo qinf = {0};
317 VkPhysicalDeviceFeatures feat = {0};
318 VkDeviceCreateInfo devinf = {0};
319 const char *ext[ARRSZ(known_devext_list)];
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);
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);
337 qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
338 qinf.queueFamilyIndex = vkqfam_idx;
340 qinf.pQueuePriorities = &prio;
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;
349 if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
350 fprintf(stderr, "failed to create vulkan device\n");
354 vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
358 static int create_swapchain(void)
362 VkSwapchainCreateInfoKHR scinf = {0};
363 VkImageViewCreateInfo ivinf;
365 if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
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;
383 if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
384 fprintf(stderr, "failed to create swapchain\n");
388 if(!vksc_img || vksc_numimg != num) {
390 vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
391 vksc_img = malloc_nf(num * sizeof *vksc_img);
392 vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
394 if(!vksc_view || vksc_numimg != num) {
396 vksc_view = malloc_nf(num * sizeof *vksc_view);
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;
414 if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
415 fprintf(stderr, "failed to create image view (%d)\n", i);
423 static int eval_pdev_score(VkPhysicalDevice dev)
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;
433 vkGetPhysicalDeviceProperties(dev, &prop);
434 vkGetPhysicalDeviceFeatures(dev, &feat);
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);
441 if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
446 /* populate format and present modes arrays, and make sure we have some of each */
447 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
452 sfmt = malloc_nf(num_fmt * sizeof *sfmt);
453 vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
455 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
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);
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) {
478 static int choose_pixfmt(void)
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
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);
495 for(i=0; i<num_fmt; i++) {
496 if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
499 for(j=0; j<sizeof pref / sizeof *pref; j++) {
500 if(vksurf_fmt[i].format == pref[j]) {
502 vksurf_numfmt = num_fmt;
513 static int have_inst_layer(const char *name)
516 for(i=0; i<inst_layers_count; i++) {
517 if(strcmp(inst_layers[i].layerName, name) == 0) {
524 static int have_ext(VkExtensionProperties *ext, int next, const char *name)
527 for(i=0; i<next; i++) {
528 if(strcmp(ext[i].extensionName, name) == 0) {