--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <vulkan/vulkan.h>
+#include "vk.h"
+#include "util.h"
+
+#ifdef __WIN32__
+#include <vulkan/vulkan_win32.h>
+#else
+/*#include <vulkan/vulkan_xlib.h>*/
+#include <X11/Xlib-xcb.h>
+#include <vulkan/vulkan_xcb.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 create_swapchain(void);
+
+static int choose_pixfmt(void);
+static int eval_pdev_score(VkPhysicalDevice dev);
+static int have_inst_layer(const char *name);
+static int have_ext(VkExtensionProperties *ext, int next, const char *name);
+
+static Display *dpy;
+static Window win;
+static int initflags;
+
+static VkInstance vk;
+static VkPhysicalDevice vkpdev;
+static int vkqfam_idx, vkqfam_maxq;
+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 VkImage *vksc_img;
+static VkExtent2D vksc_extent;
+static VkImageView *vksc_view;
+
+static VkLayerProperties *inst_layers;
+static VkExtensionProperties *inst_ext, *dev_ext;
+static uint32_t inst_ext_count, dev_ext_count, inst_layers_count;
+
+static VkPhysicalDevice *pdev_list;
+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(unsigned int flags, unsigned int *usedflags)
+{
+ initflags = flags;
+ 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;
+
+ if(initflags != flags) {
+ if(usedflags) {
+ *usedflags = initflags;
+ } else {
+ vk_cleanup();
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void vk_cleanup(void)
+{
+ int i;
+
+ free(vksc_img);
+ vksc_img = 0;
+ free(vksc_view);
+ vksc_view = 0;
+ if(vksc_view) {
+ for(i=0; i<vksc_numimg; i++) {
+ vkDestroyImageView(vkdev, vksc_view[i], 0);
+ }
+ vksc_view = 0;
+ }
+ if(vksc) {
+ vkDestroySwapchainKHR(vkdev, vksc, 0);
+ vksc = 0;
+ }
+ if(vkdev) {
+ vkDestroyDevice(vkdev, 0);
+ vkdev = 0;
+ }
+ if(vksurf) {
+ vkDestroySurfaceKHR(vk, vksurf, 0);
+ vksurf = 0;
+ }
+ if(vk) {
+ vkDestroyInstance(vk, 0);
+ vk = 0;
+ }
+ free(inst_layers);
+ inst_layers = 0;
+ free(inst_ext);
+ inst_ext = 0;
+ free(dev_ext);
+ dev_ext = 0;
+ free(pdev_list);
+ pdev_list = 0;
+}
+
+int vk_reshape(int xsz, int ysz)
+{
+ int i;
+
+ if(vksc && vksc_extent.width == xsz && vksc_extent.height == ysz) {
+ return 0;
+ }
+
+ if(vksc_view) {
+ for(i=0; i<vksc_numimg; i++) {
+ vkDestroyImageView(vkdev, vksc_view[i], 0);
+ }
+ }
+ if(vksc) vkDestroySwapchainKHR(vkdev, vksc, 0);
+
+ vksc_extent.width = xsz;
+ vksc_extent.height = ysz;
+
+ if(create_swapchain() == -1) return -1;
+
+ /* TODO create depth/stencil buffers as needed (initflags) */
+ return 0;
+}
+
+struct rpass {
+ int used;
+ int fmt;
+ int num_colbuf;
+ int num_samples;
+ /* TODO: stuff about depth-stencil */
+ int clear;
+
+ int vkobj_valid;
+ VkRenderPass vkobj;
+};
+
+static struct rpass *rpasses;
+
+int vk_create_rpass(void)
+{
+ int i;
+ struct rpass rpass = {0}, *rp = &rpass;
+
+ if(!rpasses) {
+ rpasses = darr_alloc(0, sizeof *rpasses);
+ darr_push(rpasses, &rpass); /* add dummy rpass */
+ }
+
+ for(i=1; i<darr_size(rpasses); i++) {
+ if(!rpasses[i].used) {
+ rp = rpasses + i;
+ }
+ }
+
+ /* init renderpass defaults */
+ rp->used = 1;
+ rp->fmt = vksurf_fmt[vksurf_selfmt].format;
+ rp->num_colbuf = 1;
+ rp->num_samples = 1;
+ rp->clear = 1;
+ rp->vkobj_valid = 0;
+ rp->vkobj = 0;
+
+ if(rp == &rpass) {
+ darr_push(rpasses, rp);
+ return darr_size(rpasses) - 1;
+ }
+ return rp - rpasses;
+}
+
+void vk_free_rpass(int rp)
+{
+ if(!rpasses || rp < 1 || rp >= darr_size(rpasses)) {
+ return;
+ }
+
+ if(rpasses[rp].used && rpasses[rp].vkobj) {
+ vkDestroyRenderPass(vkdev, rpasses[rp].vkobj, 0);
+ }
+ rpasses[rp].used = 0;
+}
+
+void vk_rpass_colorbuf(int rp, int fmt, int n)
+{
+ rpasses[rp].fmt = fmt;
+ rpasses[rp].num_colbuf = n;
+ rpasses[rp].vkobj_valid = 0;
+}
+
+void vk_rpass_msaa(int rp, int nsamp)
+{
+ rpasses[rp].num_samples = nsamp;
+}
+
+void vk_rpass_clear(int clear)
+{
+ rpasses[rp].clear = clear;
+}
+
+VkRenderPass vk_rpass(int rp)
+{
+ struct rpass *r;
+ VkAttachmentDescription cat;
+ VkAttachmentReference catref[16];
+ VkSubpassDescription subpass;
+ VkRenderPassCreateInfo pinf;
+ VkSubpassDependency dep;
+
+ r = rpasses + rp;
+
+ if(!r->vkobj_valid) {
+ memset(&cat, 0, sizeof cat);
+ cat.format = r->fmt;
+ cat.samples = r->num_samples;
+ cat.loadOp = r->clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ cat.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ cat.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ cat.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ cat.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ cat.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
+
+ for(i=0; i<r->num_colbuf; i++) {
+ memset(&catref[i], 0, sizeof catref);
+ catref[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+ }
+
+ memset(&subpass, 0, sizeof subpass);
+ subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ subpass.colorAttachmentCount = r->num_colbuf;
+ subpass.pColorAttachments = catref;
+
+ memset(&dep, 0, sizeof dep);
+ dep.srcSubpass =
+ }
+
+ return rpasses[rp].vkobj;
+}
+
+#define ARRSZ(arr) (sizeof arr / sizeof *arr)
+static const char *known_layer_list[] = {
+ "VK_LAYER_GOOGLE_threading",
+ "VK_LAYER_LUNARG_parameter_validation",
+ "VK_LAYER_LUNARG_object_tracker",
+ "VK_LAYER_LUNARG_image",
+ "VK_LAYER_LUNARG_core_validation",
+ "VK_LAYER_LUNARG_swapchain",
+ "VK_LAYER_GOOGLE_unique_objects"
+};
+
+static struct {
+ const char *name;
+ int required;
+} known_instext_list[] = {
+ {"VK_KHR_surface", 1},
+#ifdef __WIN32__
+ {"VK_KHR_win32_surface", 1},
+#else
+ /*{"VK_KHR_xlib_surface", 1},*/
+ {"VK_KHR_xcb_surface", 1},
+#endif
+ {"VK_KHR_debug_report", 0}
+};
+
+static struct {
+ const char *name;
+ int required;
+} known_devext_list[] = {
+ {"VK_KHR_swapchain", 1},
+ {"VK_KHR_acceleration_structure", 0},
+ {"VK_KHR_ray_tracing_pipeline", 0}
+};
+
+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_instext_list)];
+ uint32_t apiver;
+
+ vkEnumerateInstanceVersion(&apiver);
+ printf("Vulkan API version: %d.%d.%d\n", (apiver >> 22) & 0x7f,
+ (apiver >> 12) & 0x3ff, apiver & 0xfff);
+
+ memset(&appinf, 0, sizeof appinf);
+ appinf.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appinf.pApplicationName = "vkray";
+ appinf.pEngineName = "vkray";
+ appinf.apiVersion = apiver;
+
+ vkEnumerateInstanceLayerProperties(&inst_layers_count, 0);
+ inst_layers = malloc_nf(inst_layers_count * sizeof *inst_layers);
+ vkEnumerateInstanceLayerProperties(&inst_layers_count, inst_layers);
+
+ vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, 0);
+ inst_ext = malloc_nf(inst_ext_count * sizeof *inst_ext);
+ vkEnumerateInstanceExtensionProperties(0, &inst_ext_count, inst_ext);
+
+ printf("Layers:\n");
+ for(i=0; i<inst_layers_count; i++) {
+ printf(" - %s: %s\n", inst_layers[i].layerName, inst_layers[i].description);
+ }
+ printf("Instance extensions:\n");
+ for(i=0; i<inst_ext_count; i++) {
+ printf(" - %s\n", inst_ext[i].extensionName);
+ }
+
+ 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_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_instext_list[i].name);
+ return -1;
+ }
+ }
+
+ memset(&instinf, 0, sizeof instinf);
+ instinf.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ instinf.pApplicationInfo = &appinf;
+ instinf.enabledLayerCount = nlayers;
+ instinf.ppEnabledLayerNames = layers;
+ instinf.enabledExtensionCount = next;
+ instinf.ppEnabledExtensionNames = ext;
+ if(vkCreateInstance(&instinf, 0, &vk) != 0) {
+ fprintf(stderr, "failed to create vulkan instance\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int create_surface(void)
+{
+ /*
+ 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;
+ }
+ */
+ VkXcbSurfaceCreateInfoKHR xinf = {0};
+ xinf.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
+ xinf.connection = XGetXCBConnection(dpy);
+ xinf.window = (xcb_window_t)win;
+
+ if(vkCreateXcbSurfaceKHR(vk, &xinf, 0, &vksurf) != 0) {
+ fprintf(stderr, "failed to create XCB window surface\n");
+ return -1;
+ }
+ return 0;
+}
+
+int choose_phys_dev(void)
+{
+ uint32_t i, num_pdev, num_qfam, score, best_score, best_dev;
+ VkPhysicalDevice *pdev;
+ VkPhysicalDeviceProperties pdevprop;
+ VkQueueFamilyProperties *qfam;
+ VkBool32 can_pres;
+
+ vkEnumeratePhysicalDevices(vk, &num_pdev, 0);
+ 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);
+
+ 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;
+ }
+
+ 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[best_dev];
+
+ vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, 0);
+ qfam = malloc_nf(num_qfam * sizeof *qfam);
+ vkGetPhysicalDeviceQueueFamilyProperties(vkpdev, &num_qfam, qfam);
+
+ vkqfam_idx = -1;
+ for(i=0; i<num_qfam; i++) {
+ vkGetPhysicalDeviceSurfaceSupportKHR(vkpdev, i, vksurf, &can_pres);
+ if(qfam[i].queueCount && (qfam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && can_pres) {
+ vkqfam_maxq = qfam[i].queueCount;
+ vkqfam_idx = i;
+ break;
+ }
+ }
+
+ free(qfam);
+ free(pdev);
+ choose_pixfmt();
+ return 0;
+}
+
+static int create_device(void)
+{
+ float prio = 1.0f;
+ VkDeviceQueueCreateInfo qinf = {0};
+ VkPhysicalDeviceFeatures feat = {0};
+ VkDeviceCreateInfo devinf = {0};
+ const char *ext[ARRSZ(known_devext_list) + 16];
+ int i, num_ext;
+
+ vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, 0);
+ dev_ext = malloc_nf(dev_ext_count * sizeof *dev_ext);
+ vkEnumerateDeviceExtensionProperties(vkpdev, 0, &dev_ext_count, dev_ext);
+
+ num_ext = 0;
+ for(i=0; i<ARRSZ(known_devext_list); i++) {
+ if(have_ext(dev_ext, dev_ext_count, known_devext_list[i].name)) {
+ ext[num_ext++] = known_devext_list[i].name;
+ } else if(known_devext_list[i].required) {
+ fprintf(stderr, "Vulkan device lacks required extension: %s\n",
+ known_devext_list[i].name);
+ return -1;
+ }
+ }
+
+ if(initflags & VKINIT_RAY) {
+ if(have_ext(dev_ext, dev_ext_count, "VK_KHR_acceleration_structure") &&
+ have_ext(dev_ext, dev_ext_count, "VK_KHR_ray_tracing_pipeline")) {
+ ext[num_ext++] = "VK_KHR_acceleration_structure";
+ ext[num_ext++] = "VK_KHR_ray_tracing_pipeline";
+ } else {
+ initflags &= ~VKINIT_RAY;
+ }
+ }
+
+ qinf.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ qinf.queueFamilyIndex = vkqfam_idx;
+ qinf.queueCount = 1;
+ qinf.pQueuePriorities = &prio;
+
+ devinf.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ devinf.pQueueCreateInfos = &qinf;
+ devinf.queueCreateInfoCount = 1;
+ devinf.pEnabledFeatures = &feat;
+ devinf.enabledExtensionCount = num_ext;
+ devinf.ppEnabledExtensionNames = ext;
+
+ if(vkCreateDevice(vkpdev, &devinf, 0, &vkdev) != 0) {
+ fprintf(stderr, "failed to create vulkan device\n");
+ return -1;
+ }
+
+ vkGetDeviceQueue(vkdev, vkqfam_idx, 0, &vkq);
+ return 0;
+}
+
+static int create_swapchain(void)
+{
+ int i;
+ uint32_t num;
+ VkSwapchainCreateInfoKHR scinf = {0};
+ VkImageViewCreateInfo ivinf;
+
+ if(vksc_extent.width <= 0 || vksc_extent.height <= 0) {
+ return -1;
+ }
+
+ scinf.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ scinf.surface = vksurf;
+ scinf.minImageCount = 2;
+ scinf.imageFormat = vksurf_fmt[vksurf_selfmt].format;
+ scinf.imageColorSpace = vksurf_fmt[vksurf_selfmt].colorSpace;
+ scinf.imageExtent = vksc_extent;
+ scinf.imageArrayLayers = 1;
+ scinf.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ scinf.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ scinf.preTransform = vksurf_caps.currentTransform;
+ scinf.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ scinf.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ scinf.clipped = VK_TRUE;
+
+ if(vkCreateSwapchainKHR(vkdev, &scinf, 0, &vksc) != 0) {
+ fprintf(stderr, "failed to create swapchain\n");
+ return -1;
+ }
+
+ if(!vksc_img || vksc_numimg != num) {
+ free(vksc_img);
+ vkGetSwapchainImagesKHR(vkdev, vksc, &num, 0);
+ vksc_img = malloc_nf(num * sizeof *vksc_img);
+ vkGetSwapchainImagesKHR(vkdev, vksc, &num, vksc_img);
+ }
+ if(!vksc_view || vksc_numimg != num) {
+ free(vksc_view);
+ vksc_view = malloc_nf(num * sizeof *vksc_view);
+ }
+ vksc_numimg = num;
+
+ for(i=0; i<num; i++) {
+ memset(&ivinf, 0, sizeof ivinf);
+ ivinf.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ ivinf.image = vksc_img[i];
+ ivinf.format = vksurf_fmt[vksurf_selfmt].format;
+ ivinf.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivinf.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivinf.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivinf.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ ivinf.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ ivinf.subresourceRange.levelCount = 1;
+ ivinf.subresourceRange.layerCount = 1;
+ ivinf.viewType = VK_IMAGE_VIEW_TYPE_2D;
+
+ if(vkCreateImageView(vkdev, &ivinf, 0, vksc_view + i) != 0) {
+ fprintf(stderr, "failed to create image view (%d)\n", i);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+static int eval_pdev_score(VkPhysicalDevice dev)
+{
+ int score = 0;
+ 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);
+
+ 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) {
+ score = 1;
+ }
+ }
+
+ switch(prop.deviceType) {
+ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+ score++;
+ break;
+ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+ score += 2;
+ break;
+ case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+ score += 4;
+ break;
+ default:
+ break;
+ }
+
+ if(initflags & VKINIT_RAY) {
+ if(have_ext(ext, num_ext, "VK_KHR_acceleration_structure") &&
+ have_ext(ext, num_ext, "VK_KHR_ray_tracing_pipeline")) {
+ score += 100;
+ }
+ }
+
+ free(ext);
+ free(sfmt);
+ free(qfam);
+ return score;
+}
+
+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;
+
+ vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, 0);
+ if(!num_fmt) return -1;
+ vksurf_fmt = malloc_nf(num_fmt * sizeof *vksurf_fmt);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(vkpdev, vksurf, &num_fmt, vksurf_fmt);
+
+ vksurf_selfmt = 0;
+ for(i=0; i<num_fmt; i++) {
+ if(vksurf_fmt[i].colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
+ continue;
+ }
+ for(j=0; j<sizeof pref / sizeof *pref; j++) {
+ if(vksurf_fmt[i].format == pref[j]) {
+ vksurf_selfmt = i;
+ vksurf_numfmt = num_fmt;
+ return i;
+ }
+ }
+ }
+ free(vksurf_fmt);
+ vksurf_fmt = 0;
+ return -1;
+}
+
+
+static int have_inst_layer(const char *name)
+{
+ int i;
+ for(i=0; i<inst_layers_count; i++) {
+ if(strcmp(inst_layers[i].layerName, name) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int have_ext(VkExtensionProperties *ext, int next, const char *name)
+{
+ int i;
+ for(i=0; i<next; i++) {
+ if(strcmp(ext[i].extensionName, name) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}