many changes: Makefile, util, fixed indent, fixes in swapchain
authorEleni Maria Stea <estea@igalia.com>
Mon, 23 Aug 2021 05:53:59 +0000 (08:53 +0300)
committerEleni Maria Stea <estea@igalia.com>
Mon, 23 Aug 2021 05:53:59 +0000 (08:53 +0300)
- changed the Makefile to compile the shaders
- added a util.[hc]
- fixed the indentation
- changed the swapchain to be separated from context and rendering =>
  creating image views with separate functions => modified existing code
  too.

.vimrc [new file with mode: 0644]
Makefile
src/main.c
src/util.c [new file with mode: 0644]
src/util.h [new file with mode: 0644]
src/vk.c
src/vk.h

diff --git a/.vimrc b/.vimrc
new file mode 100644 (file)
index 0000000..fa29808
--- /dev/null
+++ b/.vimrc
@@ -0,0 +1,3 @@
+set ts=4
+set sw=4
+set expandtab
index 470cf95..0e3b0b4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,32 @@
 src = $(wildcard src/*.c)
 obj = $(src:.c=.o)
 dep = $(obj:.o=.d)
 src = $(wildcard src/*.c)
 obj = $(src:.c=.o)
 dep = $(obj:.o=.d)
+vsdr = $(wildcard data/*.vert)
+fsdr = $(wildcard data/*.frag)
+spv = $(subst .vert,.vert.spv,$(vsdr)) \
+         $(subst .frag,.frag.spv,$(fsdr))
 bin = rt
 
 dbg = -g
 
 CC = gcc
 bin = rt
 
 dbg = -g
 
 CC = gcc
-CFLAGS = -pedantic -Wall $(dbg) $(pkg-config --cflags glfw3)
-LDFLAGS =  -lvulkan -lglfw #$(pkg-config --libs glfw3)
+CFLAGS = -pedantic -Wall $(dbg) -MMD
+LDFLAGS =  -lvulkan -lglfw
+
+.PHONY: all
+all: $(bin) $(spv)
 
 $(bin): $(obj)
        $(CC) -o $@ $(obj) $(LDFLAGS)
 
 
 $(bin): $(obj)
        $(CC) -o $@ $(obj) $(LDFLAGS)
 
--include $(dep)
+%.vert.spv: %.vert
+       glslangValidator -V $< -o $@
 
 
-%.d: %.c
-       @$(CC) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
+%.frag.spv: %.frag
+       glslangValidator -V $< -o $@
+
+-include $(dep)
 
 .PHONY: clean
 clean:
 
 .PHONY: clean
 clean:
-       rm -f $(obj) $(bin) $(dep)
+       rm -f $(obj) $(bin) $(dep) $(spv)
index 07af1ef..b0a5ec4 100644 (file)
@@ -6,6 +6,7 @@
 #include <string.h>
 
 #include "vk.h"
 #include <string.h>
 
 #include "vk.h"
+#include "util.h"
 
 
 /* static glfw callbacks */
 
 
 /* static glfw callbacks */
@@ -36,7 +37,15 @@ static int win_w = 800;
 static int win_h = 600;
 
 static struct vk_ctx vk_core;
 static int win_h = 600;
 
 static struct vk_ctx vk_core;
-static struct vk_swapchain vk_swap;
+static VkSurfaceKHR vk_surf;
+static int vsz, fsz;
+static struct vk_renderer vk_rnd;
+static struct vk_swapchain vk_chain;
+
+static struct vk_semaphores vk_sema;
+
+/* empty for as long as we hardcode the vertices in the vertex shader */
+static struct vk_vertex_info vk_vert_info;
 
 int main(int argc, char** argv)
 {
 
 int main(int argc, char** argv)
 {
@@ -66,6 +75,8 @@ int main(int argc, char** argv)
 static bool
 init()
 {
 static bool
 init()
 {
+    char *vsdr, *fsdr;
+
     /* initialize GLFW */
 
     if (!glfwInit()) {
     /* initialize GLFW */
 
     if (!glfwInit()) {
@@ -78,15 +89,6 @@ init()
         return false;
     }
 
         return false;
     }
 
-    /* initialize Vulkan context */
-
-    if (!vk_init_ctx_for_rendering(&vk_core)) {
-        fprintf(stderr, "Failed to initialize Vulkan context.\n");
-        return false;
-    }
-
-    memset(&vk_swap, 0, sizeof vk_swap);
-
     /* create window */
 
     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
     /* create window */
 
     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
@@ -97,24 +99,41 @@ init()
         return false;
     }
 
         return false;
     }
 
+    /* initialize Vulkan context (instance) */
+
+    if (!vk_init_ctx_for_rendering(&vk_core)) {
+        fprintf(stderr, "Failed to initialize Vulkan context.\n");
+        return false;
+    }
+
     /* create (Xcb) surface */
 
     glfwGetFramebufferSize(win, &win_h, &win_h);
     /* create (Xcb) surface */
 
     glfwGetFramebufferSize(win, &win_h, &win_h);
-    if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_swap.surface)
+    if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf)
             != VK_SUCCESS) {
         fprintf(stderr, "Failed to create XCB surface.\n");
             != VK_SUCCESS) {
         fprintf(stderr, "Failed to create XCB surface.\n");
+        glfwTerminate();
+
         return false;
     }
 
         return false;
     }
 
-    /* create Vulkan swapchain */
+    /* create semaphores */
+    vk_create_semaphores(&vk_core, false, &vk_sema);
 
 
-    /* aquire images? */
+    /* create swapchain */
+    vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, VK_NULL_HANDLE, &vk_chain);
 
     /* create shaders */
 
     /* create shaders */
-
-    /* create semaphores? */
+    vsdr = sdr_load("data/main.vert.spv", &vsz);
+    fsdr = sdr_load("data/main.frag.spv", &fsz);
 
     /* create renderer */
 
     /* create renderer */
+    if (!vk_create_renderer(&vk_core, vsdr, vsz, fsdr, fsz,
+                            false, false, 0, 0,
+                            &vk_vert_info, &vk_rnd)) {
+        fprintf(stderr, "Failed to create renderer.\n");
+        return false;
+    }
 
     /* set GLFW callbacks */
 
 
     /* set GLFW callbacks */
 
@@ -137,7 +156,10 @@ display()
 static void
 cleanup()
 {
 static void
 cleanup()
 {
+    vk_destroy_renderer(&vk_core, &vk_rnd);
+
     vk_cleanup_ctx(&vk_core);
     vk_cleanup_ctx(&vk_core);
+
     glfwTerminate();
 }
 
     glfwTerminate();
 }
 
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..7d33134
--- /dev/null
@@ -0,0 +1,48 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "util.h"
+
+char *
+sdr_load(const char *fname, int *sz)
+{
+    FILE *fp;
+    char *sdr_text;
+    struct stat sp;
+    size_t filesz;
+
+    if (!(fp = fopen(fname, "r"))) {
+        fprintf(stderr, "Failed to open shader file: %s: %s.\n", fname, strerror(errno));
+        return 0;
+    }
+
+    fstat(fileno(fp), &sp);
+    filesz = sp.st_size;
+
+    if (!(sdr_text = malloc(filesz + 1))) {
+        fclose(fp);
+        return 0;
+    }
+
+    fread(sdr_text, 1, filesz, fp);
+    sdr_text[filesz] = 0;
+    fclose(fp);
+
+       if (!sdr_text)
+               fprintf(stderr, "Failed to load shader source code from: %s.\n", fname);
+
+    *sz = filesz;
+       return sdr_text;
+
+}
+
+bool
+img_dump_rgba(const char *fname,
+              int w, int h,
+              unsigned char *data)
+{
+    return true;
+}
diff --git a/src/util.h b/src/util.h
new file mode 100644 (file)
index 0000000..97abe8a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdbool.h>
+
+char *
+sdr_load(const char *fname, int *sz);
+
+bool
+img_dump_rgba(const char *fname,
+              int w, int h,
+              unsigned char *data);
+
+#endif /* UTIL_H */
index 81e0f51..de807a4 100644 (file)
--- a/src/vk.c
+++ b/src/vk.c
@@ -6,6 +6,7 @@
 #include "vk.h"
 
 /* static variables */
 #include "vk.h"
 
 /* static variables */
+
 static VkViewport viewport;
 static VkRect2D scissor;
 static bool enable_layers = true;
 static VkViewport viewport;
 static VkRect2D scissor;
 static bool enable_layers = true;
@@ -15,85 +16,85 @@ static bool enable_layers = true;
 static VkSampleCountFlagBits
 get_num_samples(uint32_t num_samples)
 {
 static VkSampleCountFlagBits
 get_num_samples(uint32_t num_samples)
 {
-       switch(num_samples) {
-       case 64:
-               return VK_SAMPLE_COUNT_64_BIT;
-       case 32:
-               return VK_SAMPLE_COUNT_32_BIT;
-       case 16:
-               return VK_SAMPLE_COUNT_16_BIT;
-       case 8:
-               return VK_SAMPLE_COUNT_8_BIT;
-       case 4:
-               return VK_SAMPLE_COUNT_4_BIT;
-       case 2:
-               return VK_SAMPLE_COUNT_2_BIT;
-       case 1:
-               break;
-       default:
-               fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
-               break;
-       }
-       return VK_SAMPLE_COUNT_1_BIT;
+    switch(num_samples) {
+    case 64:
+        return VK_SAMPLE_COUNT_64_BIT;
+    case 32:
+        return VK_SAMPLE_COUNT_32_BIT;
+    case 16:
+        return VK_SAMPLE_COUNT_16_BIT;
+    case 8:
+        return VK_SAMPLE_COUNT_8_BIT;
+    case 4:
+        return VK_SAMPLE_COUNT_4_BIT;
+    case 2:
+        return VK_SAMPLE_COUNT_2_BIT;
+    case 1:
+        break;
+    default:
+        fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n");
+        break;
+    }
+    return VK_SAMPLE_COUNT_1_BIT;
 }
 
 static VkAccessFlagBits
 get_access_mask(const VkImageLayout layout)
 {
 }
 
 static VkAccessFlagBits
 get_access_mask(const VkImageLayout layout)
 {
-       /* dstAccessMask of barriers must be supported from the pipeline
-        * stage, see also access scopes and this table:
-        * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
-        */
-       switch (layout) {
-       case VK_IMAGE_LAYOUT_UNDEFINED:
-               return 0;
-       case VK_IMAGE_LAYOUT_GENERAL:
-               return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
-       case VK_IMAGE_LAYOUT_PREINITIALIZED:
-               return VK_ACCESS_HOST_WRITE_BIT;
-       case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
-               return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
-                      VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-       case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
-               return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
-       case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
-               return VK_ACCESS_TRANSFER_READ_BIT;
-       case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
-               return VK_ACCESS_TRANSFER_WRITE_BIT;
-       case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
-               return 0;
-       default:
-               return 0;
-       };
-
-       return 0;
+    /* dstAccessMask of barriers must be supported from the pipeline
+     * stage, see also access scopes and this table:
+     * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported
+     */
+    switch (layout) {
+    case VK_IMAGE_LAYOUT_UNDEFINED:
+        return 0;
+    case VK_IMAGE_LAYOUT_GENERAL:
+        return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
+    case VK_IMAGE_LAYOUT_PREINITIALIZED:
+        return VK_ACCESS_HOST_WRITE_BIT;
+    case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+        return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
+               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+    case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+        return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
+    case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+        return VK_ACCESS_TRANSFER_READ_BIT;
+    case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+        return VK_ACCESS_TRANSFER_WRITE_BIT;
+    case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
+        return 0;
+    default:
+        return 0;
+    };
+
+    return 0;
 }
 
 static void
 enable_validation_layers(VkInstanceCreateInfo *info)
 {
 }
 
 static void
 enable_validation_layers(VkInstanceCreateInfo *info)
 {
-       int i;
-       uint32_t num_layers;
-       VkLayerProperties *layers;
-       static const char *layer_names[] = {
-               "VK_LAYER_KHRONOS_validation",
-       };
-
-       vkEnumerateInstanceLayerProperties(&num_layers, 0);
-       layers = alloca(num_layers * sizeof *layers);
-       vkEnumerateInstanceLayerProperties(&num_layers, layers);
-
-       if (num_layers) {
-               printf("Available validation layers:\n");
-               for(i = 0; i < (int)num_layers; i++) {
-                       printf(" %s\n", layers[i].layerName);
-               }
-
-               info->ppEnabledLayerNames = layer_names;
-               info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
-       } else {
-               fprintf(stderr, "Vulkan validation layers not found.\n");
-       }
+    int i;
+    uint32_t num_layers;
+    VkLayerProperties *layers;
+    static const char *layer_names[] = {
+        "VK_LAYER_KHRONOS_validation",
+    };
+
+    vkEnumerateInstanceLayerProperties(&num_layers, 0);
+    layers = alloca(num_layers * sizeof *layers);
+    vkEnumerateInstanceLayerProperties(&num_layers, layers);
+
+    if (num_layers) {
+        printf("Available validation layers:\n");
+        for(i = 0; i < (int)num_layers; i++) {
+            printf(" %s\n", layers[i].layerName);
+        }
+
+        info->ppEnabledLayerNames = layer_names;
+        info->enabledLayerCount = sizeof layer_names / sizeof *layer_names;
+    } else {
+        fprintf(stderr, "Vulkan validation layers not found.\n");
+    }
 }
 
 static void
 }
 
 static void
@@ -129,138 +130,138 @@ enable_extensions(VkInstanceCreateInfo *info)
 static VkInstance
 create_instance(bool enable_layers)
 {
 static VkInstance
 create_instance(bool enable_layers)
 {
-       VkApplicationInfo app_info;
-       VkInstanceCreateInfo inst_info;
-       VkInstance inst;
+    VkApplicationInfo app_info;
+    VkInstanceCreateInfo inst_info;
+    VkInstance inst;
 
     /* VkApplicationInfo */
 
     /* VkApplicationInfo */
-       memset(&app_info, 0, sizeof app_info);
-       app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
-       app_info.pApplicationName = "vktest";
-       app_info.apiVersion = VK_API_VERSION_1_1;
+    memset(&app_info, 0, sizeof app_info);
+    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+    app_info.pApplicationName = "vktest";
+    app_info.apiVersion = VK_API_VERSION_1_1;
 
     /* VkInstanceCreateInfo */
 
     /* VkInstanceCreateInfo */
-       memset(&inst_info, 0, sizeof inst_info);
-       inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
-       inst_info.pApplicationInfo = &app_info;
+    memset(&inst_info, 0, sizeof inst_info);
+    inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+    inst_info.pApplicationInfo = &app_info;
 
     enable_extensions(&inst_info);
 
     enable_extensions(&inst_info);
-       if (enable_layers) {
-               enable_validation_layers(&inst_info);
+    if (enable_layers) {
+        enable_validation_layers(&inst_info);
     }
 
     }
 
-       if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
-               return 0;
+    if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS)
+        return 0;
 
 
-       return inst;
+    return inst;
 }
 
 static VkPhysicalDevice
 select_physical_device(VkInstance inst)
 {
 }
 
 static VkPhysicalDevice
 select_physical_device(VkInstance inst)
 {
-       VkResult res = VK_SUCCESS;
-       uint32_t dev_count = 0;
-       VkPhysicalDevice *pdevices;
-       VkPhysicalDevice pdevice0;
+    VkResult res = VK_SUCCESS;
+    uint32_t dev_count = 0;
+    VkPhysicalDevice *pdevices;
+    VkPhysicalDevice pdevice0;
 
 
-       if ((res =
-            vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
-               return 0;
+    if ((res =
+         vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS)
+        return 0;
 
 
-       pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
-       if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
-           VK_SUCCESS)
-               return 0;
+    pdevices = malloc(dev_count * sizeof(VkPhysicalDevice));
+    if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) !=
+        VK_SUCCESS)
+        return 0;
 
 
-       pdevice0 = pdevices[0];
-       free(pdevices);
+    pdevice0 = pdevices[0];
+    free(pdevices);
 
 
-       return pdevice0;
+    return pdevice0;
 }
 
 static VkDevice
 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
 {
 }
 
 static VkDevice
 create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev)
 {
-       const char *deviceExtensions[] = { "VK_KHR_swapchain" };
-       VkDeviceQueueCreateInfo dev_queue_info;
-       VkDeviceCreateInfo dev_info;
-       VkDevice dev;
-       uint32_t prop_count;
-       VkQueueFamilyProperties *fam_props;
-       uint32_t i;
-       float qprio = 0;
-
-       ctx->qfam_idx = -1;
-       vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
-       if (prop_count < 0) {
-               fprintf(stderr, "Invalid queue family properties.\n");
-               return 0;
-       }
-
-       fam_props = malloc(prop_count * sizeof *fam_props);
-       vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
-
-       for (i = 0; i < prop_count; i++) {
-               if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
-                       ctx->qfam_idx = i;
-                       break;
-               }
-       }
-       free(fam_props);
-
-       memset(&dev_queue_info, 0, sizeof dev_queue_info);
-       dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
-       dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
-       dev_queue_info.queueCount = 1;
-       dev_queue_info.pQueuePriorities = &qprio;
-
-       memset(&dev_info, 0, sizeof dev_info);
-       dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
-       dev_info.queueCreateInfoCount = 1;
-       dev_info.pQueueCreateInfos = &dev_queue_info;
-       dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
-       dev_info.ppEnabledExtensionNames = deviceExtensions;
-
-       if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
-               return 0;
-
-       return dev;
+    const char *deviceExtensions[] = { "VK_KHR_swapchain" };
+    VkDeviceQueueCreateInfo dev_queue_info;
+    VkDeviceCreateInfo dev_info;
+    VkDevice dev;
+    uint32_t prop_count;
+    VkQueueFamilyProperties *fam_props;
+    uint32_t i;
+    float qprio = 0;
+
+    ctx->qfam_idx = -1;
+    vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0);
+    if (prop_count < 0) {
+        fprintf(stderr, "Invalid queue family properties.\n");
+        return 0;
+    }
+
+    fam_props = malloc(prop_count * sizeof *fam_props);
+    vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props);
+
+    for (i = 0; i < prop_count; i++) {
+        if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
+            ctx->qfam_idx = i;
+            break;
+        }
+    }
+    free(fam_props);
+
+    memset(&dev_queue_info, 0, sizeof dev_queue_info);
+    dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+    dev_queue_info.queueFamilyIndex = ctx->qfam_idx;
+    dev_queue_info.queueCount = 1;
+    dev_queue_info.pQueuePriorities = &qprio;
+
+    memset(&dev_info, 0, sizeof dev_info);
+    dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+    dev_info.queueCreateInfoCount = 1;
+    dev_info.pQueueCreateInfos = &dev_queue_info;
+    dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions);
+    dev_info.ppEnabledExtensionNames = deviceExtensions;
+
+    if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS)
+        return 0;
+
+    return dev;
 }
 
 static void
 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
 {
 }
 
 static void
 fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID)
 {
-       VkPhysicalDeviceIDProperties devProp;
-       VkPhysicalDeviceProperties2 prop2;
+    VkPhysicalDeviceIDProperties devProp;
+    VkPhysicalDeviceProperties2 prop2;
 
 
-       memset(&devProp, 0, sizeof devProp);
-       devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+    memset(&devProp, 0, sizeof devProp);
+    devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
 
 
-       memset(&prop2, 0, sizeof prop2);
-       prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
-       prop2.pNext = &devProp;
+    memset(&prop2, 0, sizeof prop2);
+    prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+    prop2.pNext = &devProp;
 
 
-       vkGetPhysicalDeviceProperties2(pdev, &prop2);
-       memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
-       memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
+    vkGetPhysicalDeviceProperties2(pdev, &prop2);
+    memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE);
+    memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE);
 }
 
 static VkCommandPool
 create_cmd_pool(struct vk_ctx *ctx)
 {
 }
 
 static VkCommandPool
 create_cmd_pool(struct vk_ctx *ctx)
 {
-       VkCommandPoolCreateInfo cmd_pool_info;
-       VkCommandPool cmd_pool;
-       VkDevice dev = ctx->dev;
+    VkCommandPoolCreateInfo cmd_pool_info;
+    VkCommandPool cmd_pool;
+    VkDevice dev = ctx->dev;
 
 
-       memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
-       cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
-       cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
-       cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
+    memset(&cmd_pool_info, 0, sizeof cmd_pool_info);
+    cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
+    cmd_pool_info.queueFamilyIndex = ctx->qfam_idx;
+    cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
 
 
-       if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
-               return 0;
+    if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS)
+        return 0;
 
 
-       return cmd_pool;
+    return cmd_pool;
 }
 
 static VkRenderPass
 }
 
 static VkRenderPass
@@ -268,281 +269,305 @@ create_renderpass(struct vk_ctx *ctx,
                   struct vk_image_props *color_img_props,
                   struct vk_image_props *depth_img_props)
 {
                   struct vk_image_props *color_img_props,
                   struct vk_image_props *depth_img_props)
 {
-       uint32_t num_attachments = 2;
-       VkAttachmentDescription att_dsc[2];
-       VkAttachmentReference att_rfc[2];
-       VkSubpassDescription subpass_dsc[1];
-       VkRenderPassCreateInfo rpass_info;
-
-       /* VkAttachmentDescription */
-       memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
-
-       att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
-       att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-       att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-       att_dsc[0].initialLayout = color_img_props->in_layout;
-       att_dsc[0].finalLayout = color_img_props->end_layout;
-       att_dsc[0].format = color_img_props->format;
-       att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-       att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
-
-       att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
-
-       /* We might want to reuse a depth buffer */
-       if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
-               att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-               att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
-    }
-       else {
-               att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-               att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
-    }
-
-       att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
-       att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
-       att_dsc[1].initialLayout = depth_img_props->in_layout;
-       att_dsc[1].finalLayout = depth_img_props->end_layout;
-       att_dsc[1].format = depth_img_props->format;
-
-       /* VkAttachmentReference */
-       memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
-
-       att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
-       att_rfc[0].attachment = 0;
-
-       att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
-       att_rfc[1].attachment = 1;
-
-       /* VkSubpassDescription */
-       memset(&subpass_dsc, 0, sizeof subpass_dsc);
-       subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
-       subpass_dsc[0].colorAttachmentCount = 1;
-       subpass_dsc[0].pColorAttachments = &att_rfc[0];
-       subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
-
-       /* VkRenderPassCreateInfo */
-       memset(&rpass_info, 0, sizeof rpass_info);
-       rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
-       rpass_info.attachmentCount = num_attachments;
-       rpass_info.pAttachments = att_dsc;
-       rpass_info.subpassCount = 1;
-       rpass_info.pSubpasses = subpass_dsc;
-
-       VkRenderPass rpass;
-       if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create renderpass.\n");
-               rpass = VK_NULL_HANDLE;
-       }
-
-       return rpass;
+    uint32_t num_attachments = 2;
+    VkAttachmentDescription att_dsc[2];
+    VkAttachmentReference att_rfc[2];
+    VkSubpassDescription subpass_dsc[1];
+    VkRenderPassCreateInfo rpass_info;
+
+    /* VkAttachmentDescription */
+    memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]);
+
+    att_dsc[0].samples = get_num_samples(color_img_props->num_samples);
+    att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    att_dsc[0].initialLayout = color_img_props->in_layout;
+    att_dsc[0].finalLayout = color_img_props->end_layout;
+    att_dsc[0].format = color_img_props->format;
+    att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+    att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+
+    att_dsc[1].samples = get_num_samples(depth_img_props->num_samples);
+
+    /* We might want to reuse a depth buffer */
+    if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) {
+        att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+        att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
+    }
+    else {
+        att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+        att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+    }
+
+    att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+    att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
+    att_dsc[1].initialLayout = depth_img_props->in_layout;
+    att_dsc[1].finalLayout = depth_img_props->end_layout;
+    att_dsc[1].format = depth_img_props->format;
+
+    /* VkAttachmentReference */
+    memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]);
+
+    att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
+    att_rfc[0].attachment = 0;
+
+    att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
+    att_rfc[1].attachment = 1;
+
+    /* VkSubpassDescription */
+    memset(&subpass_dsc, 0, sizeof subpass_dsc);
+    subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+    subpass_dsc[0].colorAttachmentCount = 1;
+    subpass_dsc[0].pColorAttachments = &att_rfc[0];
+    subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1];
+
+    /* VkRenderPassCreateInfo */
+    memset(&rpass_info, 0, sizeof rpass_info);
+    rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+    rpass_info.attachmentCount = num_attachments;
+    rpass_info.pAttachments = att_dsc;
+    rpass_info.subpassCount = 1;
+    rpass_info.pSubpasses = subpass_dsc;
+
+    VkRenderPass rpass;
+    if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create renderpass.\n");
+        rpass = VK_NULL_HANDLE;
+    }
+
+    return rpass;
 }
 
 static inline VkImageType
 get_image_type(uint32_t h, uint32_t d)
 {
 }
 
 static inline VkImageType
 get_image_type(uint32_t h, uint32_t d)
 {
-       if (h == 1)
-               return VK_IMAGE_TYPE_1D;
+    if (h == 1)
+        return VK_IMAGE_TYPE_1D;
 
 
-       if (d > 1)
-               return VK_IMAGE_TYPE_3D;
+    if (d > 1)
+        return VK_IMAGE_TYPE_3D;
 
 
-       return VK_IMAGE_TYPE_2D;
+    return VK_IMAGE_TYPE_2D;
 }
 
 static VkImageViewType
 get_image_view_type(struct vk_image_props *props)
 {
 }
 
 static VkImageViewType
 get_image_view_type(struct vk_image_props *props)
 {
-       VkImageType type = get_image_type(props->h, props->depth);
-       switch(type) {
-               case VK_IMAGE_TYPE_1D:
-                       return props->num_layers > 1 ?
-                               VK_IMAGE_VIEW_TYPE_1D_ARRAY :
-                               VK_IMAGE_VIEW_TYPE_1D;
-               case VK_IMAGE_TYPE_2D:
-                       if (props->num_layers == 1)
-                               return VK_IMAGE_VIEW_TYPE_2D;
-                       if (props->num_layers == 6)
-                               return VK_IMAGE_VIEW_TYPE_CUBE;
-                       if (props->num_layers % 6 == 0)
-                               return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
-                       if (props->num_layers > 1)
-                               return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
-               case VK_IMAGE_TYPE_3D:
-                       if (props->num_layers == 1)
-                               return VK_IMAGE_VIEW_TYPE_3D;
-                       if ((props->num_layers == 1) &&
-                           (props->num_levels == 1))
-                               return VK_IMAGE_VIEW_TYPE_2D;
-                       if ((props->num_levels == 1) &&
-                           (props->num_layers > 1))
-                               return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
-               default:
-                       return VK_IMAGE_VIEW_TYPE_2D;
-       }
+    VkImageType type = get_image_type(props->h, props->depth);
+    switch(type) {
+        case VK_IMAGE_TYPE_1D:
+            return props->num_layers > 1 ?
+                VK_IMAGE_VIEW_TYPE_1D_ARRAY :
+                VK_IMAGE_VIEW_TYPE_1D;
+        case VK_IMAGE_TYPE_2D:
+            if (props->num_layers == 1)
+                return VK_IMAGE_VIEW_TYPE_2D;
+            if (props->num_layers == 6)
+                return VK_IMAGE_VIEW_TYPE_CUBE;
+            if (props->num_layers % 6 == 0)
+                return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
+            if (props->num_layers > 1)
+                return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+        case VK_IMAGE_TYPE_3D:
+            if (props->num_layers == 1)
+                return VK_IMAGE_VIEW_TYPE_3D;
+            if ((props->num_layers == 1) &&
+                (props->num_levels == 1))
+                return VK_IMAGE_VIEW_TYPE_2D;
+            if ((props->num_levels == 1) &&
+                (props->num_layers > 1))
+                return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+        default:
+            return VK_IMAGE_VIEW_TYPE_2D;
+    }
 }
 
 static VkImageAspectFlagBits
 get_aspect_from_depth_format(VkFormat depth_format)
 {
 }
 
 static VkImageAspectFlagBits
 get_aspect_from_depth_format(VkFormat depth_format)
 {
-       switch (depth_format) {
-       case VK_FORMAT_D16_UNORM:
-       case VK_FORMAT_X8_D24_UNORM_PACK32:
-       case VK_FORMAT_D32_SFLOAT:
-               return VK_IMAGE_ASPECT_DEPTH_BIT;
-       case VK_FORMAT_S8_UINT:
-               return VK_IMAGE_ASPECT_STENCIL_BIT;
-       case VK_FORMAT_D16_UNORM_S8_UINT:
-       case VK_FORMAT_D24_UNORM_S8_UINT:
-       case VK_FORMAT_D32_SFLOAT_S8_UINT:
-               return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
-       default:
-               break;
-       }
-       return 0;
+    switch (depth_format) {
+    case VK_FORMAT_D16_UNORM:
+    case VK_FORMAT_X8_D24_UNORM_PACK32:
+    case VK_FORMAT_D32_SFLOAT:
+        return VK_IMAGE_ASPECT_DEPTH_BIT;
+    case VK_FORMAT_S8_UINT:
+        return VK_IMAGE_ASPECT_STENCIL_BIT;
+    case VK_FORMAT_D16_UNORM_S8_UINT:
+    case VK_FORMAT_D24_UNORM_S8_UINT:
+    case VK_FORMAT_D32_SFLOAT_S8_UINT:
+        return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+    default:
+        break;
+    }
+    return 0;
 }
 
 static VkPipelineStageFlags
 get_pipeline_stage_flags(const VkImageLayout layout)
 {
 }
 
 static VkPipelineStageFlags
 get_pipeline_stage_flags(const VkImageLayout layout)
 {
-       switch (layout) {
-       case VK_IMAGE_LAYOUT_UNDEFINED:
-               return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-       case VK_IMAGE_LAYOUT_GENERAL:
-               return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
-       case VK_IMAGE_LAYOUT_PREINITIALIZED:
-               return VK_PIPELINE_STAGE_HOST_BIT;
-       case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
-       case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
-               return VK_PIPELINE_STAGE_TRANSFER_BIT;
-       case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
-               return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
-       case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
-               return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
-                      VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
-       case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
-               return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
-       default:
+    switch (layout) {
+    case VK_IMAGE_LAYOUT_UNDEFINED:
+        return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
+    case VK_IMAGE_LAYOUT_GENERAL:
+        return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
+    case VK_IMAGE_LAYOUT_PREINITIALIZED:
+        return VK_PIPELINE_STAGE_HOST_BIT;
+    case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
+    case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
+        return VK_PIPELINE_STAGE_TRANSFER_BIT;
+    case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
+        return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+    case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
+        return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
+               VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
+    case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
+        return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
+    default:
         break;
         break;
-       }
-       return 0;
+    }
+    return 0;
+}
+
+static bool
+create_image_view(struct vk_ctx *ctx,
+                  VkImage image,
+                  VkImageViewType view_type,
+                  VkFormat format,
+                  VkImageSubresourceRange sr,
+                  bool is_swapchain,
+                  VkImageView *image_view)
+{
+    VkImageViewCreateInfo info;
+
+    memset(&info, 0, sizeof info);
+    info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+    info.image = image;
+    info.viewType = view_type;
+    info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+    info.format = format;
+    info.subresourceRange = sr;
+
+    if (is_swapchain) {
+        info.components.r = VK_COMPONENT_SWIZZLE_R;
+        info.components.g = VK_COMPONENT_SWIZZLE_G;
+        info.components.b = VK_COMPONENT_SWIZZLE_B;
+        info.components.a = VK_COMPONENT_SWIZZLE_A;
+    }
+
+    if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create image view.\n");
+        image_view = VK_NULL_HANDLE;
+
+        return false;
+    }
+
+    return true;
 }
 
 static void
 create_framebuffer(struct vk_ctx *ctx,
 }
 
 static void
 create_framebuffer(struct vk_ctx *ctx,
-                                  struct vk_image_att *color_att,
-                                  struct vk_image_att *depth_att,
-                                  struct vk_renderer *renderer)
+                   struct vk_image_att *color_att,
+                   struct vk_image_att *depth_att,
+                   struct vk_renderer *renderer)
 {
 {
-       VkImageSubresourceRange sr;
-       VkImageViewCreateInfo color_info;
-       VkImageViewCreateInfo depth_info;
-       VkFramebufferCreateInfo fb_info;
-       VkImageView atts[2];
-       VkImageViewType view_type = get_image_view_type(&color_att->props);
-
-       if (!color_att->obj.img || !depth_att->obj.img) {
-               fprintf(stderr, "Invalid framebuffer attachment image.\n");
-               goto fail;
-       }
-
-       /* create image views */
-
-       /* VKImageSubresourceRange */
-       memset(&sr, 0, sizeof sr);
-       sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-       /* If an application wants to use all mip levels
-        * or layers in an image after the baseMipLevel
-        * or baseArrayLayer, it can set levelCount and
-        * layerCount to the special values
-        * VK_REMAINING_MIP_LEVELS and
-        * VK_REMAINING_ARRAY_LAYERS without knowing the
-        * exact number of mip levels or layers.
-        */
-       sr.baseMipLevel = 0;
-       sr.levelCount = color_att->props.num_levels;
-       sr.baseArrayLayer = 0;
-       sr.layerCount = color_att->props.num_layers;
-
-       /* color view */
-       memset(&color_info, 0, sizeof color_info);
-       color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-       color_info.image = color_att->obj.img;
-       color_info.viewType = view_type;
-       color_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
-       color_info.format = color_att->props.format;
-       color_info.subresourceRange = sr;
-
-    if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create color image view for framebuffer.\n");
-               vk_destroy_image(ctx, &color_att->obj);
-               goto fail;
-       }
-
-       /* depth view */
-       memset(&sr, 0, sizeof sr);
-       sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
-       sr.baseMipLevel = 0;
-       sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
-       sr.baseArrayLayer = 0;
-       sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
-
-       memset(&depth_info, 0, sizeof depth_info);
-       depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
-       depth_info.image = depth_att->obj.img;
-       depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
-       depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
-       depth_info.format = depth_att->props.format;
-       depth_info.subresourceRange = sr;
-
-    if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) {
-
-               fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
-               vk_destroy_image(ctx, &depth_att->obj);
-               goto fail;
-       }
+    VkImageSubresourceRange sr;
+    VkFramebufferCreateInfo fb_info;
+    VkImageView atts[2];
+    VkImageViewType view_type = get_image_view_type(&color_att->props);
+
+    if (!color_att->obj.img || !depth_att->obj.img) {
+        fprintf(stderr, "Invalid framebuffer attachment image.\n");
+        goto fail;
+    }
+
+    /* create image views */
+
+    /* VKImageSubresourceRange */
+    memset(&sr, 0, sizeof sr);
+    sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    /* If an application wants to use all mip levels
+     * or layers in an image after the baseMipLevel
+     * or baseArrayLayer, it can set levelCount and
+     * layerCount to the special values
+     * VK_REMAINING_MIP_LEVELS and
+     * VK_REMAINING_ARRAY_LAYERS without knowing the
+     * exact number of mip levels or layers.
+     */
+    sr.baseMipLevel = 0;
+    sr.levelCount = color_att->props.num_levels;
+    sr.baseArrayLayer = 0;
+    sr.layerCount = color_att->props.num_layers;
+
+    /* color view */
+    if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) {
+        fprintf(stderr, "Failed to create color image view for framebuffer.\n");
+        vk_destroy_image(ctx, &color_att->obj);
+        goto fail;
+    }
+
+    /* depth view */
+    memset(&sr, 0, sizeof sr);
+    sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format);
+    sr.baseMipLevel = 0;
+    sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1;
+    sr.baseArrayLayer = 0;
+    sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1;
+
+    if (!create_image_view(ctx, depth_att->obj.img,
+                           depth_att->props.num_layers > 1 ?
+                           VK_IMAGE_VIEW_TYPE_2D_ARRAY :
+                           VK_IMAGE_VIEW_TYPE_2D,
+                           depth_att->props.format,
+                           sr,
+                           false,
+                           &depth_att->obj.img_view)) {
+        fprintf(stderr, "Failed to create depth image view for framebuffer.\n");
+        vk_destroy_image(ctx, &depth_att->obj);
+        goto fail;
+    }
 
     atts[0] = color_att->obj.img_view;
 
     atts[0] = color_att->obj.img_view;
-       atts[1] = depth_att->obj.img_view;
+    atts[1] = depth_att->obj.img_view;
 
 
-       memset(&fb_info, 0, sizeof fb_info);
-       fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
-       fb_info.renderPass = renderer->renderpass;
-       fb_info.width = color_att->props.w;
-       fb_info.height = color_att->props.h;
-       fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
-       fb_info.attachmentCount = 2;
-       fb_info.pAttachments = atts;
+    memset(&fb_info, 0, sizeof fb_info);
+    fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+    fb_info.renderPass = renderer->renderpass;
+    fb_info.width = color_att->props.w;
+    fb_info.height = color_att->props.h;
+    fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1;
+    fb_info.attachmentCount = 2;
+    fb_info.pAttachments = atts;
 
 
-       if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
-               goto fail;
+    if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS)
+        goto fail;
 
 
-       return;
+    return;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to create framebuffer.\n");
-       renderer->fb = VK_NULL_HANDLE;
+    fprintf(stderr, "Failed to create framebuffer.\n");
+    renderer->fb = VK_NULL_HANDLE;
 }
 
 static VkShaderModule
 create_shader_module(struct vk_ctx *ctx,
 }
 
 static VkShaderModule
 create_shader_module(struct vk_ctx *ctx,
-                    const char *src,
-                    unsigned int size)
+             const char *src,
+             unsigned int size)
 {
 {
-       VkShaderModuleCreateInfo sm_info;
-       VkShaderModule sm;
-
-       /* VkShaderModuleCreateInfo */
-       memset(&sm_info, 0, sizeof sm_info);
-       sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
-       sm_info.codeSize = size;
-       sm_info.pCode = (void*)src;
-
-       if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create shader module.\n");
-               sm = VK_NULL_HANDLE;
-       }
+    VkShaderModuleCreateInfo sm_info;
+    VkShaderModule sm;
+
+    /* VkShaderModuleCreateInfo */
+    memset(&sm_info, 0, sizeof sm_info);
+    sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
+    sm_info.codeSize = size;
+    sm_info.pCode = (void*)src;
+
+    if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create shader module.\n");
+        sm = VK_NULL_HANDLE;
+    }
 
 
-       return sm;
+    return sm;
 }
 
 static void
 }
 
 static void
@@ -554,259 +579,259 @@ create_pipeline(struct vk_ctx *ctx,
                 bool enable_stencil,
                 struct vk_renderer *renderer)
 {
                 bool enable_stencil,
                 struct vk_renderer *renderer)
 {
-       VkVertexInputBindingDescription vert_bind_dsc[1];
-       VkVertexInputAttributeDescription vert_att_dsc[1];
-
-       VkPipelineColorBlendAttachmentState cb_att_state[1];
-       VkPipelineVertexInputStateCreateInfo vert_input_info;
-       VkPipelineInputAssemblyStateCreateInfo asm_info;
-       VkPipelineViewportStateCreateInfo viewport_info;
-       VkPipelineRasterizationStateCreateInfo rs_info;
-       VkPipelineMultisampleStateCreateInfo ms_info;
-       VkPipelineDepthStencilStateCreateInfo ds_info;
-       VkPipelineColorBlendStateCreateInfo cb_info;
-       VkPipelineShaderStageCreateInfo sdr_stages[2];
-       VkPipelineLayoutCreateInfo layout_info;
-       VkGraphicsPipelineCreateInfo pipeline_info;
-       VkFormat format;
-       VkFormatProperties fmt_props;
-       VkPushConstantRange pc_range[1];
-
-       VkStencilOpState front;
-       VkStencilOpState back;
-       int i;
-       VkPipelineLayout pipeline_layout;
-       uint32_t stride;
-
-       /* format of vertex attributes:
-        * we have 2D vectors so we need a RG format:
-        * R for x, G for y
-        * the stride (distance between 2 consecutive elements)
-        * must be 8 because we use 32 bit floats and
-        * 32bits = 8bytes */
-       format = VK_FORMAT_R32G32_SFLOAT;
-       vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
-       assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
-       stride = 8;
-
-       /* VkVertexInputAttributeDescription */
-       memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
-       vert_att_dsc[0].location = 0;
-       vert_att_dsc[0].binding = 0;
-       vert_att_dsc[0].format = format; /* see comment */
-       vert_att_dsc[0].offset = 0;
-
-       /* VkVertexInputBindingDescription */
-       memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
-       vert_bind_dsc[0].binding = 0;
-       vert_bind_dsc[0].stride = stride;
-       vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
+    VkVertexInputBindingDescription vert_bind_dsc[1];
+    VkVertexInputAttributeDescription vert_att_dsc[1];
+
+    VkPipelineColorBlendAttachmentState cb_att_state[1];
+    VkPipelineVertexInputStateCreateInfo vert_input_info;
+    VkPipelineInputAssemblyStateCreateInfo asm_info;
+    VkPipelineViewportStateCreateInfo viewport_info;
+    VkPipelineRasterizationStateCreateInfo rs_info;
+    VkPipelineMultisampleStateCreateInfo ms_info;
+    VkPipelineDepthStencilStateCreateInfo ds_info;
+    VkPipelineColorBlendStateCreateInfo cb_info;
+    VkPipelineShaderStageCreateInfo sdr_stages[2];
+    VkPipelineLayoutCreateInfo layout_info;
+    VkGraphicsPipelineCreateInfo pipeline_info;
+    VkFormat format;
+    VkFormatProperties fmt_props;
+    VkPushConstantRange pc_range[1];
+
+    VkStencilOpState front;
+    VkStencilOpState back;
+    int i;
+    VkPipelineLayout pipeline_layout;
+    uint32_t stride;
+
+    /* format of vertex attributes:
+     * we have 2D vectors so we need a RG format:
+     * R for x, G for y
+     * the stride (distance between 2 consecutive elements)
+     * must be 8 because we use 32 bit floats and
+     * 32bits = 8bytes */
+    format = VK_FORMAT_R32G32_SFLOAT;
+    vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props);
+    assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
+    stride = 8;
+
+    /* VkVertexInputAttributeDescription */
+    memset(&vert_att_dsc, 0, sizeof vert_att_dsc);
+    vert_att_dsc[0].location = 0;
+    vert_att_dsc[0].binding = 0;
+    vert_att_dsc[0].format = format; /* see comment */
+    vert_att_dsc[0].offset = 0;
+
+    /* VkVertexInputBindingDescription */
+    memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc);
+    vert_bind_dsc[0].binding = 0;
+    vert_bind_dsc[0].stride = stride;
+    vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
 
     /* If using vbo, we have setup vertex_info in the renderer. */
 
     /* If using vbo, we have setup vertex_info in the renderer. */
-       bool use_vbo = renderer->vertex_info.num_verts > 0;
-
-       /* VkPipelineVertexInputStateCreateInfo */
-       memset(&vert_input_info, 0, sizeof vert_input_info);
-       vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
-       vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
-       vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
-       vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
-       vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
-
-       /* VkPipelineInputAssemblyStateCreateInfo */
-       memset(&asm_info, 0, sizeof asm_info);
-       asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
-       asm_info.topology = renderer->vertex_info.topology ?
+    bool use_vbo = renderer->vertex_info.num_verts > 0;
+
+    /* VkPipelineVertexInputStateCreateInfo */
+    memset(&vert_input_info, 0, sizeof vert_input_info);
+    vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+    vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0;
+    vert_input_info.pVertexBindingDescriptions = vert_bind_dsc;
+    vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0;
+    vert_input_info.pVertexAttributeDescriptions = vert_att_dsc;
+
+    /* VkPipelineInputAssemblyStateCreateInfo */
+    memset(&asm_info, 0, sizeof asm_info);
+    asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
+    asm_info.topology = renderer->vertex_info.topology ?
                         renderer->vertex_info.topology
                         : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
                         renderer->vertex_info.topology
                         : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
-       asm_info.primitiveRestartEnable = false;
-
-       /* VkViewport */
-       viewport.x = viewport.y = 0;
-       viewport.width = width;
-       viewport.height = height;
-       viewport.minDepth = 0;
-       viewport.maxDepth = 1;
-
-       /* VkRect2D scissor */
-       scissor.offset.x = scissor.offset.y = 0;
-       scissor.extent.width = width;
-       scissor.extent.height = height;
-
-       /* VkPipelineViewportStateCreateInfo */
-       memset(&viewport_info, 0, sizeof viewport_info);
-       viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
-       viewport_info.viewportCount = 1;
-       viewport_info.pViewports = &viewport;
-       viewport_info.scissorCount = 1;
-       viewport_info.pScissors = &scissor;
-
-       /* VkPipelineRasterizationStateCreateInfo */
-       memset(&rs_info, 0, sizeof rs_info);
-       rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
-       rs_info.polygonMode = VK_POLYGON_MODE_FILL;
-       rs_info.cullMode = VK_CULL_MODE_NONE;
-       rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
-       rs_info.lineWidth = 1.0;
-
-       /* VkPipelineMultisampleStateCreateInfo */
-       memset(&ms_info, 0, sizeof ms_info);
-       ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
-       ms_info.rasterizationSamples = num_samples;
-
-       /* VkStencilOpState */
-       /* The default values for ES are taken by Topi Pohjolainen's code */
-       /* defaults in OpenGL ES 3.1 */
-       memset(&front, 0, sizeof front);
-       front.compareMask = ~0;
-       front.writeMask = ~0;
-       front.reference = 0;
-
-       memset(&back, 0, sizeof back);
-       back.compareMask = ~0;
-       back.writeMask = ~0;
-       back.reference = 0;
-
-       /* VkPipelineDepthStencilStateCreateInfo */
-       memset(&ds_info, 0, sizeof ds_info);
-       ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
-       ds_info.front = front;
-       ds_info.back = back;
-       /* defaults in OpenGL ES 3.1 */
-       ds_info.minDepthBounds = 0;
-       ds_info.maxDepthBounds = 1;
-       /* z buffer, stencil buffer */
-       if (enable_depth) {
-               ds_info.depthTestEnable = VK_TRUE;
-               ds_info.depthWriteEnable = VK_TRUE;
-               ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
-       }
-       if (enable_stencil) {
-               ds_info.stencilTestEnable = VK_TRUE;
-               ds_info.depthTestEnable = VK_FALSE;
-               ds_info.depthWriteEnable = VK_TRUE;
-       }
-
-       /* we only care about the passOp here */
-       ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
-       ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
-       ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
-       ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
-       ds_info.back.compareMask = 0xffffffff;
-       ds_info.back.writeMask = 0xffffffff;
-       ds_info.back.reference = 1;
-       ds_info.front = ds_info.back;
-
-       /* VkPipelineColorBlendAttachmentState */
-       memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
-       cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
+    asm_info.primitiveRestartEnable = false;
+
+    /* VkViewport */
+    viewport.x = viewport.y = 0;
+    viewport.width = width;
+    viewport.height = height;
+    viewport.minDepth = 0;
+    viewport.maxDepth = 1;
+
+    /* VkRect2D scissor */
+    scissor.offset.x = scissor.offset.y = 0;
+    scissor.extent.width = width;
+    scissor.extent.height = height;
+
+    /* VkPipelineViewportStateCreateInfo */
+    memset(&viewport_info, 0, sizeof viewport_info);
+    viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
+    viewport_info.viewportCount = 1;
+    viewport_info.pViewports = &viewport;
+    viewport_info.scissorCount = 1;
+    viewport_info.pScissors = &scissor;
+
+    /* VkPipelineRasterizationStateCreateInfo */
+    memset(&rs_info, 0, sizeof rs_info);
+    rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
+    rs_info.polygonMode = VK_POLYGON_MODE_FILL;
+    rs_info.cullMode = VK_CULL_MODE_NONE;
+    rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
+    rs_info.lineWidth = 1.0;
+
+    /* VkPipelineMultisampleStateCreateInfo */
+    memset(&ms_info, 0, sizeof ms_info);
+    ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
+    ms_info.rasterizationSamples = num_samples;
+
+    /* VkStencilOpState */
+    /* The default values for ES are taken by Topi Pohjolainen's code */
+    /* defaults in OpenGL ES 3.1 */
+    memset(&front, 0, sizeof front);
+    front.compareMask = ~0;
+    front.writeMask = ~0;
+    front.reference = 0;
+
+    memset(&back, 0, sizeof back);
+    back.compareMask = ~0;
+    back.writeMask = ~0;
+    back.reference = 0;
+
+    /* VkPipelineDepthStencilStateCreateInfo */
+    memset(&ds_info, 0, sizeof ds_info);
+    ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
+    ds_info.front = front;
+    ds_info.back = back;
+    /* defaults in OpenGL ES 3.1 */
+    ds_info.minDepthBounds = 0;
+    ds_info.maxDepthBounds = 1;
+    /* z buffer, stencil buffer */
+    if (enable_depth) {
+        ds_info.depthTestEnable = VK_TRUE;
+        ds_info.depthWriteEnable = VK_TRUE;
+        ds_info.depthCompareOp = VK_COMPARE_OP_LESS;
+    }
+    if (enable_stencil) {
+        ds_info.stencilTestEnable = VK_TRUE;
+        ds_info.depthTestEnable = VK_FALSE;
+        ds_info.depthWriteEnable = VK_TRUE;
+    }
+
+    /* we only care about the passOp here */
+    ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
+    ds_info.back.failOp = VK_STENCIL_OP_REPLACE;
+    ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE;
+    ds_info.back.passOp = VK_STENCIL_OP_REPLACE;
+    ds_info.back.compareMask = 0xffffffff;
+    ds_info.back.writeMask = 0xffffffff;
+    ds_info.back.reference = 1;
+    ds_info.front = ds_info.back;
+
+    /* VkPipelineColorBlendAttachmentState */
+    memset(&cb_att_state[0], 0, sizeof cb_att_state[0]);
+    cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT |
                                       VK_COLOR_COMPONENT_G_BIT |
                                       VK_COLOR_COMPONENT_B_BIT |
                                       VK_COLOR_COMPONENT_A_BIT);
 
                                       VK_COLOR_COMPONENT_G_BIT |
                                       VK_COLOR_COMPONENT_B_BIT |
                                       VK_COLOR_COMPONENT_A_BIT);
 
-       /* VkPipelineColorBlendStateCreateInfo */
-       memset(&cb_info, 0, sizeof cb_info);
-       cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
-       cb_info.attachmentCount = 1;
-       cb_info.pAttachments = cb_att_state;
-       /* default in ES 3.1 */
-       for (i = 0; i < 4; i++) {
-               cb_info.blendConstants[i] = 0.0f;
-       }
-
-       /* VkPipelineShaderStageCreateInfo */
-       memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
-
-       sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-       sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
-       sdr_stages[0].module = renderer->vs;
-       sdr_stages[0].pName = "main";
-
-       sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-       sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
-       sdr_stages[1].module = renderer->fs;
-       sdr_stages[1].pName = "main";
-
-       /* VkPushConstantRange */
-       memset(pc_range, 0, sizeof pc_range[0]);
-       pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
-       pc_range[0].size = sizeof (struct vk_dims); /* w, h */
-
-       /* VkPipelineLayoutCreateInfo */
-       memset(&layout_info, 0, sizeof layout_info);
-       layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
-       layout_info.pushConstantRangeCount = 1;
-       layout_info.pPushConstantRanges = pc_range;
-
-       if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create pipeline layout\n");
-               renderer->pipeline = VK_NULL_HANDLE;
-               return;
-       }
-
-       renderer->pipeline_layout = pipeline_layout;
-
-       /* VkGraphicsPipelineCreateInfo */
-       memset(&pipeline_info, 0, sizeof pipeline_info);
-       pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
-       pipeline_info.layout = pipeline_layout;
-       pipeline_info.renderPass = renderer->renderpass;
-       pipeline_info.pVertexInputState = &vert_input_info;
-       pipeline_info.pInputAssemblyState = &asm_info;
-       pipeline_info.pViewportState = &viewport_info;
-       pipeline_info.pRasterizationState = &rs_info;
-       pipeline_info.pMultisampleState = &ms_info;
-       pipeline_info.pDepthStencilState = &ds_info;
-       pipeline_info.pColorBlendState = &cb_info;
-       pipeline_info.stageCount = 2;
-       pipeline_info.pStages = sdr_stages;
-
-       if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
+    /* VkPipelineColorBlendStateCreateInfo */
+    memset(&cb_info, 0, sizeof cb_info);
+    cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
+    cb_info.attachmentCount = 1;
+    cb_info.pAttachments = cb_att_state;
+    /* default in ES 3.1 */
+    for (i = 0; i < 4; i++) {
+        cb_info.blendConstants[i] = 0.0f;
+    }
+
+    /* VkPipelineShaderStageCreateInfo */
+    memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]);
+
+    sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
+    sdr_stages[0].module = renderer->vs;
+    sdr_stages[0].pName = "main";
+
+    sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
+    sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
+    sdr_stages[1].module = renderer->fs;
+    sdr_stages[1].pName = "main";
+
+    /* VkPushConstantRange */
+    memset(pc_range, 0, sizeof pc_range[0]);
+    pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
+    pc_range[0].size = sizeof (struct vk_dims); /* w, h */
+
+    /* VkPipelineLayoutCreateInfo */
+    memset(&layout_info, 0, sizeof layout_info);
+    layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
+    layout_info.pushConstantRangeCount = 1;
+    layout_info.pPushConstantRanges = pc_range;
+
+    if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create pipeline layout\n");
+        renderer->pipeline = VK_NULL_HANDLE;
+        return;
+    }
+
+    renderer->pipeline_layout = pipeline_layout;
+
+    /* VkGraphicsPipelineCreateInfo */
+    memset(&pipeline_info, 0, sizeof pipeline_info);
+    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
+    pipeline_info.layout = pipeline_layout;
+    pipeline_info.renderPass = renderer->renderpass;
+    pipeline_info.pVertexInputState = &vert_input_info;
+    pipeline_info.pInputAssemblyState = &asm_info;
+    pipeline_info.pViewportState = &viewport_info;
+    pipeline_info.pRasterizationState = &rs_info;
+    pipeline_info.pMultisampleState = &ms_info;
+    pipeline_info.pDepthStencilState = &ds_info;
+    pipeline_info.pColorBlendState = &cb_info;
+    pipeline_info.stageCount = 2;
+    pipeline_info.pStages = sdr_stages;
+
+    if (vkCreateGraphicsPipelines(ctx->dev, 0, 1,
                                   &pipeline_info, 0,
                                   &renderer->pipeline) != VK_SUCCESS) {
                                   &pipeline_info, 0,
                                   &renderer->pipeline) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create graphics pipeline.\n");
-               renderer->pipeline = VK_NULL_HANDLE;
-       }
+        fprintf(stderr, "Failed to create graphics pipeline.\n");
+        renderer->pipeline = VK_NULL_HANDLE;
+    }
 }
 
 static VkCommandBuffer
 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
 {
 }
 
 static VkCommandBuffer
 create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool)
 {
-       VkCommandBuffer cmd_buf;
-       VkCommandBufferAllocateInfo alloc_info;
+    VkCommandBuffer cmd_buf;
+    VkCommandBufferAllocateInfo alloc_info;
 
 
-       memset(&alloc_info, 0, sizeof alloc_info);
-       alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
-       alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
-       alloc_info.commandBufferCount = 1;
-       alloc_info.commandPool = cmd_pool;
+    memset(&alloc_info, 0, sizeof alloc_info);
+    alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
+    alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
+    alloc_info.commandBufferCount = 1;
+    alloc_info.commandPool = cmd_pool;
 
 
-       if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
-               return 0;
+    if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS)
+        return 0;
 
 
-       return cmd_buf;
+    return cmd_buf;
 }
 
 static uint32_t
 get_memory_type_idx(VkPhysicalDevice pdev,
 }
 
 static uint32_t
 get_memory_type_idx(VkPhysicalDevice pdev,
-                   const VkMemoryRequirements *mem_reqs,
-                   VkMemoryPropertyFlagBits prop_flags)
+            const VkMemoryRequirements *mem_reqs,
+            VkMemoryPropertyFlagBits prop_flags)
 {
 {
-       VkPhysicalDeviceMemoryProperties pdev_mem_props;
-       uint32_t i;
+    VkPhysicalDeviceMemoryProperties pdev_mem_props;
+    uint32_t i;
 
 
-       vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
+    vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props);
 
 
-       for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
-               const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
+    for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) {
+        const VkMemoryType *type = &pdev_mem_props.memoryTypes[i];
 
 
-               if ((mem_reqs->memoryTypeBits & (1 << i)) &&
-                   (type->propertyFlags & prop_flags) == prop_flags) {
-                       return i;
-                       break;
-               }
-       }
-       return UINT32_MAX;
+        if ((mem_reqs->memoryTypeBits & (1 << i)) &&
+            (type->propertyFlags & prop_flags) == prop_flags) {
+            return i;
+            break;
+        }
+    }
+    return UINT32_MAX;
 }
 
 static VkDeviceMemory
 }
 
 static VkDeviceMemory
@@ -817,10 +842,10 @@ alloc_memory(struct vk_ctx *ctx,
              VkBuffer buffer,
              VkMemoryPropertyFlagBits prop_flags)
 {
              VkBuffer buffer,
              VkMemoryPropertyFlagBits prop_flags)
 {
-       VkExportMemoryAllocateInfo exp_mem_info;
-       VkMemoryAllocateInfo mem_alloc_info;
-       VkDeviceMemory mem;
-       VkMemoryDedicatedAllocateInfoKHR ded_info;
+    VkExportMemoryAllocateInfo exp_mem_info;
+    VkMemoryAllocateInfo mem_alloc_info;
+    VkDeviceMemory mem;
+    VkMemoryDedicatedAllocateInfoKHR ded_info;
 
     if (is_external) {
         memset(&exp_mem_info, 0, sizeof exp_mem_info);
 
     if (is_external) {
         memset(&exp_mem_info, 0, sizeof exp_mem_info);
@@ -829,56 +854,56 @@ alloc_memory(struct vk_ctx *ctx,
             VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
     }
 
             VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
     }
 
-       memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
-       mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
-       mem_alloc_info.pNext = &exp_mem_info;
-       mem_alloc_info.allocationSize = mem_reqs->size;
-       mem_alloc_info.memoryTypeIndex =
-               get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
+    memset(&mem_alloc_info, 0, sizeof mem_alloc_info);
+    mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
+    mem_alloc_info.pNext = &exp_mem_info;
+    mem_alloc_info.allocationSize = mem_reqs->size;
+    mem_alloc_info.memoryTypeIndex =
+        get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags);
 
 
-       if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
-               fprintf(stderr, "No suitable memory type index found.\n");
-               return 0;
-       }
+    if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) {
+        fprintf(stderr, "No suitable memory type index found.\n");
+        return 0;
+    }
 
 
-       if (image || buffer) {
-               memset(&ded_info, 0, sizeof ded_info);
-               ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
-               ded_info.image = image;
-               ded_info.buffer = buffer;
+    if (image || buffer) {
+        memset(&ded_info, 0, sizeof ded_info);
+        ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
+        ded_info.image = image;
+        ded_info.buffer = buffer;
 
 
-               exp_mem_info.pNext = &ded_info;
-       }
+        exp_mem_info.pNext = &ded_info;
+    }
 
 
-       if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
-           VK_SUCCESS)
-               return 0;
+    if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) !=
+        VK_SUCCESS)
+        return 0;
 
 
-       return mem;
+    return mem;
 }
 
 static bool
 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
 {
 }
 
 static bool
 alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
 {
-       VkMemoryDedicatedRequirements ded_reqs;
-       VkImageMemoryRequirementsInfo2 req_info2;
-       VkMemoryRequirements2 mem_reqs2;
+    VkMemoryDedicatedRequirements ded_reqs;
+    VkImageMemoryRequirementsInfo2 req_info2;
+    VkMemoryRequirements2 mem_reqs2;
 
 
-       memset(&ded_reqs, 0, sizeof ded_reqs);
-       ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
+    memset(&ded_reqs, 0, sizeof ded_reqs);
+    ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS;
 
 
-       /* VkImageMemoryRequirementsInfo2 */
-       memset(&req_info2, 0, sizeof req_info2);
-       req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
-       req_info2.image = img_obj->img;
+    /* VkImageMemoryRequirementsInfo2 */
+    memset(&req_info2, 0, sizeof req_info2);
+    req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2;
+    req_info2.image = img_obj->img;
 
 
-       /* VkMemoryRequirements2 */
-       memset(&mem_reqs2, 0, sizeof mem_reqs2);
-       mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
-       mem_reqs2.pNext = &ded_reqs;
+    /* VkMemoryRequirements2 */
+    memset(&mem_reqs2, 0, sizeof mem_reqs2);
+    mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2;
+    mem_reqs2.pNext = &ded_reqs;
 
 
-       vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
-       img_obj->mobj.mem = alloc_memory(ctx,
+    vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2);
+    img_obj->mobj.mem = alloc_memory(ctx,
                                      true, /* is_external = FIXME */
                                      &mem_reqs2.memoryRequirements,
                                      ded_reqs.requiresDedicatedAllocation ?
                                      true, /* is_external = FIXME */
                                      &mem_reqs2.memoryRequirements,
                                      ded_reqs.requiresDedicatedAllocation ?
@@ -887,172 +912,282 @@ alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
                                      mem_reqs2.memoryRequirements.memoryTypeBits &
                                         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
                                      mem_reqs2.memoryRequirements.memoryTypeBits &
                                         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
 
-       img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
-       img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
-       if (img_obj->mobj.mem == VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to allocate image memory.\n");
-               return false;
-       }
+    img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size;
+    img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation;
+    if (img_obj->mobj.mem == VK_NULL_HANDLE) {
+        fprintf(stderr, "Failed to allocate image memory.\n");
+        return false;
+    }
 
 
-       if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
+    if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) !=
             VK_SUCCESS) {
             VK_SUCCESS) {
-               fprintf(stderr, "Failed to bind image memory.\n");
-               return false;
-       }
+        fprintf(stderr, "Failed to bind image memory.\n");
+        return false;
+    }
 
 
-       return true;
+    return true;
 }
 
 static bool
 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
 {
     VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
 }
 
 static bool
 are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props)
 {
     VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info;
-       VkExternalImageFormatProperties ext_img_fmt_props;
-
-       int i;
-       VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
-       VkImageFormatProperties2 img_fmt_props;
-       VkImageUsageFlagBits all_flags[] = {
-               VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
-               VK_IMAGE_USAGE_TRANSFER_DST_BIT,
-               VK_IMAGE_USAGE_SAMPLED_BIT,
-               VK_IMAGE_USAGE_STORAGE_BIT,
-               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
-               VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
-               VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
-               /* Shouldn't be used together with COLOR, DEPTH_STENCIL
-                * attachment bits:
-                * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
-                * Provided by VK_EXT_fragment_density_map
-                * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
-                * Provided by VK_NV_shading_rate_image
-                * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
-                * Provided by VK_KHR_fragment_shading_rate
-                * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
-                */
-       };
-       VkImageUsageFlagBits flags = 0;
-
-       VkExternalMemoryFeatureFlagBits export_feature_flags =
-               VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
-       VkExternalMemoryHandleTypeFlagBits handle_type =
-               VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
-
-       memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
-       ext_img_fmt_info.sType =
-               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
-       ext_img_fmt_info.handleType = handle_type;
-
-       memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
-       ext_img_fmt_props.sType =
-               VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
-
-       memset(&img_fmt_props, 0, sizeof img_fmt_props);
-       img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
-       img_fmt_props.pNext = &ext_img_fmt_props;
-
-       memset(&img_fmt_info, 0, sizeof img_fmt_info);
-       img_fmt_info.sType =
-               VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
-       img_fmt_info.pNext = &ext_img_fmt_info;
-       img_fmt_info.format = props->format;
-       img_fmt_info.type = get_image_type(props->h, props->depth);
-       img_fmt_info.tiling = props->tiling;
-
-       for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
-               img_fmt_info.usage = all_flags[i];
-               if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
-                                       &img_fmt_info,
-                                       &img_fmt_props) == VK_SUCCESS) {
-                       flags |= all_flags[i];
-               }
-       }
-
-       /* usage can't be null */
-       if (flags) {
-               img_fmt_info.usage = flags;
-       }
-       else {
-               fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
-               return false;
-       }
-
-       if (vkGetPhysicalDeviceImageFormatProperties2
-           (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
-               fprintf(stderr,
-                       "Unsupported Vulkan format properties.\n");
-               return false;
-       }
-       props->usage = flags;
-
-       if (props->need_export &&
-           !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
-                   & export_feature_flags)) {
-               fprintf(stderr, "Unsupported Vulkan external memory features.\n");
-               return false;
-       }
-
-       return true;
+    VkExternalImageFormatProperties ext_img_fmt_props;
+
+    int i;
+    VkPhysicalDeviceImageFormatInfo2 img_fmt_info;
+    VkImageFormatProperties2 img_fmt_props;
+    VkImageUsageFlagBits all_flags[] = {
+        VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
+        VK_IMAGE_USAGE_TRANSFER_DST_BIT,
+        VK_IMAGE_USAGE_SAMPLED_BIT,
+        VK_IMAGE_USAGE_STORAGE_BIT,
+        VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+        VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
+        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
+        /* Shouldn't be used together with COLOR, DEPTH_STENCIL
+         * attachment bits:
+         * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
+         * Provided by VK_EXT_fragment_density_map
+         * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
+         * Provided by VK_NV_shading_rate_image
+         * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV,
+         * Provided by VK_KHR_fragment_shading_rate
+         * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
+         */
+    };
+    VkImageUsageFlagBits flags = 0;
+
+    VkExternalMemoryFeatureFlagBits export_feature_flags =
+        VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT;
+    VkExternalMemoryHandleTypeFlagBits handle_type =
+        VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+    memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info);
+    ext_img_fmt_info.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO;
+    ext_img_fmt_info.handleType = handle_type;
+
+    memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props);
+    ext_img_fmt_props.sType =
+        VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES;
+
+    memset(&img_fmt_props, 0, sizeof img_fmt_props);
+    img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+    img_fmt_props.pNext = &ext_img_fmt_props;
+
+    memset(&img_fmt_info, 0, sizeof img_fmt_info);
+    img_fmt_info.sType =
+        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
+    img_fmt_info.pNext = &ext_img_fmt_info;
+    img_fmt_info.format = props->format;
+    img_fmt_info.type = get_image_type(props->h, props->depth);
+    img_fmt_info.tiling = props->tiling;
+
+    for (i = 0; i < ARRAY_SIZE(all_flags); i++) {
+        img_fmt_info.usage = all_flags[i];
+        if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev,
+                    &img_fmt_info,
+                    &img_fmt_props) == VK_SUCCESS) {
+            flags |= all_flags[i];
+        }
+    }
+
+    /* usage can't be null */
+    if (flags) {
+        img_fmt_info.usage = flags;
+    }
+    else {
+        fprintf(stderr, "Unsupported Vulkan format properties: usage.\n");
+        return false;
+    }
+
+    if (vkGetPhysicalDeviceImageFormatProperties2
+        (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) {
+        fprintf(stderr,
+            "Unsupported Vulkan format properties.\n");
+        return false;
+    }
+    props->usage = flags;
+
+    if (props->need_export &&
+        !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures
+            & export_feature_flags)) {
+        fprintf(stderr, "Unsupported Vulkan external memory features.\n");
+        return false;
+    }
+
+    return true;
+}
+
+/* static swapchain / surf related functions */
+
+static bool
+sc_validate_surface(struct vk_ctx *ctx,
+                 VkSurfaceKHR surf)
+{
+    VkBool32 supported;
+    if (!surf) {
+        fprintf(stderr, "No surface!\n");
+        return false;
+    }
+
+    if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to validate surface.\n");
+        return false;
+    }
+
+    if (!supported) {
+        fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx);
+        return false;
+    }
+
+    return true;
+}
+
+static bool
+sc_select_format(struct vk_ctx *ctx,
+                 VkSurfaceKHR surf,
+                 VkSwapchainCreateInfoKHR *s_info)
+{
+    VkSurfaceFormatKHR *formats;
+    uint32_t num_formats;
+
+    if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to get the number of surface formats.\n");
+        return false;
+    }
+
+    if (!num_formats) {
+        fprintf(stderr, "No surface formats found.\n");
+        return false;
+    }
+
+    formats = malloc(num_formats * sizeof *formats);
+
+    if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to get the supported surface formats.\n");
+        return false;
+    }
+
+    if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) {
+        s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
+        s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
+    } else {
+        s_info->imageFormat = formats[0].format;
+        s_info->imageColorSpace = formats[0].colorSpace;
+    }
+    free(formats);
+
+    return true;
 }
 
 }
 
+static bool
+sc_select_supported_present_modes(struct vk_ctx *ctx,
+                                  VkSurfaceKHR surf,
+                                  bool has_vsync,
+                                  VkSwapchainCreateInfoKHR *s_info)
+{
+    VkPresentModeKHR *present_modes;
+    uint32_t num_present_modes;
+    int i;
+
+    /* find supported present modes */
+    if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) {
+        fprintf(stderr, "Failed to get the number of the supported presentation modes.\n");
+        return false;
+    }
+
+    present_modes = malloc(num_present_modes * sizeof *present_modes);
+    if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to get the number of supported presentation modes.\n");
+        return false;
+    }
+    if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes,
+                                                  present_modes) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to get the supported presentation modes.\n");
+        return false;
+    }
+
+    s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR;
+    if (!has_vsync) {
+        for (i = 0; i < num_present_modes; i++) {
+            if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
+                s_info->presentMode = present_modes[i];
+                goto success;
+            }
+            if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
+                s_info->presentMode = present_modes[i];
+                goto success;
+            }
+        }
+    }
+
+success:
+    free(present_modes);
+    return true;
+}
+
+/* end of static functions */
+
 /* exposed Vulkan functions */
 
 bool
 vk_init_ctx(struct vk_ctx *ctx)
 {
 /* exposed Vulkan functions */
 
 bool
 vk_init_ctx(struct vk_ctx *ctx)
 {
-       if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to create Vulkan instance.\n");
-               goto fail;
-       }
+    if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) {
+        fprintf(stderr, "Failed to create Vulkan instance.\n");
+        goto fail;
+    }
 
 
-       if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to find suitable physical device.\n");
-               goto fail;
-       }
+    if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) {
+        fprintf(stderr, "Failed to find suitable physical device.\n");
+        goto fail;
+    }
 
 
-       if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to create Vulkan device.\n");
-               goto fail;
-       }
+    if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) {
+        fprintf(stderr, "Failed to create Vulkan device.\n");
+        goto fail;
+    }
 
 
-       fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
-       return true;
+    fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID);
+    return true;
 
 fail:
 
 fail:
-       vk_cleanup_ctx(ctx);
-       return false;
+    vk_cleanup_ctx(ctx);
+    return false;
 }
 
 bool
 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
 {
 }
 
 bool
 vk_init_ctx_for_rendering(struct vk_ctx *ctx)
 {
-       if (!vk_init_ctx(ctx)) {
-               fprintf(stderr, "Failed to initialize Vulkan.\n");
-               return false;
-       }
+    if (!vk_init_ctx(ctx)) {
+        fprintf(stderr, "Failed to initialize Vulkan.\n");
+        return false;
+    }
 
 
-       if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to create command pool.\n");
-               goto fail;
-       }
+    if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) {
+        fprintf(stderr, "Failed to create command pool.\n");
+        goto fail;
+    }
 
 
-       if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
+    if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) ==
                                        VK_NULL_HANDLE) {
                                        VK_NULL_HANDLE) {
-               fprintf(stderr, "Failed to create command buffer.\n");
-               goto fail;
-       }
+        fprintf(stderr, "Failed to create command buffer.\n");
+        goto fail;
+    }
 
 
-       vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
-       if (!ctx->queue) {
-               fprintf(stderr, "Failed to get command queue.\n");
-               goto fail;
-       }
+    vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue);
+    if (!ctx->queue) {
+        fprintf(stderr, "Failed to get command queue.\n");
+        goto fail;
+    }
 
 
-       return true;
+    return true;
 
 fail:
 
 fail:
-       vk_cleanup_ctx(ctx);
-       return false;
+    vk_cleanup_ctx(ctx);
+    return false;
 }
 
 void
 }
 
 void
@@ -1063,132 +1198,132 @@ vk_cleanup_ctx(struct vk_ctx *ctx)
     }
 
     if (ctx->cmd_buf != VK_NULL_HANDLE) {
     }
 
     if (ctx->cmd_buf != VK_NULL_HANDLE) {
-               vkResetCommandBuffer(ctx->cmd_buf,
+        vkResetCommandBuffer(ctx->cmd_buf,
                              VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
                              VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
-               vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
-               ctx->cmd_buf = VK_NULL_HANDLE;
-       }
+        vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf);
+        ctx->cmd_buf = VK_NULL_HANDLE;
+    }
 
 
-       if (ctx->cmd_pool != VK_NULL_HANDLE) {
-               vkResetCommandPool(ctx->dev, ctx->cmd_pool,
+    if (ctx->cmd_pool != VK_NULL_HANDLE) {
+        vkResetCommandPool(ctx->dev, ctx->cmd_pool,
                            VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
                            VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT);
-               vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
-               ctx->cmd_pool = VK_NULL_HANDLE;
-       }
-
-       if (ctx->dev != VK_NULL_HANDLE) {
-               vkDestroyDevice(ctx->dev, 0);
-               ctx->dev = VK_NULL_HANDLE;
-       }
-
-       if (ctx->inst != VK_NULL_HANDLE) {
-               vkDestroyInstance(ctx->inst, 0);
-               ctx->inst = VK_NULL_HANDLE;
-       }
+        vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0);
+        ctx->cmd_pool = VK_NULL_HANDLE;
+    }
+
+    if (ctx->dev != VK_NULL_HANDLE) {
+        vkDestroyDevice(ctx->dev, 0);
+        ctx->dev = VK_NULL_HANDLE;
+    }
+
+    if (ctx->inst != VK_NULL_HANDLE) {
+        vkDestroyInstance(ctx->inst, 0);
+        ctx->inst = VK_NULL_HANDLE;
+    }
 }
 
 bool
 vk_create_image(struct vk_ctx *ctx,
 }
 
 bool
 vk_create_image(struct vk_ctx *ctx,
-                               struct vk_image_props *props,
-                               struct vk_image_obj *img)
+                struct vk_image_props *props,
+                struct vk_image_obj *img)
 {
 {
-       VkImageCreateInfo img_info;
-
-       memset(&img_info, 0, sizeof img_info);
-       img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-       img_info.pNext = 0; /* do something if external */
-       img_info.imageType = get_image_type(props->h, props->depth);
-       img_info.format = props->format;
-       img_info.extent.width = props->w;
-       img_info.extent.height = props->h;
-       img_info.extent.depth = props->depth;
-       img_info.mipLevels = props->num_levels ? props->num_levels : 1;
-       img_info.arrayLayers = props->num_layers ?
+    VkImageCreateInfo img_info;
+
+    memset(&img_info, 0, sizeof img_info);
+    img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    img_info.pNext = 0; /* do something if external */
+    img_info.imageType = get_image_type(props->h, props->depth);
+    img_info.format = props->format;
+    img_info.extent.width = props->w;
+    img_info.extent.height = props->h;
+    img_info.extent.depth = props->depth;
+    img_info.mipLevels = props->num_levels ? props->num_levels : 1;
+    img_info.arrayLayers = props->num_layers ?
                            props->num_layers : VK_SAMPLE_COUNT_1_BIT;
                            props->num_layers : VK_SAMPLE_COUNT_1_BIT;
-       img_info.samples = get_num_samples(props->num_samples);
-       img_info.tiling = props->tiling;
-       img_info.usage = props->usage ?
+    img_info.samples = get_num_samples(props->num_samples);
+    img_info.tiling = props->tiling;
+    img_info.usage = props->usage ?
                      props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
                      props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
-       img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-       img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
 
 
-       if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
-               goto fail;
+    if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
+        goto fail;
 
 
-       if(!alloc_image_memory(ctx, img))
-               goto fail;
+    if(!alloc_image_memory(ctx, img))
+        goto fail;
 
 
-       return true;
+    return true;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to create external image.\n");
-       vk_destroy_image(ctx, img);
-       img->img = VK_NULL_HANDLE;
-       img->mobj.mem = VK_NULL_HANDLE;
-       return false;
+    fprintf(stderr, "Failed to create external image.\n");
+    vk_destroy_image(ctx, img);
+    img->img = VK_NULL_HANDLE;
+    img->mobj.mem = VK_NULL_HANDLE;
+    return false;
 }
 
 void
 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
 {
 }
 
 void
 vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj)
 {
-       if (img_obj->img != VK_NULL_HANDLE) {
-               vkDestroyImage(ctx->dev, img_obj->img, 0);
-               img_obj->img = VK_NULL_HANDLE;
-       }
-
-       if (img_obj->mobj.mem != VK_NULL_HANDLE) {
-               vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
-               img_obj->mobj.mem = VK_NULL_HANDLE;
-       }
+    if (img_obj->img != VK_NULL_HANDLE) {
+        vkDestroyImage(ctx->dev, img_obj->img, 0);
+        img_obj->img = VK_NULL_HANDLE;
+    }
+
+    if (img_obj->mobj.mem != VK_NULL_HANDLE) {
+        vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0);
+        img_obj->mobj.mem = VK_NULL_HANDLE;
+    }
 }
 
 bool
 vk_create_ext_image(struct vk_ctx *ctx,
 }
 
 bool
 vk_create_ext_image(struct vk_ctx *ctx,
-                   struct vk_image_props *props, struct vk_image_obj *img)
+                    struct vk_image_props *props, struct vk_image_obj *img)
 {
 {
-       VkExternalMemoryImageCreateInfo ext_img_info;
-       VkImageCreateInfo img_info;
-
-       memset(&ext_img_info, 0, sizeof ext_img_info);
-       ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
-       ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
-
-       memset(&img_info, 0, sizeof img_info);
-       img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
-       img_info.pNext = &ext_img_info;
-       img_info.imageType = get_image_type(props->h, props->depth);
-       img_info.format = props->format;
-       img_info.extent.width = props->w;
-       img_info.extent.height = props->h;
-       img_info.extent.depth = props->depth;
-       img_info.mipLevels = props->num_levels ? props->num_levels : 1;
-       img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
-       img_info.samples = get_num_samples(props->num_samples);
-       img_info.tiling = props->tiling;
-       img_info.usage = props->usage;
-       img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
-       img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-       /* issue 17 of EXT_external_objects
-        * Required in OpenGL implementations that support
-        * ARB_texture_view, OES_texture_view, EXT_texture_view,
-        * or OpenGL 4.3 and above.
-        */
-       img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
-
-       if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
-               goto fail;
-
-       if(!alloc_image_memory(ctx, img))
-               goto fail;
-
-       return true;
+    VkExternalMemoryImageCreateInfo ext_img_info;
+    VkImageCreateInfo img_info;
+
+    memset(&ext_img_info, 0, sizeof ext_img_info);
+    ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
+    ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+    memset(&img_info, 0, sizeof img_info);
+    img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+    img_info.pNext = &ext_img_info;
+    img_info.imageType = get_image_type(props->h, props->depth);
+    img_info.format = props->format;
+    img_info.extent.width = props->w;
+    img_info.extent.height = props->h;
+    img_info.extent.depth = props->depth;
+    img_info.mipLevels = props->num_levels ? props->num_levels : 1;
+    img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT;
+    img_info.samples = get_num_samples(props->num_samples);
+    img_info.tiling = props->tiling;
+    img_info.usage = props->usage;
+    img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+    img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    /* issue 17 of EXT_external_objects
+     * Required in OpenGL implementations that support
+     * ARB_texture_view, OES_texture_view, EXT_texture_view,
+     * or OpenGL 4.3 and above.
+     */
+    img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+
+    if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS)
+        goto fail;
+
+    if(!alloc_image_memory(ctx, img))
+        goto fail;
+
+    return true;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to create external image.\n");
-       vk_destroy_image(ctx, img);
-       img->img = VK_NULL_HANDLE;
-       img->mobj.mem = VK_NULL_HANDLE;
-       return false;
+    fprintf(stderr, "Failed to create external image.\n");
+    vk_destroy_image(ctx, img);
+    img->img = VK_NULL_HANDLE;
+    img->mobj.mem = VK_NULL_HANDLE;
+    return false;
 }
 
 bool
 }
 
 bool
@@ -1206,25 +1341,25 @@ vk_fill_ext_image_props(struct vk_ctx *ctx,
                         bool need_export,
                         struct vk_image_props *props)
 {
                         bool need_export,
                         struct vk_image_props *props)
 {
-       props->w = w;
-       props->h = h;
-       props->depth = d;
+    props->w = w;
+    props->h = h;
+    props->depth = d;
 
 
-       props->num_samples = num_samples;
-       props->num_levels = num_levels;
-       props->num_layers = num_layers;
+    props->num_samples = num_samples;
+    props->num_levels = num_levels;
+    props->num_layers = num_layers;
 
 
-       props->format = format;
-       props->tiling = tiling;
+    props->format = format;
+    props->tiling = tiling;
 
 
-       props->in_layout = in_layout;
-       props->end_layout = end_layout;
+    props->in_layout = in_layout;
+    props->end_layout = end_layout;
     props->need_export = need_export;
 
     props->need_export = need_export;
 
-       if (!are_props_supported(ctx, props))
-               return false;
+    if (!are_props_supported(ctx, props))
+        return false;
 
 
-       return true;
+    return true;
 }
 
 bool
 }
 
 bool
@@ -1240,40 +1375,45 @@ vk_create_renderer(struct vk_ctx *ctx,
                    struct vk_vertex_info *vert_info,
                    struct vk_renderer *renderer)
 {
                    struct vk_vertex_info *vert_info,
                    struct vk_renderer *renderer)
 {
-       memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
-       if (vert_info)
-               renderer->vertex_info = *vert_info;
+    memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info);
+    if (vert_info)
+        renderer->vertex_info = *vert_info;
+
+    if (!color_att || depth_att) {
+        fprintf(stderr, "Empty attachment.\n");
+        goto fail;
+    }
 
 
-       renderer->renderpass = create_renderpass(ctx, &color_att->props,
+    renderer->renderpass = create_renderpass(ctx, &color_att->props,
                                              &depth_att->props);
                                              &depth_att->props);
-       if (renderer->renderpass == VK_NULL_HANDLE)
-               goto fail;
+    if (renderer->renderpass == VK_NULL_HANDLE)
+        goto fail;
 
 
-       create_framebuffer(ctx, color_att, depth_att, renderer);
-       if (renderer->fb == VK_NULL_HANDLE)
-               goto fail;
+    create_framebuffer(ctx, color_att, depth_att, renderer);
+    if (renderer->fb == VK_NULL_HANDLE)
+        goto fail;
 
 
-       renderer->vs = create_shader_module(ctx, vs_src, vs_size);
-       if (renderer->vs == VK_NULL_HANDLE)
-               goto fail;
+    renderer->vs = create_shader_module(ctx, vs_src, vs_size);
+    if (renderer->vs == VK_NULL_HANDLE)
+        goto fail;
 
 
-       renderer->fs = create_shader_module(ctx, fs_src, fs_size);
-       if (renderer->fs == VK_NULL_HANDLE)
-               goto fail;
+    renderer->fs = create_shader_module(ctx, fs_src, fs_size);
+    if (renderer->fs == VK_NULL_HANDLE)
+        goto fail;
 
 
-       create_pipeline(ctx, color_att->props.w, color_att->props.h,
+    create_pipeline(ctx, color_att->props.w, color_att->props.h,
                     color_att->props.num_samples, enable_depth,
                     enable_stencil, renderer);
 
                     color_att->props.num_samples, enable_depth,
                     enable_stencil, renderer);
 
-       if (renderer->pipeline == VK_NULL_HANDLE)
-               goto fail;
+    if (renderer->pipeline == VK_NULL_HANDLE)
+        goto fail;
 
 
-       return true;
+    return true;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to create graphics pipeline.\n");
-       vk_destroy_renderer(ctx, renderer);
-       return false;
+    fprintf(stderr, "Failed to create graphics pipeline.\n");
+    vk_destroy_renderer(ctx, renderer);
+    return false;
 }
 
 void
 }
 
 void
@@ -1281,34 +1421,34 @@ vk_destroy_renderer(struct vk_ctx *ctx,
                     struct vk_renderer *renderer)
 {
     if (renderer->renderpass != VK_NULL_HANDLE) {
                     struct vk_renderer *renderer)
 {
     if (renderer->renderpass != VK_NULL_HANDLE) {
-               vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
-               renderer->renderpass = VK_NULL_HANDLE;
-       }
-
-       if (renderer->vs != VK_NULL_HANDLE) {
-               vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
-               renderer->vs = VK_NULL_HANDLE;
-       }
-
-       if (renderer->fs != VK_NULL_HANDLE) {
-               vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
-               renderer->fs = VK_NULL_HANDLE;
-       }
-
-       if (renderer->fb != VK_NULL_HANDLE) {
-               vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
-               renderer->fb = VK_NULL_HANDLE;
-       }
-
-       if (renderer->pipeline != VK_NULL_HANDLE) {
-               vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
-               renderer->pipeline = VK_NULL_HANDLE;
-       }
-
-       if (renderer->pipeline_layout != VK_NULL_HANDLE) {
-               vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
-               renderer->pipeline_layout = VK_NULL_HANDLE;
-       }
+        vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0);
+        renderer->renderpass = VK_NULL_HANDLE;
+    }
+
+    if (renderer->vs != VK_NULL_HANDLE) {
+        vkDestroyShaderModule(ctx->dev, renderer->vs, 0);
+        renderer->vs = VK_NULL_HANDLE;
+    }
+
+    if (renderer->fs != VK_NULL_HANDLE) {
+        vkDestroyShaderModule(ctx->dev, renderer->fs, 0);
+        renderer->fs = VK_NULL_HANDLE;
+    }
+
+    if (renderer->fb != VK_NULL_HANDLE) {
+        vkDestroyFramebuffer(ctx->dev, renderer->fb, 0);
+        renderer->fb = VK_NULL_HANDLE;
+    }
+
+    if (renderer->pipeline != VK_NULL_HANDLE) {
+        vkDestroyPipeline(ctx->dev, renderer->pipeline, 0);
+        renderer->pipeline = VK_NULL_HANDLE;
+    }
+
+    if (renderer->pipeline_layout != VK_NULL_HANDLE) {
+        vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0);
+        renderer->pipeline_layout = VK_NULL_HANDLE;
+    }
 }
 
 bool
 }
 
 bool
@@ -1317,271 +1457,271 @@ vk_create_ext_buffer(struct vk_ctx *ctx,
                      VkBufferUsageFlagBits usage,
                      struct vk_buf *bo)
 {
                      VkBufferUsageFlagBits usage,
                      struct vk_buf *bo)
 {
-       VkExternalMemoryBufferCreateInfo ext_bo_info;
+    VkExternalMemoryBufferCreateInfo ext_bo_info;
 
 
-       memset(&ext_bo_info, 0, sizeof ext_bo_info);
-       ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
-       ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+    memset(&ext_bo_info, 0, sizeof ext_bo_info);
+    ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
+    ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
 
 
-       if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
-               fprintf(stderr, "Failed to allocate external buffer.\n");
-               return false;
-       }
+    if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) {
+        fprintf(stderr, "Failed to allocate external buffer.\n");
+        return false;
+    }
 
 
-       return true;
+    return true;
 }
 
 bool
 vk_create_buffer(struct vk_ctx *ctx,
                  bool is_external,
 }
 
 bool
 vk_create_buffer(struct vk_ctx *ctx,
                  bool is_external,
-                                uint32_t sz,
-                                VkBufferUsageFlagBits usage,
-                                void *pnext,
-                                struct vk_buf *bo)
+                 uint32_t sz,
+                 VkBufferUsageFlagBits usage,
+                 void *pnext,
+                 struct vk_buf *bo)
 {
 {
-       VkBufferCreateInfo buf_info;
-       VkMemoryRequirements mem_reqs;
-
-       bo->mobj.mem = VK_NULL_HANDLE;
-       bo->buf = VK_NULL_HANDLE;
-
-       /* VkBufferCreateInfo */
-       memset(&buf_info, 0, sizeof buf_info);
-       buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
-       buf_info.size = sz;
-       buf_info.usage = usage;
-       buf_info.pNext = pnext;
-       buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
-
-       if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
-               goto fail;
-
-       /* allocate buffer */
-       vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
-       /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
-        * host cache management commands vkFlushMappedMemoryRanges and
-        * vkInvalidateMappedMemoryRanges are not needed to flush host
-        * writes to the device or make device writes visible to the
-        * host, respectively. */
-       bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
+    VkBufferCreateInfo buf_info;
+    VkMemoryRequirements mem_reqs;
+
+    bo->mobj.mem = VK_NULL_HANDLE;
+    bo->buf = VK_NULL_HANDLE;
+
+    /* VkBufferCreateInfo */
+    memset(&buf_info, 0, sizeof buf_info);
+    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
+    buf_info.size = sz;
+    buf_info.usage = usage;
+    buf_info.pNext = pnext;
+    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+
+    if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS)
+        goto fail;
+
+    /* allocate buffer */
+    vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs);
+    /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the
+     * host cache management commands vkFlushMappedMemoryRanges and
+     * vkInvalidateMappedMemoryRanges are not needed to flush host
+     * writes to the device or make device writes visible to the
+     * host, respectively. */
+    bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE,
                                 VK_NULL_HANDLE,
                                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
 
                                 VK_NULL_HANDLE,
                                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
 
-       if (bo->mobj.mem == VK_NULL_HANDLE)
-               goto fail;
+    if (bo->mobj.mem == VK_NULL_HANDLE)
+        goto fail;
 
 
-       bo->mobj.mem_sz = sz;
+    bo->mobj.mem_sz = sz;
 
 
-       if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to bind buffer memory.\n");
-               goto fail;
-       }
+    if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to bind buffer memory.\n");
+        goto fail;
+    }
 
 
-       return true;
+    return true;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to allocate buffer.\n");
-       vk_destroy_buffer(ctx, bo);
-       return false;
+    fprintf(stderr, "Failed to allocate buffer.\n");
+    vk_destroy_buffer(ctx, bo);
+    return false;
 }
 
 bool
 vk_update_buffer_data(struct vk_ctx *ctx,
 }
 
 bool
 vk_update_buffer_data(struct vk_ctx *ctx,
-                                         void *data,
-                                         uint32_t data_sz,
-                                         struct vk_buf *bo)
+                      void *data,
+                      uint32_t data_sz,
+                      struct vk_buf *bo)
 {
 {
-       void *map;
+    void *map;
 
 
-       if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to map buffer memory.\n");
-               goto fail;
-       }
+    if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to map buffer memory.\n");
+        goto fail;
+    }
 
 
-       memcpy(map, data, data_sz);
+    memcpy(map, data, data_sz);
 
 
-       vkUnmapMemory(ctx->dev, bo->mobj.mem);
-       return true;
+    vkUnmapMemory(ctx->dev, bo->mobj.mem);
+    return true;
 
 fail:
 
 fail:
-       fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
-       vk_destroy_buffer(ctx, bo);
+    fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n");
+    vk_destroy_buffer(ctx, bo);
 
 
-       return false;
+    return false;
 }
 
 void
 vk_destroy_buffer(struct vk_ctx *ctx,
 }
 
 void
 vk_destroy_buffer(struct vk_ctx *ctx,
-                 struct vk_buf *bo)
+          struct vk_buf *bo)
 {
 {
-       if (bo->buf != VK_NULL_HANDLE)
-               vkDestroyBuffer(ctx->dev, bo->buf, 0);
+    if (bo->buf != VK_NULL_HANDLE)
+        vkDestroyBuffer(ctx->dev, bo->buf, 0);
 
 
-       if (bo->mobj.mem != VK_NULL_HANDLE)
-               vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
+    if (bo->mobj.mem != VK_NULL_HANDLE)
+        vkFreeMemory(ctx->dev, bo->mobj.mem, 0);
 
 
-       bo->mobj.mem_sz = 0;
-       bo->buf = VK_NULL_HANDLE;
-       bo->mobj.mem = VK_NULL_HANDLE;
+    bo->mobj.mem_sz = 0;
+    bo->buf = VK_NULL_HANDLE;
+    bo->mobj.mem = VK_NULL_HANDLE;
 }
 
 void
 vk_draw(struct vk_ctx *ctx,
 }
 
 void
 vk_draw(struct vk_ctx *ctx,
-               struct vk_buf *vbo,
-               struct vk_renderer *renderer,
-               float *vk_fb_color,
-               uint32_t vk_fb_color_count,
-               struct vk_semaphores *semaphores,
-               struct vk_image_att *attachments,
-               uint32_t n_attachments,
-               float x, float y,
-               float w, float h)
+        struct vk_buf *vbo,
+        struct vk_renderer *renderer,
+        float *vk_fb_color,
+        uint32_t vk_fb_color_count,
+        struct vk_semaphores *semaphores,
+        struct vk_image_att *attachments,
+        uint32_t n_attachments,
+        float x, float y,
+        float w, float h)
 {
 {
-       VkCommandBufferBeginInfo cmd_begin_info;
-       VkRenderPassBeginInfo rp_begin_info;
-       VkRect2D rp_area;
-       VkClearValue clear_values[2];
-       VkSubmitInfo submit_info;
-       VkDeviceSize offsets[] = {0};
-       VkPipelineStageFlagBits stage_flags;
-       struct vk_dims img_size;
-
-       assert(vk_fb_color_count == 4);
-
-       /* VkCommandBufferBeginInfo */
-       memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
-       cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-       cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
-
-       /* VkRect2D render area */
-       memset(&rp_area, 0, sizeof rp_area);
-       rp_area.extent.width = (uint32_t)w;
-       rp_area.extent.height = (uint32_t)h;
-       rp_area.offset.x = x;
-       rp_area.offset.y = y;
-
-       /* VkClearValue */
-       memset(&clear_values[0], 0, sizeof clear_values[0]);
-       clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
-       clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
-       clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
-       clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
-
-       memset(&clear_values[1], 0, sizeof clear_values[1]);
-       clear_values[1].depthStencil.depth = 1.0;
-       clear_values[1].depthStencil.stencil = 0;
-
-       /* VkRenderPassBeginInfo */
-       memset(&rp_begin_info, 0, sizeof rp_begin_info);
-       rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-       rp_begin_info.renderPass = renderer->renderpass;
-       rp_begin_info.framebuffer = renderer->fb;
-       rp_begin_info.renderArea = rp_area;
-       rp_begin_info.clearValueCount = 2;
-       rp_begin_info.pClearValues = clear_values;
-
-       /* VkSubmitInfo */
-       stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
-
-       memset(&submit_info, 0, sizeof submit_info);
-       submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-       submit_info.commandBufferCount = 1;
-       submit_info.pCommandBuffers = &ctx->cmd_buf;
-
-       /* semaphores */
-       if (semaphores) {
-               assert(semaphores->frame_ready);
-               assert(semaphores->frame_done);
-
-               submit_info.pWaitDstStageMask = &stage_flags;
-               submit_info.waitSemaphoreCount = 1;
-               submit_info.pWaitSemaphores = &semaphores->frame_done;
-
-               submit_info.signalSemaphoreCount = 1;
-               submit_info.pSignalSemaphores = &semaphores->frame_ready;
-       }
-
-       vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
-       vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
-
-       viewport.x = x;
-       viewport.y = y;
-       viewport.width = w;
-       viewport.height = h;
-
-       scissor.offset.x = x;
-       scissor.offset.y = y;
-       scissor.extent.width = w;
-       scissor.extent.height = h;
-
-       vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
-       vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
-
-       img_size.w = (float)w;
-       img_size.h = (float)h;
-       vkCmdPushConstants(ctx->cmd_buf,
-                          renderer->pipeline_layout,
-                          VK_SHADER_STAGE_FRAGMENT_BIT,
-                          0, sizeof (struct vk_dims),
-                          &img_size);
-
-       if (vbo) {
-               vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
-       }
-       vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
-
-       int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
-       vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
-       vkCmdEndRenderPass(ctx->cmd_buf);
+    VkCommandBufferBeginInfo cmd_begin_info;
+    VkRenderPassBeginInfo rp_begin_info;
+    VkRect2D rp_area;
+    VkClearValue clear_values[2];
+    VkSubmitInfo submit_info;
+    VkDeviceSize offsets[] = {0};
+    VkPipelineStageFlagBits stage_flags;
+    struct vk_dims img_size;
+
+    assert(vk_fb_color_count == 4);
+
+    /* VkCommandBufferBeginInfo */
+    memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
+    cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
+
+    /* VkRect2D render area */
+    memset(&rp_area, 0, sizeof rp_area);
+    rp_area.extent.width = (uint32_t)w;
+    rp_area.extent.height = (uint32_t)h;
+    rp_area.offset.x = x;
+    rp_area.offset.y = y;
+
+    /* VkClearValue */
+    memset(&clear_values[0], 0, sizeof clear_values[0]);
+    clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
+    clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
+    clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
+    clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
+
+    memset(&clear_values[1], 0, sizeof clear_values[1]);
+    clear_values[1].depthStencil.depth = 1.0;
+    clear_values[1].depthStencil.stencil = 0;
+
+    /* VkRenderPassBeginInfo */
+    memset(&rp_begin_info, 0, sizeof rp_begin_info);
+    rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    rp_begin_info.renderPass = renderer->renderpass;
+    rp_begin_info.framebuffer = renderer->fb;
+    rp_begin_info.renderArea = rp_area;
+    rp_begin_info.clearValueCount = 2;
+    rp_begin_info.pClearValues = clear_values;
+
+    /* VkSubmitInfo */
+    stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+
+    memset(&submit_info, 0, sizeof submit_info);
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &ctx->cmd_buf;
+
+    /* semaphores */
+    if (semaphores) {
+        assert(semaphores->frame_ready);
+        assert(semaphores->frame_done);
+
+        submit_info.pWaitDstStageMask = &stage_flags;
+        submit_info.waitSemaphoreCount = 1;
+        submit_info.pWaitSemaphores = &semaphores->frame_done;
+
+        submit_info.signalSemaphoreCount = 1;
+        submit_info.pSignalSemaphores = &semaphores->frame_ready;
+    }
+
+    vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+    vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
+
+    viewport.x = x;
+    viewport.y = y;
+    viewport.width = w;
+    viewport.height = h;
+
+    scissor.offset.x = x;
+    scissor.offset.y = y;
+    scissor.extent.width = w;
+    scissor.extent.height = h;
+
+    vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
+    vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
+
+    img_size.w = (float)w;
+    img_size.h = (float)h;
+    vkCmdPushConstants(ctx->cmd_buf,
+               renderer->pipeline_layout,
+               VK_SHADER_STAGE_FRAGMENT_BIT,
+               0, sizeof (struct vk_dims),
+               &img_size);
+
+    if (vbo) {
+        vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets);
+    }
+    vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
+
+    int num_vertices = vbo ? renderer->vertex_info.num_verts : 4;
+    vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0);
+    vkCmdEndRenderPass(ctx->cmd_buf);
     if (attachments) {
     if (attachments) {
-               VkImageMemoryBarrier *barriers =
-                       calloc(n_attachments, sizeof(VkImageMemoryBarrier));
-               VkImageMemoryBarrier *barrier = barriers;
-               for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
-                       struct vk_image_att *att = &attachments[n];
-                       VkImageAspectFlagBits depth_stencil_flags =
-                               get_aspect_from_depth_format(att->props.format);
-                       bool is_depth = (depth_stencil_flags != 0);
-
-                       /* Insert barrier to mark ownership transfer. */
-                       barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-                       barrier->oldLayout = is_depth ?
-                               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
-                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-                       barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
-                       barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
-                       barrier->dstAccessMask = get_access_mask(barrier->newLayout);
-                       barrier->srcQueueFamilyIndex = ctx->qfam_idx;
-                       barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
-                       barrier->image = att->obj.img;
-                       barrier->subresourceRange.aspectMask = is_depth ?
-                               depth_stencil_flags :
-                               VK_IMAGE_ASPECT_COLOR_BIT;
-                       barrier->subresourceRange.baseMipLevel = 0;
-                       barrier->subresourceRange.levelCount = 1;
-                       barrier->subresourceRange.baseArrayLayer = 0;
-                       barrier->subresourceRange.layerCount = 1;
-               }
-
-               vkCmdPipelineBarrier(ctx->cmd_buf,
-                                    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
-                                    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
-                                    0,
-                                    0, NULL,
-                                    0, NULL,
-                                    n_attachments, barriers);
-               free(barriers);
-       }
-
-       vkEndCommandBuffer(ctx->cmd_buf);
-
-       if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to submit queue.\n");
-       }
-
-       if (!semaphores)
-               vkQueueWaitIdle(ctx->queue);
+        VkImageMemoryBarrier *barriers =
+            calloc(n_attachments, sizeof(VkImageMemoryBarrier));
+        VkImageMemoryBarrier *barrier = barriers;
+        for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
+            struct vk_image_att *att = &attachments[n];
+            VkImageAspectFlagBits depth_stencil_flags =
+                get_aspect_from_depth_format(att->props.format);
+            bool is_depth = (depth_stencil_flags != 0);
+
+            /* Insert barrier to mark ownership transfer. */
+            barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+            barrier->oldLayout = is_depth ?
+                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
+                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+            barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
+            barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
+            barrier->dstAccessMask = get_access_mask(barrier->newLayout);
+            barrier->srcQueueFamilyIndex = ctx->qfam_idx;
+            barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
+            barrier->image = att->obj.img;
+            barrier->subresourceRange.aspectMask = is_depth ?
+                depth_stencil_flags :
+                VK_IMAGE_ASPECT_COLOR_BIT;
+            barrier->subresourceRange.baseMipLevel = 0;
+            barrier->subresourceRange.levelCount = 1;
+            barrier->subresourceRange.baseArrayLayer = 0;
+            barrier->subresourceRange.layerCount = 1;
+        }
+
+        vkCmdPipelineBarrier(ctx->cmd_buf,
+                     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+                     VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                     0,
+                     0, NULL,
+                     0, NULL,
+                     n_attachments, barriers);
+        free(barriers);
+    }
+
+    vkEndCommandBuffer(ctx->cmd_buf);
+
+    if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to submit queue.\n");
+    }
+
+    if (!semaphores)
+        vkQueueWaitIdle(ctx->queue);
 }
 
 void
 }
 
 void
@@ -1597,194 +1737,239 @@ vk_clear_color(struct vk_ctx *ctx,
                float x, float y,
                float w, float h)
 {
                float x, float y,
                float w, float h)
 {
-       VkCommandBufferBeginInfo cmd_begin_info;
-       VkRenderPassBeginInfo rp_begin_info;
-       VkRect2D rp_area;
-       VkClearValue clear_values[2];
-       VkSubmitInfo submit_info;
-       VkPipelineStageFlagBits stage_flags;
-       VkImageSubresourceRange img_range;
-
-       assert(vk_fb_color_count == 4);
-
-       /* VkCommandBufferBeginInfo */
-       memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
-       cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-       cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-
-       /* VkRect2D render area */
-       memset(&rp_area, 0, sizeof rp_area);
-       rp_area.extent.width = (uint32_t)w;
-       rp_area.extent.height = (uint32_t)h;
-       rp_area.offset.x = x;
-       rp_area.offset.y = y;
-
-       /* VkClearValue */
-       memset(&clear_values[0], 0, sizeof clear_values[0]);
-       clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
-       clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
-       clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
-       clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
-
-       memset(&clear_values[1], 0, sizeof clear_values[1]);
-       clear_values[1].depthStencil.depth = 1.0;
-       clear_values[1].depthStencil.stencil = 0;
-
-       /* VkRenderPassBeginInfo */
-       memset(&rp_begin_info, 0, sizeof rp_begin_info);
-       rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
-       rp_begin_info.renderPass = renderer->renderpass;
-       rp_begin_info.framebuffer = renderer->fb;
-       rp_begin_info.renderArea = rp_area;
-       rp_begin_info.clearValueCount = 2;
-       rp_begin_info.pClearValues = clear_values;
-
-       /* VkSubmitInfo */
-       stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
-
-       memset(&submit_info, 0, sizeof submit_info);
-       submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-       submit_info.commandBufferCount = 1;
-       submit_info.pCommandBuffers = &ctx->cmd_buf;
+    VkCommandBufferBeginInfo cmd_begin_info;
+    VkRenderPassBeginInfo rp_begin_info;
+    VkRect2D rp_area;
+    VkClearValue clear_values[2];
+    VkSubmitInfo submit_info;
+    VkPipelineStageFlagBits stage_flags;
+    VkImageSubresourceRange img_range;
+
+    assert(vk_fb_color_count == 4);
+
+    /* VkCommandBufferBeginInfo */
+    memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
+    cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+    /* VkRect2D render area */
+    memset(&rp_area, 0, sizeof rp_area);
+    rp_area.extent.width = (uint32_t)w;
+    rp_area.extent.height = (uint32_t)h;
+    rp_area.offset.x = x;
+    rp_area.offset.y = y;
+
+    /* VkClearValue */
+    memset(&clear_values[0], 0, sizeof clear_values[0]);
+    clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */
+    clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */
+    clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */
+    clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */
+
+    memset(&clear_values[1], 0, sizeof clear_values[1]);
+    clear_values[1].depthStencil.depth = 1.0;
+    clear_values[1].depthStencil.stencil = 0;
+
+    /* VkRenderPassBeginInfo */
+    memset(&rp_begin_info, 0, sizeof rp_begin_info);
+    rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+    rp_begin_info.renderPass = renderer->renderpass;
+    rp_begin_info.framebuffer = renderer->fb;
+    rp_begin_info.renderArea = rp_area;
+    rp_begin_info.clearValueCount = 2;
+    rp_begin_info.pClearValues = clear_values;
+
+    /* VkSubmitInfo */
+    stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+
+    memset(&submit_info, 0, sizeof submit_info);
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &ctx->cmd_buf;
 
     /* FIXME */
 
     /* FIXME */
-       if (has_wait) {
-               submit_info.pWaitDstStageMask = &stage_flags;
-               submit_info.waitSemaphoreCount = 1;
-               submit_info.pWaitSemaphores = &semaphores->frame_done;
-       }
-
-       if (has_signal) {
-               submit_info.signalSemaphoreCount = 1;
-               submit_info.pSignalSemaphores = &semaphores->frame_ready;
-       }
-
-       img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-       img_range.baseMipLevel = 0;
-       img_range.levelCount = 1;
-       img_range.baseArrayLayer = 0;
-       img_range.layerCount = 1;
-
-       vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
-       vk_transition_image_layout(&attachments[0],
-                                  ctx->cmd_buf,
-                                  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-                                  VK_IMAGE_LAYOUT_GENERAL,
-                                  VK_QUEUE_FAMILY_EXTERNAL,
-                                  ctx->qfam_idx);
-       vkCmdClearColorImage(ctx->cmd_buf,
-                            attachments[0].obj.img,
-                            VK_IMAGE_LAYOUT_GENERAL,
-                            &clear_values[0].color,
-                            1,
-                            &img_range);
-
-       vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
-
-       viewport.x = x;
-       viewport.y = y;
-       viewport.width = w;
-       viewport.height = h;
-
-       scissor.offset.x = x;
-       scissor.offset.y = y;
-       scissor.extent.width = w;
-       scissor.extent.height = h;
-
-       vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
-       vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
-
-       vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
-
-       vkCmdEndRenderPass(ctx->cmd_buf);
-
-       if (attachments) {
-               VkImageMemoryBarrier *barriers =
-                       calloc(n_attachments, sizeof(VkImageMemoryBarrier));
-               VkImageMemoryBarrier *barrier = barriers;
-
-               for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
-                       struct vk_image_att *att = &attachments[n];
-
-                       /* Insert barrier to mark ownership transfer. */
-                       barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-
-                       bool is_depth =
-                               get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
-
-                       barrier->oldLayout = is_depth ?
-                               VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
-                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
-                       barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
-                       barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
-                       barrier->dstAccessMask = get_access_mask(barrier->newLayout);
-                       barrier->srcQueueFamilyIndex = ctx->qfam_idx;
-                       barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
-                       barrier->image = att->obj.img;
-                       barrier->subresourceRange.aspectMask = is_depth ?
-                               VK_IMAGE_ASPECT_DEPTH_BIT :
-                               VK_IMAGE_ASPECT_COLOR_BIT;
-                       barrier->subresourceRange.baseMipLevel = 0;
-                       barrier->subresourceRange.levelCount = 1;
-                       barrier->subresourceRange.baseArrayLayer = 0;
-                       barrier->subresourceRange.layerCount = 1;
-               }
-
-               vkCmdPipelineBarrier(ctx->cmd_buf,
-                                    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
-                                    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
-                                    0,
-                                    0, NULL,
-                                    0, NULL,
-                                    n_attachments, barriers);
-               free(barriers);
-       }
-
-       vkEndCommandBuffer(ctx->cmd_buf);
-
-       if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to submit queue.\n");
-       }
-
-       if (!semaphores && !has_wait && !has_signal)
-               vkQueueWaitIdle(ctx->queue);
+    if (has_wait) {
+        submit_info.pWaitDstStageMask = &stage_flags;
+        submit_info.waitSemaphoreCount = 1;
+        submit_info.pWaitSemaphores = &semaphores->frame_done;
+    }
+
+    if (has_signal) {
+        submit_info.signalSemaphoreCount = 1;
+        submit_info.pSignalSemaphores = &semaphores->frame_ready;
+    }
+
+    img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    img_range.baseMipLevel = 0;
+    img_range.levelCount = 1;
+    img_range.baseArrayLayer = 0;
+    img_range.layerCount = 1;
+
+    vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+    vk_transition_image_layout(&attachments[0],
+                               ctx->cmd_buf,
+                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                               VK_IMAGE_LAYOUT_GENERAL,
+                               VK_QUEUE_FAMILY_EXTERNAL,
+                               ctx->qfam_idx);
+    vkCmdClearColorImage(ctx->cmd_buf,
+                         attachments[0].obj.img,
+                         VK_IMAGE_LAYOUT_GENERAL,
+                         &clear_values[0].color,
+                         1,
+                         &img_range);
+
+    vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
+
+    viewport.x = x;
+    viewport.y = y;
+    viewport.width = w;
+    viewport.height = h;
+
+    scissor.offset.x = x;
+    scissor.offset.y = y;
+    scissor.extent.width = w;
+    scissor.extent.height = h;
+
+    vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport);
+    vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor);
+
+    vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline);
+
+    vkCmdEndRenderPass(ctx->cmd_buf);
+
+    if (attachments) {
+        VkImageMemoryBarrier *barriers =
+            calloc(n_attachments, sizeof(VkImageMemoryBarrier));
+        VkImageMemoryBarrier *barrier = barriers;
+
+        for (uint32_t n = 0; n < n_attachments; n++, barrier++) {
+            struct vk_image_att *att = &attachments[n];
+
+            /* Insert barrier to mark ownership transfer. */
+            barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+
+            bool is_depth =
+                get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE;
+
+            barrier->oldLayout = is_depth ?
+                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL :
+                VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
+            barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL;
+            barrier->srcAccessMask = get_access_mask(barrier->oldLayout);
+            barrier->dstAccessMask = get_access_mask(barrier->newLayout);
+            barrier->srcQueueFamilyIndex = ctx->qfam_idx;
+            barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
+            barrier->image = att->obj.img;
+            barrier->subresourceRange.aspectMask = is_depth ?
+                VK_IMAGE_ASPECT_DEPTH_BIT :
+                VK_IMAGE_ASPECT_COLOR_BIT;
+            barrier->subresourceRange.baseMipLevel = 0;
+            barrier->subresourceRange.levelCount = 1;
+            barrier->subresourceRange.baseArrayLayer = 0;
+            barrier->subresourceRange.layerCount = 1;
+        }
+
+        vkCmdPipelineBarrier(ctx->cmd_buf,
+                     VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
+                     VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+                     0,
+                     0, NULL,
+                     0, NULL,
+                     n_attachments, barriers);
+        free(barriers);
+    }
+
+    vkEndCommandBuffer(ctx->cmd_buf);
+
+    if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to submit queue.\n");
+    }
+
+    if (!semaphores && !has_wait && !has_signal)
+        vkQueueWaitIdle(ctx->queue);
 }
 
 bool
 vk_create_swapchain(struct vk_ctx *ctx,
                     int width, int height,
 }
 
 bool
 vk_create_swapchain(struct vk_ctx *ctx,
                     int width, int height,
-                    int num_qfam,
+                    bool has_vsync,
+                    VkSurfaceKHR surf,
+                    struct vk_swapchain *old_swapchain,
                     struct vk_swapchain *swapchain)
 {
                     struct vk_swapchain *swapchain)
 {
+    VkSurfaceCapabilitiesKHR surf_cap;
     VkSwapchainCreateInfoKHR s_info;
     VkExtent2D extent;
     VkSwapchainCreateInfoKHR s_info;
     VkExtent2D extent;
+    VkImageSubresourceRange sr;
+    VkImage *s_images;
+    int i;
 
 
-    extent.width = width;
-    extent.height = height;
+    if (!sc_validate_surface(ctx, surf)) {
+        fprintf(stderr, "Failed to validate surface!\n");
+        return false;
+    }
 
 
-    memset(&s_info, 0, sizeof s_info);
+    /* get pdevice capabilities
+     * will need that to determine the swapchain number of images
+     */
+    if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to query surface capabilities.\n");
+        return false;
+    }
+
+    /* allocate and init an empty struct vk_swapchain */
+    swapchain = malloc(sizeof *swapchain);
+    memset(swapchain, 0, sizeof *swapchain);
+
+    swapchain->surface = surf;
 
 
+    memset(&s_info, 0, sizeof s_info);
     s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
     s_info.flags = 0;
     s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
     s_info.flags = 0;
-    s_info.surface = swapchain->surface;
-    s_info.minImageCount = 2;
-    s_info.imageFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
-    s_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+    /* surface format */
+    if (!sc_select_format(ctx, surf, &s_info)) {
+        fprintf(stderr, "Failed to determine the surface format.\n");
+        return false;
+    }
+    s_info.surface = surf;
+
+    /* number of images */
+    s_info.minImageCount = surf_cap.minImageCount;
+    /* swapchain images dims */
+    {
+        extent.width = width;
+        extent.height = height;
+    }
+    if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) {
+        s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+    }
     s_info.imageExtent = extent;
     s_info.imageArrayLayers = 1;
     s_info.imageExtent = extent;
     s_info.imageArrayLayers = 1;
-    s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
-                        VK_IMAGE_USAGE_SAMPLED_BIT |
-                        VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
-                        VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-
-    s_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
-    s_info.queueFamilyIndexCount = num_qfam; /* how many queue families */
-
-    s_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
+    /* enable color attachment bit and transfer src and transfer dst bits
+     * too if they are supported */
+    {
+        s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+        if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)
+            s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+        if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)
+            s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+    }
+    s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+    s_info.queueFamilyIndexCount = ctx->qfam_idx;
+
+    /* we might want to use this function when we recreate the swapchain too */
+    s_info.preTransform = surf_cap.supportedTransforms &
+                            VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ?
+                            VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
+                            surf_cap.currentTransform;
+
+    /* we could also write a sc_select_supported_composite_alpha
+     * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally
+     * supported */
     s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
     s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-    s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
     s_info.clipped = VK_TRUE;
     s_info.clipped = VK_TRUE;
-    s_info.oldSwapchain = VK_NULL_HANDLE;
+    s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0;
 
     if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
                              &swapchain->swapchain) != VK_SUCCESS) {
 
     if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0,
                              &swapchain->swapchain) != VK_SUCCESS) {
@@ -1792,6 +1977,55 @@ vk_create_swapchain(struct vk_ctx *ctx,
         return false;
     }
 
         return false;
     }
 
+    /* if an existing swapchain is recreated we need to destroy
+     * the old swapchain and clean up the images */
+    if (old_swapchain) {
+        for (i = 0; i < old_swapchain->num_images; i++) {
+            vkDestroyImageView(ctx->dev, old_swapchain->images[i].image_view, 0);
+        }
+        vk_destroy_swapchain(ctx, old_swapchain);
+    }
+
+    /* get the number of swapchain images and the swapchain images
+     * and store the new swapchain images
+     */
+    vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0);
+    printf("number of swapchain images: %d\n", swapchain->num_images);
+
+    /* create images */
+    s_images = malloc(swapchain->num_images * sizeof(VkImage));
+    vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images);
+
+    swapchain->image_fmt = s_info.imageFormat;
+    swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_swap_image_obj));
+
+    memset(&sr, 0, sizeof sr);
+    sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    sr.levelCount = 1;
+    sr.layerCount = 1;
+
+    for (i = 0; i < swapchain->num_images; i++) {
+        swapchain->images[i].image = s_images[i];
+        if (!(create_image_view(ctx,
+                                swapchain->images[i].image,
+                                VK_IMAGE_VIEW_TYPE_2D,
+                                swapchain->image_fmt,
+                                sr,
+                                true,
+                                &swapchain->images[i].image_view))) {
+            fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i);
+            break;
+        }
+        if (i < swapchain->num_images - 1) {
+            int j;
+            for (j = 0; j < i; j++) {
+                vkDestroyImageView(ctx->dev, swapchain->images[i].image_view, 0);
+            }
+            return false;
+        }
+    }
+
+    free(s_images);
     return true;
 }
 
     return true;
 }
 
@@ -1801,6 +2035,9 @@ vk_destroy_swapchain(struct vk_ctx *ctx,
 {
     vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
     vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
 {
     vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0);
     vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0);
+
+    free(swapchain);
+    swapchain = 0;
 }
 
 void
 }
 
 void
@@ -1809,151 +2046,154 @@ vk_copy_image_to_buffer(struct vk_ctx *ctx,
                         struct vk_buf *dst_bo,
                         float w, float h)
 {
                         struct vk_buf *dst_bo,
                         float w, float h)
 {
-       VkCommandBufferBeginInfo cmd_begin_info;
-       VkSubmitInfo submit_info;
-       VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
-
-       /* VkCommandBufferBeginInfo */
-       memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
-       cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
-       cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
-
-       memset(&submit_info, 0, sizeof submit_info);
-       submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
-       submit_info.commandBufferCount = 1;
-       submit_info.pCommandBuffers = &ctx->cmd_buf;
-
-       vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
-       if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
-               vk_transition_image_layout(src_img,
+    VkCommandBufferBeginInfo cmd_begin_info;
+    VkSubmitInfo submit_info;
+    VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format);
+
+    /* VkCommandBufferBeginInfo */
+    memset(&cmd_begin_info, 0, sizeof cmd_begin_info);
+    cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
+    cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
+
+    memset(&submit_info, 0, sizeof submit_info);
+    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+    submit_info.commandBufferCount = 1;
+    submit_info.pCommandBuffers = &ctx->cmd_buf;
+
+    vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info);
+    if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) {
+        vk_transition_image_layout(src_img,
                                    ctx->cmd_buf,
                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                    VK_QUEUE_FAMILY_EXTERNAL,
                                    ctx->qfam_idx);
 
                                    ctx->cmd_buf,
                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                    VK_QUEUE_FAMILY_EXTERNAL,
                                    ctx->qfam_idx);
 
-               /* copy image to buf */
-               VkBufferImageCopy copy_region = {
-                       .bufferOffset = 0,
-                       .bufferRowLength = w,
-                       .bufferImageHeight = h,
-                       .imageSubresource = {
-                               .aspectMask = aspect_mask ? aspect_mask
+        /* copy image to buf */
+        VkBufferImageCopy copy_region = {
+            .bufferOffset = 0,
+            .bufferRowLength = w,
+            .bufferImageHeight = h,
+            .imageSubresource = {
+                .aspectMask = aspect_mask ? aspect_mask
                               : VK_IMAGE_ASPECT_COLOR_BIT,
                               : VK_IMAGE_ASPECT_COLOR_BIT,
-                               .mipLevel = 0,
-                               .baseArrayLayer = 0,
-                               .layerCount = 1,
-                       },
-                       .imageOffset = { 0, 0, 0 },
-                       .imageExtent = { w, h, 1 }
+                .mipLevel = 0,
+                .baseArrayLayer = 0,
+                .layerCount = 1,
+            },
+            .imageOffset = { 0, 0, 0 },
+            .imageExtent = { w, h, 1 }
                 };
 
                 };
 
-               vkCmdCopyImageToBuffer(ctx->cmd_buf,
+        vkCmdCopyImageToBuffer(ctx->cmd_buf,
                                src_img->obj.img,
                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                dst_bo->buf, 1, &copy_region);
 
                                src_img->obj.img,
                                VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                dst_bo->buf, 1, &copy_region);
 
-               vk_transition_image_layout(src_img,
+        vk_transition_image_layout(src_img,
                                    ctx->cmd_buf,
                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                                    VK_QUEUE_FAMILY_EXTERNAL,
                                    ctx->qfam_idx);
 
                                    ctx->cmd_buf,
                                    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                                    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
                                    VK_QUEUE_FAMILY_EXTERNAL,
                                    ctx->qfam_idx);
 
-               VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
-                       .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
-                       .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
-                       .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
-                       .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
-                       .dstQueueFamilyIndex = ctx->qfam_idx,
-                       .buffer = dst_bo->buf,
-                       .offset = 0,
-                       .size = VK_WHOLE_SIZE
-               };
-
-               vkCmdPipelineBarrier(ctx->cmd_buf,
+        VkBufferMemoryBarrier write_finish_buffer_memory_barrier = {
+            .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
+            .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
+            .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
+            .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
+            .dstQueueFamilyIndex = ctx->qfam_idx,
+            .buffer = dst_bo->buf,
+            .offset = 0,
+            .size = VK_WHOLE_SIZE
+        };
+
+        vkCmdPipelineBarrier(ctx->cmd_buf,
                              VK_PIPELINE_STAGE_TRANSFER_BIT,
                              VK_PIPELINE_STAGE_HOST_BIT,
                              (VkDependencyFlags) 0, 0, NULL,
                              1, &write_finish_buffer_memory_barrier,
                              0, NULL);
     }
                              VK_PIPELINE_STAGE_TRANSFER_BIT,
                              VK_PIPELINE_STAGE_HOST_BIT,
                              (VkDependencyFlags) 0, 0, NULL,
                              1, &write_finish_buffer_memory_barrier,
                              0, NULL);
     }
-       vkEndCommandBuffer(ctx->cmd_buf);
+    vkEndCommandBuffer(ctx->cmd_buf);
 
 
-       if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to submit queue.\n");
-       }
-       vkQueueWaitIdle(ctx->queue);
+    if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to submit queue.\n");
+    }
+    vkQueueWaitIdle(ctx->queue);
 }
 
 // FIXME: external
 bool
 vk_create_semaphores(struct vk_ctx *ctx,
 }
 
 // FIXME: external
 bool
 vk_create_semaphores(struct vk_ctx *ctx,
-                                        struct vk_semaphores *semaphores)
+                     bool is_external,
+                     struct vk_semaphores *semaphores)
 {
 {
-       VkSemaphoreCreateInfo sema_info;
-       VkExportSemaphoreCreateInfo exp_sema_info;
-
-       /* VkExportSemaphoreCreateInfo */
-       memset(&exp_sema_info, 0, sizeof exp_sema_info);
-       exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
-       exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
-
-       /* VkSemaphoreCreateInfo */
-       memset(&sema_info, 0, sizeof sema_info);
-       sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
-       sema_info.pNext = &exp_sema_info;
-
-       if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create semaphore frame_ready.\n");
-               return false;
-       }
-
-       if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
-               fprintf(stderr, "Failed to create semaphore frame_done.\n");
-               return false;
-       }
-
-       return true;
+    VkSemaphoreCreateInfo sema_info;
+    VkExportSemaphoreCreateInfo exp_sema_info;
+
+    if (is_external) {
+        /* VkExportSemaphoreCreateInfo */
+        memset(&exp_sema_info, 0, sizeof exp_sema_info);
+        exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+        exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
+    }
+
+    /* VkSemaphoreCreateInfo */
+    memset(&sema_info, 0, sizeof sema_info);
+    sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+    sema_info.pNext = is_external ? &exp_sema_info : 0;
+
+    if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create semaphore frame_ready.\n");
+        return false;
+    }
+
+    if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) {
+        fprintf(stderr, "Failed to create semaphore frame_done.\n");
+        return false;
+    }
+
+    return true;
 }
 
 void
 vk_destroy_semaphores(struct vk_ctx *ctx,
 }
 
 void
 vk_destroy_semaphores(struct vk_ctx *ctx,
-                                         struct vk_semaphores *semaphores)
+                      struct vk_semaphores *semaphores)
 {
 {
-       if (semaphores->frame_ready)
-               vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
-       if (semaphores->frame_done)
-               vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
+    if (semaphores->frame_ready)
+        vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0);
+    if (semaphores->frame_done)
+        vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0);
 }
 
 void
 vk_transition_image_layout(struct vk_image_att *img_att,
 }
 
 void
 vk_transition_image_layout(struct vk_image_att *img_att,
-                          VkCommandBuffer cmd_buf,
-                          VkImageLayout old_layout,
-                          VkImageLayout new_layout,
-                          uint32_t src_queue_fam_idx,
-                          uint32_t dst_queue_fam_idx)
+               VkCommandBuffer cmd_buf,
+               VkImageLayout old_layout,
+               VkImageLayout new_layout,
+               uint32_t src_queue_fam_idx,
+               uint32_t dst_queue_fam_idx)
 {
 {
-       VkImageMemoryBarrier barrier;
-       struct vk_image_props props = img_att->props;
-       VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
-
-       memset(&barrier, 0, sizeof barrier);
-       barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
-       barrier.srcAccessMask = get_access_mask(old_layout);
-       barrier.dstAccessMask = get_access_mask(new_layout);
-       barrier.oldLayout = old_layout;
-       barrier.newLayout = new_layout;
-       barrier.srcQueueFamilyIndex = src_queue_fam_idx;
-       barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
-       barrier.image = img_att->obj.img;
-       barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
+    VkImageMemoryBarrier barrier;
+    struct vk_image_props props = img_att->props;
+    VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format);
+
+    memset(&barrier, 0, sizeof barrier);
+    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
+    barrier.srcAccessMask = get_access_mask(old_layout);
+    barrier.dstAccessMask = get_access_mask(new_layout);
+    barrier.oldLayout = old_layout;
+    barrier.newLayout = new_layout;
+    barrier.srcQueueFamilyIndex = src_queue_fam_idx;
+    barrier.dstQueueFamilyIndex = dst_queue_fam_idx;
+    barrier.image = img_att->obj.img;
+    barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask :
                                           VK_IMAGE_ASPECT_COLOR_BIT;
                                           VK_IMAGE_ASPECT_COLOR_BIT;
-       barrier.subresourceRange.levelCount = 1;
-       barrier.subresourceRange.layerCount = 1;
+    barrier.subresourceRange.levelCount = 1;
+    barrier.subresourceRange.layerCount = 1;
 
 
-       vkCmdPipelineBarrier(cmd_buf,
+    vkCmdPipelineBarrier(cmd_buf,
                          get_pipeline_stage_flags(old_layout),
                          get_pipeline_stage_flags(new_layout),
                          0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);
                          get_pipeline_stage_flags(old_layout),
                          get_pipeline_stage_flags(new_layout),
                          0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier);
index 140f525..ff5c025 100644 (file)
--- a/src/vk.h
+++ b/src/vk.h
@@ -7,18 +7,24 @@
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 struct vk_ctx
 {
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 struct vk_ctx
 {
-       VkInstance inst;
-       VkPhysicalDevice pdev;
-       VkDevice dev;
+    VkInstance inst;
+    VkPhysicalDevice pdev;
+    VkDevice dev;
 
 
-       VkCommandPool cmd_pool;
-       VkCommandBuffer cmd_buf;
+    VkCommandPool cmd_pool;
+    VkCommandBuffer cmd_buf;
 
 
-       VkQueue queue;
-       int qfam_idx;
+    VkQueue queue;
+    int qfam_idx;
 
 
-       uint8_t deviceUUID[VK_UUID_SIZE];
-       uint8_t driverUUID[VK_UUID_SIZE];
+    uint8_t deviceUUID[VK_UUID_SIZE];
+    uint8_t driverUUID[VK_UUID_SIZE];
+};
+
+struct vk_swap_image_obj
+{
+    VkImage image;
+    VkImageView image_view;
 };
 
 struct vk_swapchain
 };
 
 struct vk_swapchain
@@ -26,83 +32,90 @@ struct vk_swapchain
     VkSwapchainKHR swapchain;
     VkSurfaceKHR surface;
     VkSurfaceFormatKHR surf_fmt;
     VkSwapchainKHR swapchain;
     VkSurfaceKHR surface;
     VkSurfaceFormatKHR surf_fmt;
-    uint32_t num_images;
+
+    /* image properties */
+    VkFormat image_fmt;
     VkExtent2D extent2d;
     VkExtent2D extent2d;
+
+    uint32_t num_images;
+    struct vk_swap_image_obj *images;
 };
 
 struct vk_image_props
 {
 };
 
 struct vk_image_props
 {
-       uint32_t w;
-       uint32_t h;
-       uint32_t depth;
+    uint32_t w;
+    uint32_t h;
+    uint32_t depth;
 
 
-       uint32_t num_samples;
-       uint32_t num_levels;
-       uint32_t num_layers;
+    uint32_t num_samples;
+    uint32_t num_levels;
+    uint32_t num_layers;
 
 
-       VkFormat format;
-       VkImageUsageFlagBits usage;
-       VkImageTiling tiling;
+    VkFormat format;
+    VkImageUsageFlagBits usage;
+    VkImageTiling tiling;
 
 
-       VkImageLayout in_layout;
-       VkImageLayout end_layout;
+    VkImageLayout in_layout;
+    VkImageLayout end_layout;
 
     bool need_export;
 };
 
 struct vk_mem_obj {
 
     bool need_export;
 };
 
 struct vk_mem_obj {
-       VkDeviceMemory mem;
-       VkDeviceSize mem_sz;
-       bool dedicated;
+    VkDeviceMemory mem;
+    VkDeviceSize mem_sz;
+
+    bool dedicated;
 };
 
 struct vk_image_obj {
 };
 
 struct vk_image_obj {
-       VkImage img;
+    VkImage img;
     VkImageView img_view;
     VkImageView img_view;
-       struct vk_mem_obj mobj;
+
+    struct vk_mem_obj mobj;
 };
 
 struct vk_image_att {
 };
 
 struct vk_image_att {
-       struct vk_image_obj obj;
-       struct vk_image_props props;
+    struct vk_image_obj obj;
+    struct vk_image_props props;
 };
 
 struct vk_vertex_info
 {
 };
 
 struct vk_vertex_info
 {
-       int num_verts;
-       int num_components;
+    int num_verts;
+    int num_components;
 
 
-       VkPrimitiveTopology topology;
+    VkPrimitiveTopology topology;
 };
 
 struct vk_buf
 {
 };
 
 struct vk_buf
 {
-       VkBuffer buf;
-       struct vk_mem_obj mobj;
+    VkBuffer buf;
+    struct vk_mem_obj mobj;
 };
 
 struct vk_renderer
 {
 };
 
 struct vk_renderer
 {
-       VkPipeline pipeline;
-       VkPipelineLayout pipeline_layout;
-       VkRenderPass renderpass;
-       VkShaderModule vs;
-       VkShaderModule fs;
-       VkFramebuffer fb;
-
-       struct vk_vertex_info vertex_info;
+    VkPipeline pipeline;
+    VkPipelineLayout pipeline_layout;
+    VkRenderPass renderpass;
+    VkShaderModule vs;
+    VkShaderModule fs;
+    VkFramebuffer fb;
+
+    struct vk_vertex_info vertex_info;
 };
 
 struct vk_dims
 {
 };
 
 struct vk_dims
 {
-       float w;
-       float h;
+    float w;
+    float h;
 };
 
 struct vk_semaphores
 {
 };
 
 struct vk_semaphores
 {
-       VkSemaphore frame_ready;
-       VkSemaphore frame_done;
+    VkSemaphore frame_ready;
+    VkSemaphore frame_done;
 };
 
 /* context */
 };
 
 /* context */
@@ -115,92 +128,99 @@ void vk_cleanup_ctx(struct vk_ctx *ctx);
 
 bool
 vk_create_image(struct vk_ctx *ctx,
 
 bool
 vk_create_image(struct vk_ctx *ctx,
-                               struct vk_image_props *props,
-                               struct vk_image_obj *img_obj);
+                struct vk_image_props *props,
+                struct vk_image_obj *img_obj);
 void
 vk_destroy_image(struct vk_ctx *ctx,
 void
 vk_destroy_image(struct vk_ctx *ctx,
-                                struct vk_image_obj *img_obj);
-
+                 struct vk_image_obj *img_obj);
 
 bool
 vk_fill_ext_image_props(struct vk_ctx *ctx,
 
 bool
 vk_fill_ext_image_props(struct vk_ctx *ctx,
-                                               uint32_t w, uint32_t h,
-                                               uint32_t depth,
-                                               uint32_t num_samples,
-                                               uint32_t num_levels,
-                                               uint32_t num_layers,
-                                               VkFormat format,
-                                               VkImageTiling tiling,
-                                               VkImageLayout in_layout,
-                                               VkImageLayout end_layout,
+                        uint32_t w, uint32_t h,
+                        uint32_t depth,
+                        uint32_t num_samples,
+                        uint32_t num_levels,
+                        uint32_t num_layers,
+                        VkFormat format,
+                        VkImageTiling tiling,
+                        VkImageLayout in_layout,
+                        VkImageLayout end_layout,
                         bool need_export,
                         bool need_export,
-                                               struct vk_image_props *props);
+                        struct vk_image_props *props);
+
+bool
+vk_create_attachment_from_swapchain_image(struct vk_ctx *ctx,
+                                          VkImage *swapchain_img,
+                                          VkImageView *swapchain_view,
+                                          struct vk_image_props *swapchain_props,
+                                          struct vk_image_att *color_att);
 
 /* buffers */
 
 bool
 vk_create_buffer(struct vk_ctx *ctx,
                  bool is_external,
 
 /* buffers */
 
 bool
 vk_create_buffer(struct vk_ctx *ctx,
                  bool is_external,
-                                uint32_t sz,
-                                VkBufferUsageFlagBits usage,
-                                void *pnext,
-                                struct vk_buf *bo);
+                 uint32_t sz,
+                 VkBufferUsageFlagBits usage,
+                 void *pnext,
+                 struct vk_buf *bo);
 void
 vk_destroy_buffer(struct vk_ctx *ctx,
 void
 vk_destroy_buffer(struct vk_ctx *ctx,
-                                 struct vk_buf *bo);
+                  struct vk_buf *bo);
 bool
 vk_update_buffer_data(struct vk_ctx *ctx,
 bool
 vk_update_buffer_data(struct vk_ctx *ctx,
-                                         void *data,
-                                         uint32_t data_sz,
-                                         struct vk_buf *bo);
+                      void *data,
+                      uint32_t data_sz,
+                      struct vk_buf *bo);
 
 bool
 vk_create_ext_buffer(struct vk_ctx *ctx,
 
 bool
 vk_create_ext_buffer(struct vk_ctx *ctx,
-                    uint32_t sz,
-                    VkBufferUsageFlagBits usage,
-                    struct vk_buf *bo);
+                     uint32_t sz,
+                     VkBufferUsageFlagBits usage,
+                     struct vk_buf *bo);
 
 
 /* semaphores */
 
 bool
 vk_create_semaphores(struct vk_ctx *ctx,
 
 
 /* semaphores */
 
 bool
 vk_create_semaphores(struct vk_ctx *ctx,
-                                        struct vk_semaphores *semaphores);
+                     bool is_external,
+                     struct vk_semaphores *semaphores);
 void
 vk_destroy_semaphores(struct vk_ctx *ctx,
 void
 vk_destroy_semaphores(struct vk_ctx *ctx,
-                                         struct vk_semaphores *semaphores);
+                      struct vk_semaphores *semaphores);
 
 /* renderer */
 
 bool
 vk_create_renderer(struct vk_ctx *ctx,
 
 /* renderer */
 
 bool
 vk_create_renderer(struct vk_ctx *ctx,
-                                  const char *vs_src,
-                                  unsigned int vs_size,
-                                  const char *fs_src,
-                                  unsigned int fs_size,
-                                  bool enable_depth,
-                                  bool enable_stencil,
-                                  struct vk_image_att *color_att,
-                                  struct vk_image_att *depth_att,
-                                  struct vk_vertex_info *vert_info,
-                                  struct vk_renderer *renderer);
+                   const char *vs_src,
+                   unsigned int vs_size,
+                   const char *fs_src,
+                   unsigned int fs_size,
+                   bool enable_depth,
+                   bool enable_stencil,
+                   struct vk_image_att *color_att,
+                   struct vk_image_att *depth_att,
+                   struct vk_vertex_info *vert_info,
+                   struct vk_renderer *renderer);
 
 void
 vk_destroy_renderer(struct vk_ctx *ctx,
 
 void
 vk_destroy_renderer(struct vk_ctx *ctx,
-                                       struct vk_renderer *pipeline);
+                    struct vk_renderer *pipeline);
 
 /* draw */
 
 void
 vk_draw(struct vk_ctx *ctx,
 
 /* draw */
 
 void
 vk_draw(struct vk_ctx *ctx,
-               struct vk_buf *vbo,
-               struct vk_renderer *renderer,
-               float *vk_fb_color,
-               uint32_t vk_fb_color_count,
-               struct vk_semaphores *semaphores,
-               struct vk_image_att *attachments,
-               uint32_t n_attachments,
-               float x, float y, float w, float h);
+        struct vk_buf *vbo,
+        struct vk_renderer *renderer,
+        float *vk_fb_color,
+        uint32_t vk_fb_color_count,
+        struct vk_semaphores *semaphores,
+        struct vk_image_att *attachments,
+        uint32_t n_attachments,
+        float x, float y, float w, float h);
 
 void
 vk_clear_color(struct vk_ctx *ctx,
 
 void
 vk_clear_color(struct vk_ctx *ctx,
@@ -219,7 +239,9 @@ vk_clear_color(struct vk_ctx *ctx,
 bool
 vk_create_swapchain(struct vk_ctx *ctx,
                     int width, int height,
 bool
 vk_create_swapchain(struct vk_ctx *ctx,
                     int width, int height,
-                    int num_qfam,
+                    bool vsync,
+                    VkSurfaceKHR surf,
+                    struct vk_swapchain *old_swapchain,
                     struct vk_swapchain *swapchain);
 void
 vk_destroy_swapchain(struct vk_ctx *ctx,
                     struct vk_swapchain *swapchain);
 void
 vk_destroy_swapchain(struct vk_ctx *ctx,
@@ -229,16 +251,16 @@ vk_destroy_swapchain(struct vk_ctx *ctx,
 
 void
 vk_copy_image_to_buffer(struct vk_ctx *ctx,
 
 void
 vk_copy_image_to_buffer(struct vk_ctx *ctx,
-                                               struct vk_image_att *src_img,
-                                               struct vk_buf *dst_bo,
-                                               float w, float h);
+                        struct vk_image_att *src_img,
+                        struct vk_buf *dst_bo,
+                        float w, float h);
 
 void
 vk_transition_image_layout(struct vk_image_att *img_att,
 
 void
 vk_transition_image_layout(struct vk_image_att *img_att,
-                          VkCommandBuffer cmd_buf,
-                          VkImageLayout old_layout,
-                          VkImageLayout new_layout,
-                          uint32_t src_queue_family_index,
-                          uint32_t dst_queue_family_index);
+                           VkCommandBuffer cmd_buf,
+                           VkImageLayout old_layout,
+                           VkImageLayout new_layout,
+                           uint32_t src_queue_family_index,
+                           uint32_t dst_queue_family_index);
 
 #endif /* VK_H */
 
 #endif /* VK_H */