#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;
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",
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);
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;
}
}
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;
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 */
-}