vkCreateXlibSurfaceKHR hangs forever
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 20 Dec 2021 04:57:01 +0000 (06:57 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 20 Dec 2021 04:57:01 +0000 (06:57 +0200)
Makefile
src/main_x11.c
src/vk.c
src/vk.h

index b9931ac..3ed975a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,9 @@ bin = vkray
 sdr = $(wildcard sdr/*.glsl)
 spirv = $(sdr:.glsl=.spv)
 
-CFLAGS = -pedantic -Wall -g -MMD
+warn = -pedantic -Wall -Wno-unused-variable
+
+CFLAGS = $(warn) -g -MMD
 LDFLAGS = -lvulkan -lX11
 
 $(bin): $(obj) $(spirv)
index d593494..6ff15b8 100644 (file)
@@ -3,6 +3,7 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include "app.h"
+#include "vk.h"
 
 static Window create_window(const char *title, int xsz, int ysz);
 static void handle_event(XEvent *ev);
@@ -31,6 +32,7 @@ int main(int argc, char **argv)
        if(!(win = create_window("vkray", 1280, 800))) {
                return 1;
        }
+       vk_init_xwin(dpy, win);
 
        if(app_init() == -1) {
                goto end;
index edc3bf1..e07dbf9 100644 (file)
--- a/src/vk.c
+++ b/src/vk.c
@@ -5,13 +5,35 @@
 #include "vk.h"
 #include "util.h"
 
+#ifdef __WIN32__
+#include <vulkan/vulkan_win32.h>
+#else
+#include <vulkan/vulkan_xlib.h>
+#endif
+
 static int create_instance(void);
+static int create_surface(void);
+static int choose_phys_dev(void);
 static int create_device(void);
+static int choose_pixfmt(void);
+static int eval_pdev_score(VkPhysicalDevice dev);
 static int have_inst_layer(const char *name);
-static int have_inst_ext(const char *name);
-static int have_dev_ext(const char *name);
+static int have_ext(VkExtensionProperties *ext, int next, const char *name);
+
+static Display *dpy;
+static Window win;
 
 static VkInstance vk;
+static VkPhysicalDevice vkpdev;
+static int vkqfam_idx = -1;
+static VkDevice vkdev;
+static VkQueue vkq;
+static VkSurfaceKHR vksurf;
+static VkSurfaceCapabilitiesKHR vksurf_caps;
+static int vksurf_numfmt, vksurf_selfmt;
+static VkSurfaceFormatKHR *vksurf_fmt;
+static VkSwapchainKHR vksc;
+static int vksc_numimg;
 
 static VkLayerProperties *inst_layers;
 static VkExtensionProperties *inst_ext, *dev_ext;
@@ -22,6 +44,30 @@ static uint32_t num_pdev;
 
 static int have_raytrace, have_debug_report;
 
+void vk_init_xwin(Display *d, Window w)
+{
+       dpy = d;
+       win = w;
+}
+
+int vk_init(void)
+{
+       if(create_instance() == -1)     return -1;
+       if(create_surface() == -1) return -1;
+       if(choose_phys_dev() == -1) return -1;
+       if(create_device() == -1) return -1;
+       return 0;
+}
+
+void vk_cleanup(void)
+{
+       vkDestroyInstance(vk, 0);
+       free(inst_layers);
+       free(inst_ext);
+       free(pdev_list);
+}
+
+
 #define ARRSZ(arr)     (sizeof arr / sizeof *arr)
 static const char *known_layer_list[] = {
        "VK_LAYER_GOOGLE_threading",
@@ -36,45 +82,23 @@ static const char *known_layer_list[] = {
 static struct {
        const char *name;
        int required;
-} known_ext_list[] = {
+} known_instext_list[] = {
        {"VK_KHR_surface", 1},
 #ifdef __WIN32__
        {"VK_KHR_win32_surface", 1},
 #else
        {"VK_KHR_xlib_surface", 1},
 #endif
-       {"VK_KHR_debug_report", 0},
-       {"VK_KHR_acceleration_structure", 0},
-       {"VK_KHR_ray_tracing_pipeline", 0}
+       {"VK_KHR_debug_report", 0}
 };
 
-int vk_init(void)
-{
-       if(create_instance() == -1) {
-               return -1;
-       }
-       if(create_device() == -1) {
-               return -1;
-       }
-       return 0;
-}
-
-void vk_cleanup(void)
-{
-       vkDestroyInstance(vk, 0);
-       free(inst_layers);
-       free(inst_ext);
-       free(pdev_list);
-}
-
-
 static int create_instance(void)
 {
        int i, nlayers = 0, next = 0;
        VkInstanceCreateInfo instinf;
        VkApplicationInfo appinf;
        const char *layers[ARRSZ(known_layer_list)];
-       const char *ext[ARRSZ(known_ext_list)];
+       const char *ext[ARRSZ(known_instext_list)];
        uint32_t apiver;
 
        vkEnumerateInstanceVersion(&apiver);
@@ -104,20 +128,19 @@ static int create_instance(void)
                printf(" - %s\n", inst_ext[i].extensionName);
        }
 
-       have_raytrace = have_inst_ext("VK_KHR_ray_tracing_pipeline");
-       have_debug_report = have_inst_ext("VK_KHR_debug_report");
+       have_debug_report = have_ext(inst_ext, inst_ext_count, "VK_KHR_debug_report");
 
        for(i=0; i<ARRSZ(known_layer_list); i++) {
                if(have_inst_layer(known_layer_list[i])) {
                        layers[nlayers++] = known_layer_list[i];
                }
        }
-       for(i=0; i<ARRSZ(known_ext_list); i++) {
-               if(have_inst_ext(known_ext_list[i].name)) {
-                       ext[next++] = known_ext_list[i].name;
-               } else if(known_ext_list[i].required) {
+       for(i=0; i<ARRSZ(known_instext_list); i++) {
+               if(have_ext(inst_ext, inst_ext_count, known_instext_list[i].name)) {
+                       ext[next++] = known_instext_list[i].name;
+               } else if(known_instext_list[i].required) {
                        fprintf(stderr, "Vulkan implementation lacks required instance extension: %s\n",
-                                       known_ext_list[i].name);
+                                       known_instext_list[i].name);
                        return -1;
                }
        }
@@ -137,47 +160,157 @@ static int create_instance(void)
        return 0;
 }
 
-static int create_device(void)
+static int create_surface(void)
 {
-       int i;
-       VkPhysicalDeviceProperties2 pdevprop2;
-       VkPhysicalDeviceRayTracingPipelinePropertiesKHR raypipe_prop;
-       VkPhysicalDeviceAccelerationStructurePropertiesKHR rayacc_prop;
+       VkXlibSurfaceCreateInfoKHR xinf = {0};
+       xinf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
+       xinf.dpy = dpy;
+       xinf.window = win;
+
+       if(vkCreateXlibSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
+               fprintf(stderr, "failed to create Xlib window surface\n");
+               return -1;
+       }
+       return 0;
+}
+
+int choose_phys_dev(void)
+{
+       uint32_t i, num_pdev, score, best_score, best_dev;
+       VkPhysicalDevice *pdev;
+       VkPhysicalDeviceProperties pdevprop;
 
        vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
-       pdev_list = malloc_nf(num_pdev * sizeof *pdev_list);
-       vkEnumeratePhysicalDevices(vk, &num_pdev, pdev_list);
+       if(!num_pdev) {
+               fprintf(stderr, "no vulkan devices found\n");
+               return -1;
+       }
+       pdev = malloc_nf(num_pdev * sizeof *pdev);
+       vkEnumeratePhysicalDevices(vk, &num_pdev, pdev);
 
        printf("Found %d physical devices\n", num_pdev);
-       for(i=0; i<num_pdev; i++) {
-               if(have_raytrace) {
-                       memset(&rayacc_prop, 0, sizeof rayacc_prop);
-                       rayacc_prop.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
 
-                       memset(&raypipe_prop, 0, sizeof raypipe_prop);
-                       raypipe_prop.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
-                       raypipe_prop.pNext = &rayacc_prop;
+       best_score = 0;
+       best_dev = -1;
+       for(i=0; i<num_pdev; i++) {
+               if((score = eval_pdev_score(pdev[i])) && score > best_score) {
+                       best_score = score;
+                       best_dev = i;
                }
 
-               memset(&pdevprop2, 0, sizeof pdevprop2);
-               pdevprop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-               pdevprop2.pNext = have_raytrace ? &raypipe_prop : 0;
-
-               vkGetPhysicalDeviceProperties2(pdev_list[i], &pdevprop2);
-               printf(" %d: %s\n", i, pdevprop2.properties.deviceName);
-               if(have_raytrace) {
-                       printf("  Raytracing properties:\n");
-                       printf("    max ray recursion: %u\n", raypipe_prop.maxRayRecursionDepth);
-                       printf("    max ray dispatch: %u\n", raypipe_prop.maxRayDispatchInvocationCount);
-                       printf("    max leaf geometry: %llu\n", (unsigned long long)rayacc_prop.maxGeometryCount);
-                       printf("    max leaf primitves: %llu\n", (unsigned long long)rayacc_prop.maxPrimitiveCount);
-                       printf("    max instances: %llu\n", (unsigned long long)rayacc_prop.maxInstanceCount);
+               vkGetPhysicalDeviceProperties(pdev[i], &pdevprop);
+               printf(" %d: %s (score: %d)\n", i, pdevprop.deviceName, score);
+       }
+       if(best_dev == -1) {
+               fprintf(stderr, "no suitable vulkan device found\n");
+               free(pdev);
+               return -1;
+       }
+
+       vkpdev = pdev[i];
+
+       free(pdev);
+       choose_pixfmt();
+       return 0;
+}
+
+static int create_device(void)
+{
+       return 0;
+}
+
+static int eval_pdev_score(VkPhysicalDevice dev)
+{
+       uint32_t i, num_fmt, num_qfam, num_ext;
+       VkQueueFamilyProperties *qfam;
+       VkExtensionProperties *ext;
+       VkPhysicalDeviceProperties prop;
+       VkPhysicalDeviceFeatures feat;
+       VkSurfaceFormatKHR *sfmt;
+       VkBool32 can_pres;
+
+       vkGetPhysicalDeviceProperties(dev, &prop);
+       vkGetPhysicalDeviceFeatures(dev, &feat);
+
+       /* check if we have the swapchain extension */
+       vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, 0);
+       ext = malloc_nf(num_ext * sizeof *ext);
+       vkEnumerateDeviceExtensionProperties(dev, 0, &num_ext, ext);
+
+       if(!have_ext(ext, num_ext, "VK_KHR_swapchain")) {
+               free(ext);
+               return 0;
+       }
+
+       /* populate format and present modes arrays, and make sure we have some of each */
+       vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, 0);
+       if(!num_fmt) {
+               free(ext);
+               return 0;
+       }
+       sfmt = malloc_nf(num_fmt * sizeof *sfmt);
+       vkGetPhysicalDeviceSurfaceFormatsKHR(dev, vksurf, &num_fmt, sfmt);
+
+       vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev, vksurf, &vksurf_caps);
+
+       /* find a queue family which can do graphics and can present */
+       vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, 0);
+       qfam = malloc_nf(num_qfam * sizeof *qfam);
+       vkGetPhysicalDeviceQueueFamilyProperties(dev, &num_qfam, qfam);
+
+       vkqfam_idx = -1;
+       for(i=0; i<num_qfam; i++) {
+               vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, vksurf, &can_pres);
+               if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
+                       vkqfam_idx = i;
+                       free(ext);
+                       free(sfmt);
+                       free(qfam);
+                       return 1;
                }
        }
 
+       free(ext);
+       free(sfmt);
+       free(qfam);
        return 0;
 }
 
+static int choose_pixfmt(void)
+{
+       static const VkFormat pref[] = {
+               VK_FORMAT_B8G8R8_UNORM,
+               VK_FORMAT_R8G8B8_UNORM,
+               VK_FORMAT_B8G8R8A8_UNORM,
+               VK_FORMAT_R8G8B8A8_UNORM
+       };
+       int i, j;
+       uint32_t num_fmt;
+       VkSurfaceFormatKHR *sfmt;
+
+       vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
+       if(!num_fmt) return -1;
+       sfmt = malloc_nf(num_fmt * sizeof *sfmt);
+       vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, sfmt);
+
+       vksurf_selfmt = 0;
+       for(i=0; i<num_fmt; i++) {
+               if(sfmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+                       continue;
+               }
+               for(j=0; j<sizeof pref / sizeof *pref; j++) {
+                       if(sfmt[i].format == pref[j]) {
+                               vksurf_selfmt = i;
+                               free(sfmt);
+                               return i;
+                       }
+               }
+       }
+       free(sfmt);
+       return -1;
+}
+
+
 static int have_inst_layer(const char *name)
 {
        int i;
@@ -189,18 +322,13 @@ static int have_inst_layer(const char *name)
        return 0;
 }
 
-static int have_inst_ext(const char *name)
+static int have_ext(VkExtensionProperties *ext, int next, const char *name)
 {
        int i;
-       for(i=0; i<inst_ext_count; i++) {
-               if(strcmp(inst_ext[i].extensionName, name) == 0) {
+       for(i=0; i<next; i++) {
+               if(strcmp(ext[i].extensionName, name) == 0) {
                        return 1;
                }
        }
        return 0;
 }
-
-static int have_dev_ext(const char *name)
-{
-       return 0;       /* TODO */
-}
index d30853b..5fcf16e 100644 (file)
--- a/src/vk.h
+++ b/src/vk.h
@@ -1,6 +1,10 @@
 #ifndef VK_H_
 #define VK_H_
 
+#include <X11/Xlib.h>
+
+void vk_init_xwin(Display *dpy, Window win);
+
 int vk_init(void);
 void vk_cleanup(void);