Revert "demos: Add msaa-tri.c for msaa rendering example modified from tri.c"
authorCourtney Goeltzenleuchter <courtney@LunarG.com>
Wed, 13 May 2015 22:25:37 +0000 (16:25 -0600)
committerCourtney Goeltzenleuchter <courtney@LunarG.com>
Wed, 13 May 2015 22:25:37 +0000 (16:25 -0600)
This reverts commit 0e83c4d651d5602a35b5c54eb59f2543310b5f31.

demos/msaa-tri.c [deleted file]

diff --git a/demos/msaa-tri.c b/demos/msaa-tri.c
deleted file mode 100644 (file)
index a8e10c9..0000000
+++ /dev/null
@@ -1,1948 +0,0 @@
-/*
- * Vulkan
- *
- * Copyright (C) 2014-2015 LunarG, Inc.
- * Copyright (c) 2015 Samsung Electronics, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-/*
- * Draw a textured triangle with depth testing.  This is written against Intel
- * ICD.  It does not do state transition nor object memory binding like it
- * should.  It also does no error checking.
- */
-/* Modified to use MSAA
- *
- * Changes to tri.c
- * (1) No color attachment views created for swap chain images
- * (2) create an offscreen MSAA (samples = 4) image as color attachment
- * (3) create msaa depth/stencil image
- * (4) during draw time, attach msaa image and msaa depth/stencil buffer
- *     as color and depth/stencil attachment
- * (5) once drawn to msaa color image, resolve it to swap chain image
- */
-/* Contributed by Henry Song (henry.song@samsung.com) */
-
-#ifndef VK_PROTOTYPES
-#define VK_PROTOTYPES
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdbool.h>
-#include <assert.h>
-
-#ifdef _WIN32
-#pragma comment(linker, "/subsystem:windows")
-#include <windows.h>
-#include <fcntl.h>
-#include <io.h>
-#define APP_NAME_STR_LEN 80
-#else  // _WIN32
-#include <xcb/xcb.h>
-#endif // _WIN32
-
-#include <Vk/vulkan.h>
-#include <Vk/vkDbg.h>
-#include <Vk/vk_wsi_lunarg.h>
-
-#include "icd-spv.h"
-
-#define DEMO_BUFFER_COUNT 2
-#define DEMO_TEXTURE_COUNT 1
-#define VERTEX_BUFFER_BIND_ID 0
-#define APP_SHORT_NAME "tri"
-#define APP_LONG_NAME "The Vulkan Triangle Demo Program"
-
-#ifdef _WIN32
-bool consoleCreated = false;
-
-#define WAIT_FOR_CONSOLE_DESTROY \
-    do { \
-        if (consoleCreated) \
-            Sleep(INFINITE); \
-    } while (0)
-
-#define ERR_EXIT(err_msg, err_class)                                    \
-    do {                                                                \
-        MessageBox(NULL, err_msg, err_class, MB_OK);                    \
-        if (consoleCreated) {                                           \
-            printf("\nPlease close this window when you are finished "      \
-                   "looking at the console output.\n");                 \
-            fflush(stdout);                                             \
-        }                                                               \
-        WAIT_FOR_CONSOLE_DESTROY;                                       \
-        exit(1);                                                        \
-   } while (0)
-
-// NOTE: If the following values (copied from "loader_platform.h") change, they
-// need to change here as well:
-#define LAYER_NAMES_ENV "VK_LAYER_NAMES"
-#define LAYER_NAMES_REGISTRY_VALUE "VK_LAYER_NAMES"
-#else  // _WIN32
-    #define WAIT_FOR_CONSOLE_DESTROY
-
-#define ERR_EXIT(err_msg, err_class)                                    \
-    do {                                                                \
-        printf(err_msg);                                                \
-        fflush(stdout);                                                 \
-        exit(1);                                                        \
-   } while (0)
-#endif // _WIN32
-
-struct texture_object {
-    VkSampler sampler;
-
-    VkImage image;
-    VkImageLayout imageLayout;
-
-    uint32_t  num_mem;
-    VkDeviceMemory *mem;
-    VkImageView view;
-    int32_t tex_width, tex_height;
-};
-
-struct demo {
-#ifdef _WIN32
-#define APP_NAME_STR_LEN 80
-    HINSTANCE connection;        // hInstance - Windows Instance
-    char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
-    HWND        window;          // hWnd - window handle
-#else  // _WIN32
-    xcb_connection_t *connection;
-    xcb_screen_t *screen;
-    xcb_window_t window;
-    xcb_intern_atom_reply_t *atom_wm_delete_window;
-#endif // _WIN32
-    bool prepared;
-    bool use_staging_buffer;
-
-    VkInstance inst;
-    VkPhysicalDevice gpu;
-    VkDevice device;
-    VkQueue queue;
-    VkPhysicalDeviceProperties *gpu_props;
-    VkPhysicalDeviceQueueProperties *queue_props;
-    uint32_t graphics_queue_node_index;
-
-    int width, height;
-    VkFormat format;
-
-    VkSwapChainWSI swap_chain;
-    struct {
-        VkImage image;
-        VkDeviceMemory mem;
-    } buffers[DEMO_BUFFER_COUNT];
-
-    struct {
-        VkFormat format;
-
-        VkImage image;
-        uint32_t num_mem;
-        VkDeviceMemory *mem;
-        VkColorAttachmentView view;
-    } msaa_color;
-
-    struct {
-        VkFormat format;
-
-        VkImage image;
-        uint32_t  num_mem;
-        VkDeviceMemory *mem;
-        VkDepthStencilView view;
-    } msaa_depth;
-
-    struct texture_object textures[DEMO_TEXTURE_COUNT];
-
-    struct {
-        VkBuffer buf;
-        uint32_t  num_mem;
-        VkDeviceMemory *mem;
-
-        VkPipelineVertexInputCreateInfo vi;
-        VkVertexInputBindingDescription vi_bindings[1];
-        VkVertexInputAttributeDescription vi_attrs[2];
-    } vertices;
-
-    VkCmdBuffer cmd;  // Buffer for initialization commands
-    VkPipelineLayout pipeline_layout;
-    VkDescriptorSetLayout desc_layout;
-    VkPipeline pipeline;
-
-    VkDynamicVpState viewport;
-    VkDynamicRsState raster;
-    VkDynamicCbState color_blend;
-    VkDynamicDsState depth_stencil;
-
-    VkDescriptorPool desc_pool;
-    VkDescriptorSet desc_set;
-
-    bool quit;
-    uint32_t current_buffer;
-};
-
-static void demo_flush_init_cmd(struct demo *demo)
-{
-    VkResult err;
-
-    if (demo->cmd == VK_NULL_HANDLE)
-        return;
-
-    err = vkEndCommandBuffer(demo->cmd);
-    assert(!err);
-
-    const VkCmdBuffer cmd_bufs[] = { demo->cmd };
-
-    err = vkQueueSubmit(demo->queue, 1, cmd_bufs, VK_NULL_HANDLE);
-    assert(!err);
-
-    err = vkQueueWaitIdle(demo->queue);
-    assert(!err);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_COMMAND_BUFFER, demo->cmd);
-    demo->cmd = VK_NULL_HANDLE;
-}
-
-static void demo_add_mem_refs(
-        struct demo *demo,
-        int num_refs, VkDeviceMemory *mem)
-{
-    vkQueueAddMemReferences(demo->queue, num_refs, mem);
-}
-
-static void demo_remove_mem_refs(
-        struct demo *demo,
-        int num_refs, VkDeviceMemory *mem)
-{
-    vkQueueRemoveMemReferences(demo->queue, num_refs, mem);
-}
-
-static void demo_set_image_layout(
-        struct demo *demo,
-        VkImage image,
-        VkImageLayout old_image_layout,
-        VkImageLayout new_image_layout)
-{
-    VkResult err;
-
-    if (demo->cmd == VK_NULL_HANDLE) {
-        const VkCmdBufferCreateInfo cmd = {
-            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
-            .pNext = NULL,
-            .queueNodeIndex = demo->graphics_queue_node_index,
-            .flags = 0,
-        };
-
-        err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
-        assert(!err);
-
-        VkCmdBufferBeginInfo cmd_buf_info = {
-            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
-            .pNext = NULL,
-            .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT |
-                VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
-        };
-        err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
-    }
-
-    VkImageMemoryBarrier image_memory_barrier = {
-        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
-        .pNext = NULL,
-        .outputMask = 0,
-        .inputMask = 0,
-        .oldLayout = old_image_layout,
-        .newLayout = new_image_layout,
-        .image = image,
-        .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 0 }
-    };
-
-    if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) {
-        /* Make sure anything that was copying from this image has completed */
-        image_memory_barrier.inputMask = VK_MEMORY_INPUT_TRANSFER_BIT;
-    }
-
-    if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
-        /* Make sure any Copy or CPU writes to image are flushed */
-        image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_TRANSFER_BIT | VK_MEMORY_OUTPUT_CPU_WRITE_BIT;
-    }
-
-    VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
-
-    VkPipeEvent set_events[] = { VK_PIPE_EVENT_TOP_OF_PIPE };
-
-    vkCmdPipelineBarrier(demo->cmd, VK_WAIT_EVENT_TOP_OF_PIPE, 1, set_events, 1, (const void **)&pmemory_barrier);
-}
-
-static void demo_draw_build_cmd(struct demo *demo)
-{
-    const VkColorAttachmentBindInfo color_attachment = {
-        .view = demo->msaa_color.view,
-        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-    };
-    const VkDepthStencilBindInfo depth_stencil = {
-        .view = demo->msaa_depth.view,
-        .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
-    };
-    const VkClearColor clear_color = {
-        .color.floatColor = { 0.2f, 0.2f, 0.2f, 1.0f },
-        .useRawValue = false,
-    };
-    const float clear_depth = 0.0f;
-    VkImageSubresourceRange clear_range;
-    VkCmdBufferBeginInfo cmd_buf_info = {
-        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
-        .pNext = NULL,
-        .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT |
-            VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
-    };
-    VkResult err;
-    VkAttachmentLoadOp load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-    VkAttachmentStoreOp store_op = VK_ATTACHMENT_STORE_OP_RESOLVE_MSAA;
-    const VkFramebufferCreateInfo fb_info = {
-         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
-         .pNext = NULL,
-         .colorAttachmentCount = 1,
-         .pColorAttachments = (VkColorAttachmentBindInfo*) &color_attachment,
-         .pDepthStencilAttachment = (VkDepthStencilBindInfo*) &depth_stencil,
-         .sampleCount = 4,
-         .width  = demo->width,
-         .height = demo->height,
-         .layers = 1,
-    };
-    VkRenderPassCreateInfo rp_info;
-    VkRenderPassBegin rp_begin;
-
-    memset(&rp_info, 0 , sizeof(rp_info));
-    err = vkCreateFramebuffer(demo->device, &fb_info, &rp_begin.framebuffer);
-    assert(!err);
-    rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
-    rp_info.renderArea.extent.width = demo->width;
-    rp_info.renderArea.extent.height = demo->height;
-    rp_info.colorAttachmentCount = fb_info.colorAttachmentCount;
-    rp_info.pColorFormats = &demo->format;
-    rp_info.pColorLayouts = &color_attachment.layout;
-    rp_info.pColorLoadOps = &load_op;
-    rp_info.pColorStoreOps = &store_op;
-    rp_info.pColorLoadClearValues = &clear_color;
-    rp_info.depthStencilFormat = VK_FORMAT_D16_UNORM;
-    rp_info.depthStencilLayout = depth_stencil.layout;
-    rp_info.depthLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-    rp_info.depthLoadClearValue = clear_depth;
-    rp_info.depthStoreOp = VK_ATTACHMENT_STORE_OP_RESOLVE_MSAA;
-    rp_info.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
-    rp_info.stencilLoadClearValue = 0;
-    rp_info.stencilStoreOp = VK_ATTACHMENT_STORE_OP_RESOLVE_MSAA;
-    err = vkCreateRenderPass(demo->device, &rp_info, &(rp_begin.renderPass));
-    assert(!err);
-
-    err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
-    assert(!err);
-
-
-    vkCmdBindPipeline(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
-                                  demo->pipeline);
-    vkCmdBindDescriptorSets(demo->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
-            0, 1, & demo->desc_set, 0, NULL);
-
-    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_POINT_VIEWPORT, demo->viewport);
-    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_POINT_RASTER, demo->raster);
-    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_POINT_COLOR_BLEND,
-                                     demo->color_blend);
-    vkCmdBindDynamicStateObject(demo->cmd, VK_STATE_BIND_POINT_DEPTH_STENCIL,
-                                     demo->depth_stencil);
-
-    VkDeviceSize offsets[1] = {0};
-    vkCmdBindVertexBuffers(demo->cmd, VERTEX_BUFFER_BIND_ID, 1, &demo->vertices.buf, offsets);
-
-    vkCmdBeginRenderPass(demo->cmd, &rp_begin);
-    clear_range.aspect = VK_IMAGE_ASPECT_COLOR;
-    clear_range.baseMipLevel = 0;
-    clear_range.mipLevels = 1;
-    clear_range.baseArraySlice = 0;
-    clear_range.arraySize = 1;
-
-    vkCmdClearColorImage(demo->cmd,
-            demo->msaa_color.image,
-            VK_IMAGE_LAYOUT_CLEAR_OPTIMAL,
-            clear_color, 1, &clear_range);
-
-    clear_range.aspect = VK_IMAGE_ASPECT_DEPTH;
-    vkCmdClearDepthStencil(demo->cmd,
-            demo->msaa_depth.image, VK_IMAGE_LAYOUT_CLEAR_OPTIMAL,
-            clear_depth, 0, 1, &clear_range);
-
-    vkCmdDraw(demo->cmd, 0, 3, 0, 1);
-    vkCmdEndRenderPass(demo->cmd, rp_begin.renderPass);
-
-    VkImageResolve resolve = {
-        .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
-        .srcOffset = { 0, 0, 0 },
-        .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
-        .destOffset = { 0, 0, 0 },
-        .extent = { demo->width, demo->height, 1 }
-    };
-
-    demo_set_image_layout(demo, demo->msaa_color.image,
-                                   VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
-                                   VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL);
-
-    vkCmdResolveImage(demo->cmd, demo->msaa_color.image,
-        VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
-       demo->buffers[demo->current_buffer].image,
-        VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL, 1, &resolve);
-
-    err = vkEndCommandBuffer(demo->cmd);
-    assert(!err);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_RENDER_PASS, rp_begin.renderPass);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_FRAMEBUFFER, rp_begin.framebuffer);
-}
-
-static void demo_draw(struct demo *demo)
-{
-    const VkPresentInfoWSI present = {
-        .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_WSI,
-        .pNext = NULL,
-        .image = demo->buffers[demo->current_buffer].image,
-        .flipInterval = 0,
-    };
-    VkResult err;
-
-    demo_draw_build_cmd(demo);
-
-    err = vkQueueSubmit(demo->queue, 1, &demo->cmd, VK_NULL_HANDLE);
-    assert(!err);
-
-    err = vkQueuePresentWSI(demo->queue, &present);
-    assert(!err);
-
-    demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
-
-    err = vkQueueWaitIdle(demo->queue);
-    assert(err == VK_SUCCESS);
-}
-
-static void demo_prepare_buffers(struct demo *demo)
-{
-    const VkSwapChainCreateInfoWSI swap_chain = {
-        .sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI,
-        .pNext = NULL,
-        .pNativeWindowSystemHandle = demo->connection,
-        .pNativeWindowHandle = (void *) (intptr_t) demo->window,
-        .imageCount = DEMO_BUFFER_COUNT,
-        .imageFormat = demo->format,
-        .imageExtent = {
-            .width = demo->width,
-            .height = demo->height,
-        },
-        .imageArraySize = 1,
-        .imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT,
-    };
-    VkSwapChainImageInfoWSI images[DEMO_BUFFER_COUNT];
-    size_t images_size = sizeof(images);
-    VkResult err;
-    uint32_t i;
-
-    err = vkCreateSwapChainWSI(demo->device, &swap_chain, &demo->swap_chain);
-    assert(!err);
-
-    err = vkGetSwapChainInfoWSI(demo->swap_chain,
-            VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI,
-            &images_size, images);
-    assert(!err && images_size == sizeof(images));
-
-    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
-        demo->buffers[i].image = images[i].image;
-        demo->buffers[i].mem = images[i].memory;
-
-        demo_add_mem_refs(demo, 1, &demo->buffers[i].mem);
-        demo_set_image_layout(demo, demo->buffers[i].image,
-                               VK_IMAGE_LAYOUT_UNDEFINED,
-                               VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL);
-    }
-
-    demo->current_buffer = 0;
-
-    /* create MSAA image */
-    const VkFormat msaa_format = VK_FORMAT_B8G8R8A8_UNORM;
-
-    const VkImageCreateInfo msaa_image_create_info = {
-        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-        .pNext = NULL,
-        .imageType = VK_IMAGE_TYPE_2D,
-        .format = msaa_format,
-        .extent = { demo->width, demo->height, 1 },
-        .mipLevels = 1,
-        .arraySize = 1,
-        .samples = 4,
-        .tiling = VK_IMAGE_TILING_OPTIMAL,
-        .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
-        .flags = 0,
-    };
-    VkMemoryAllocInfo msaa_mem_alloc = {
-        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
-        .pNext = NULL,
-        .allocationSize = 0,
-        .memProps = 0,
-        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
-    };
-
-    VkMemoryRequirements *msaa_mem_reqs;
-    size_t msaa_mem_reqs_size = sizeof(VkMemoryRequirements);
-    uint32_t msaa_num_allocations = 0;
-    size_t msaa_num_alloc_size = sizeof(msaa_num_allocations);
-
-    err = vkCreateImage(demo->device, &msaa_image_create_info,
-            &demo->msaa_color.image);
-    assert(!err);
-
-    err = vkGetObjectInfo(demo->device,
-                VK_OBJECT_TYPE_IMAGE, demo->msaa_color.image,
-                VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
-                &msaa_num_alloc_size, &msaa_num_allocations);
-    assert(!err && msaa_num_alloc_size == sizeof(msaa_num_allocations));
-    msaa_mem_reqs = malloc(msaa_num_allocations * sizeof(VkMemoryRequirements));
-    demo->msaa_color.mem = malloc(msaa_num_allocations * sizeof(VkDeviceMemory));
-    err = vkGetObjectInfo(demo->device,
-                VK_OBJECT_TYPE_IMAGE, demo->msaa_color.image,
-                VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
-                &msaa_mem_reqs_size, msaa_mem_reqs);
-    assert(!err && msaa_mem_reqs_size == msaa_num_allocations * sizeof(VkMemoryRequirements));
-    for (uint32_t j = 0; j < msaa_num_allocations; j ++) {
-        msaa_mem_alloc.allocationSize = msaa_mem_reqs[j].size;
-
-        /* allocate memory */
-        err = vkAllocMemory(demo->device, &msaa_mem_alloc,
-                    &(demo->msaa_color.mem[j]));
-        assert(!err);
-
-        /* bind memory */
-        err = vkQueueBindObjectMemory(demo->queue,
-                VK_OBJECT_TYPE_IMAGE, demo->msaa_color.image,
-                j, demo->msaa_color.mem[j], 0);
-        assert(!err);
-    }
-    free(msaa_mem_reqs);
-    msaa_mem_reqs = NULL;
-
-    demo->msaa_color.num_mem = msaa_num_allocations;
-
-    demo_add_mem_refs(demo, 1, demo->msaa_color.mem);
-    demo_set_image_layout(demo, demo->msaa_color.image,
-                           VK_IMAGE_LAYOUT_UNDEFINED,
-                           VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
-    VkColorAttachmentViewCreateInfo msaa_color_attachment_view = {
-        .sType = VK_STRUCTURE_TYPE_COLOR_ATTACHMENT_VIEW_CREATE_INFO,
-        .pNext = NULL,
-        .format = demo->format,
-        .mipLevel = 0,
-        .baseArraySlice = 0,
-        .arraySize = 1,
-    };
-
-    msaa_color_attachment_view.image = demo->msaa_color.image;
-
-    err = vkCreateColorAttachmentView(demo->device,
-        &msaa_color_attachment_view, &demo->msaa_color.view);
-    assert(!err);
-}
-
-static void demo_prepare_depth(struct demo *demo)
-{
-    const VkFormat depth_format = VK_FORMAT_D16_UNORM;
-    const VkImageCreateInfo image = {
-        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-        .pNext = NULL,
-        .imageType = VK_IMAGE_TYPE_2D,
-        .format = depth_format,
-        .extent = { demo->width, demo->height, 1 },
-        .mipLevels = 1,
-        .arraySize = 1,
-        .samples = 4,
-        .tiling = VK_IMAGE_TILING_OPTIMAL,
-        .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_BIT,
-        .flags = 0,
-    };
-    VkMemoryAllocInfo mem_alloc = {
-        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
-        .pNext = NULL,
-        .allocationSize = 0,
-        .memProps = VK_MEMORY_PROPERTY_DEVICE_ONLY,
-        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
-    };
-    VkDepthStencilViewCreateInfo view = {
-        .sType = VK_STRUCTURE_TYPE_DEPTH_STENCIL_VIEW_CREATE_INFO,
-        .pNext = NULL,
-        .image = VK_NULL_HANDLE,
-        .mipLevel = 0,
-        .baseArraySlice = 0,
-        .arraySize = 1,
-        .flags = 0,
-    };
-
-    VkMemoryRequirements *mem_reqs;
-    size_t mem_reqs_size = sizeof(VkMemoryRequirements);
-    VkResult err;
-    uint32_t num_allocations = 0;
-    size_t num_alloc_size = sizeof(num_allocations);
-
-    demo->msaa_depth.format = depth_format;
-
-    /* create image */
-    err = vkCreateImage(demo->device, &image,
-            &demo->msaa_depth.image);
-    assert(!err);
-
-    err = vkGetObjectInfo(demo->device,
-                    VK_OBJECT_TYPE_IMAGE, demo->msaa_depth.image,
-                    VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
-                    &num_alloc_size, &num_allocations);
-    assert(!err && num_alloc_size == sizeof(num_allocations));
-    mem_reqs = malloc(num_allocations * sizeof(VkMemoryRequirements));
-    demo->msaa_depth.mem = malloc(num_allocations * sizeof(VkDeviceMemory));
-    demo->msaa_depth.num_mem = num_allocations;
-    err = vkGetObjectInfo(demo->device,
-                    VK_OBJECT_TYPE_IMAGE, demo->msaa_depth.image,
-                    VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
-                    &mem_reqs_size, mem_reqs);
-    assert(!err && mem_reqs_size == num_allocations * sizeof(VkMemoryRequirements));
-    for (uint32_t i = 0; i < num_allocations; i ++) {
-        mem_alloc.allocationSize = mem_reqs[i].size;
-
-        /* allocate memory */
-        err = vkAllocMemory(demo->device, &mem_alloc,
-                    &(demo->msaa_depth.mem[i]));
-        assert(!err);
-
-        /* bind memory */
-        err = vkQueueBindObjectMemory(demo->queue,
-                VK_OBJECT_TYPE_IMAGE, demo->msaa_depth.image,
-                i, demo->msaa_depth.mem[i], 0);
-        assert(!err);
-    }
-
-    demo_set_image_layout(demo, demo->msaa_depth.image,
-                           VK_IMAGE_LAYOUT_UNDEFINED,
-                           VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
-
-    demo_add_mem_refs(demo, demo->msaa_depth.num_mem, demo->msaa_depth.mem);
-
-    /* create image view */
-    view.image = demo->msaa_depth.image;
-    err = vkCreateDepthStencilView(demo->device, &view,
-            &demo->msaa_depth.view);
-    assert(!err);
-}
-
-static void demo_prepare_texture_image(struct demo *demo,
-                                       const uint32_t *tex_colors,
-                                       struct texture_object *tex_obj,
-                                       VkImageTiling tiling,
-                                       VkImageUsageFlags usage,
-                                       VkFlags mem_props)
-{
-    const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
-    const int32_t tex_width = 2;
-    const int32_t tex_height = 2;
-    VkResult err;
-
-    tex_obj->tex_width = tex_width;
-    tex_obj->tex_height = tex_height;
-
-    const VkImageCreateInfo image_create_info = {
-        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
-        .pNext = NULL,
-        .imageType = VK_IMAGE_TYPE_2D,
-        .format = tex_format,
-        .extent = { tex_width, tex_height, 1 },
-        .mipLevels = 1,
-        .arraySize = 1,
-        .samples = 1,
-        .tiling = tiling,
-        .usage = usage,
-        .flags = 0,
-    };
-    VkMemoryAllocInfo mem_alloc = {
-        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
-        .pNext = NULL,
-        .allocationSize = 0,
-        .memProps = mem_props,
-        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
-    };
-
-    VkMemoryRequirements *mem_reqs;
-    size_t mem_reqs_size = sizeof(VkMemoryRequirements);
-    uint32_t num_allocations = 0;
-    size_t num_alloc_size = sizeof(num_allocations);
-
-    err = vkCreateImage(demo->device, &image_create_info,
-            &tex_obj->image);
-    assert(!err);
-
-    err = vkGetObjectInfo(demo->device,
-                VK_OBJECT_TYPE_IMAGE, tex_obj->image,
-                VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
-                &num_alloc_size, &num_allocations);
-    assert(!err && num_alloc_size == sizeof(num_allocations));
-    mem_reqs = malloc(num_allocations * sizeof(VkMemoryRequirements));
-    tex_obj->mem = malloc(num_allocations * sizeof(VkDeviceMemory));
-    err = vkGetObjectInfo(demo->device,
-                VK_OBJECT_TYPE_IMAGE, tex_obj->image,
-                VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
-                &mem_reqs_size, mem_reqs);
-    assert(!err && mem_reqs_size == num_allocations * sizeof(VkMemoryRequirements));
-    for (uint32_t j = 0; j < num_allocations; j ++) {
-        mem_alloc.allocationSize = mem_reqs[j].size;
-
-        /* allocate memory */
-        err = vkAllocMemory(demo->device, &mem_alloc,
-                    &(tex_obj->mem[j]));
-        assert(!err);
-
-        /* bind memory */
-        err = vkQueueBindObjectMemory(demo->queue,
-                VK_OBJECT_TYPE_IMAGE, tex_obj->image,
-                j, tex_obj->mem[j], 0);
-        assert(!err);
-    }
-    free(mem_reqs);
-    mem_reqs = NULL;
-
-    tex_obj->num_mem = num_allocations;
-
-    if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
-        const VkImageSubresource subres = {
-            .aspect = VK_IMAGE_ASPECT_COLOR,
-            .mipLevel = 0,
-            .arraySlice = 0,
-        };
-        VkSubresourceLayout layout;
-        size_t layout_size = sizeof(VkSubresourceLayout);
-        void *data;
-        int32_t x, y;
-
-        err = vkGetImageSubresourceInfo(demo->device, tex_obj->image, &subres,
-                                         VK_SUBRESOURCE_INFO_TYPE_LAYOUT,
-                                         &layout_size, &layout);
-        assert(!err && layout_size == sizeof(layout));
-        /* Linear texture must be within a single memory object */
-        assert(num_allocations == 1);
-
-        err = vkMapMemory(demo->device, tex_obj->mem[0], 0, 0, 0, &data);
-        assert(!err);
-
-        for (y = 0; y < tex_height; y++) {
-            uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y);
-            for (x = 0; x < tex_width; x++)
-                row[x] = tex_colors[(x & 1) ^ (y & 1)];
-        }
-
-        err = vkUnmapMemory(demo->device, tex_obj->mem[0]);
-        assert(!err);
-    }
-
-    tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
-    demo_set_image_layout(demo, tex_obj->image,
-                           VK_IMAGE_LAYOUT_UNDEFINED,
-                           tex_obj->imageLayout);
-    /* setting the image layout does not reference the actual memory so no need to add a mem ref */
-}
-
-static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_obj)
-{
-    /* clean up staging resources */
-    for (uint32_t j = 0; j < tex_obj->num_mem; j ++) {
-        vkQueueBindObjectMemory(demo->queue,
-                VK_OBJECT_TYPE_IMAGE, tex_obj->image, j, VK_NULL_HANDLE, 0);
-        vkFreeMemory(demo->device, tex_obj->mem[j]);
-    }
-
-    free(tex_obj->mem);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, tex_obj->image);
-}
-
-static void demo_prepare_textures(struct demo *demo)
-{
-    const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
-    VkFormatProperties props;
-    size_t size = sizeof(props);
-    const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = {
-        { 0xffff0000, 0xff00ff00 },
-    };
-    VkResult err;
-    uint32_t i;
-
-    err = vkGetFormatInfo(demo->device, tex_format,
-                           VK_FORMAT_INFO_TYPE_PROPERTIES,
-                           &size, &props);
-    assert(!err);
-
-    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
-        if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) {
-            /* Device can texture using linear textures */
-            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
-                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-        } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT){
-            /* Must use staging buffer to copy linear texture to optimized */
-            struct texture_object staging_texture;
-
-            memset(&staging_texture, 0, sizeof(staging_texture));
-            demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
-                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
-
-            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
-                                       VK_IMAGE_TILING_OPTIMAL,
-                                       (VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
-                                       VK_MEMORY_PROPERTY_DEVICE_ONLY);
-
-            demo_set_image_layout(demo, staging_texture.image,
-                                   staging_texture.imageLayout,
-                                   VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL);
-
-            demo_set_image_layout(demo, demo->textures[i].image,
-                                   demo->textures[i].imageLayout,
-                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL);
-
-            VkImageCopy copy_region = {
-                .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
-                .srcOffset = { 0, 0, 0 },
-                .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
-                .destOffset = { 0, 0, 0 },
-                .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 },
-            };
-            vkCmdCopyImage(demo->cmd,
-                            staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
-                            demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
-                            1, &copy_region);
-
-            demo_add_mem_refs(demo, staging_texture.num_mem, staging_texture.mem);
-            demo_add_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem);
-
-            demo_set_image_layout(demo, demo->textures[i].image,
-                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
-                                   demo->textures[i].imageLayout);
-
-            demo_flush_init_cmd(demo);
-
-            demo_remove_mem_refs(demo, staging_texture.num_mem, staging_texture.mem);
-            demo_destroy_texture_image(demo, &staging_texture);
-        } else {
-            /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */
-            assert(!"No support for B8G8R8A8_UNORM as texture image format");
-        }
-
-        const VkSamplerCreateInfo sampler = {
-            .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
-            .pNext = NULL,
-            .magFilter = VK_TEX_FILTER_NEAREST,
-            .minFilter = VK_TEX_FILTER_NEAREST,
-            .mipMode = VK_TEX_MIPMAP_MODE_BASE,
-            .addressU = VK_TEX_ADDRESS_WRAP,
-            .addressV = VK_TEX_ADDRESS_WRAP,
-            .addressW = VK_TEX_ADDRESS_WRAP,
-            .mipLodBias = 0.0f,
-            .maxAnisotropy = 1,
-            .compareOp = VK_COMPARE_OP_NEVER,
-            .minLod = 0.0f,
-            .maxLod = 0.0f,
-            .borderColor = VK_BORDER_COLOR_OPAQUE_WHITE,
-        };
-        VkImageViewCreateInfo view = {
-            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
-            .pNext = NULL,
-            .image = VK_NULL_HANDLE,
-            .viewType = VK_IMAGE_VIEW_TYPE_2D,
-            .format = tex_format,
-            .channels = { VK_CHANNEL_SWIZZLE_R,
-                          VK_CHANNEL_SWIZZLE_G,
-                          VK_CHANNEL_SWIZZLE_B,
-                          VK_CHANNEL_SWIZZLE_A, },
-            .subresourceRange = { VK_IMAGE_ASPECT_COLOR, 0, 1, 0, 1 },
-            .minLod = 0.0f,
-        };
-
-        /* create sampler */
-        err = vkCreateSampler(demo->device, &sampler,
-                &demo->textures[i].sampler);
-        assert(!err);
-
-        /* create image view */
-        view.image = demo->textures[i].image;
-        err = vkCreateImageView(demo->device, &view,
-                                 &demo->textures[i].view);
-        assert(!err);
-    }
-}
-
-static void demo_prepare_vertices(struct demo *demo)
-{
-    const float vb[3][5] = {
-        /*      position             texcoord */
-        { -1.0f, -1.0f, -0.6f,      0.0f, 0.0f },
-        {  1.0f, -1.0f, -0.5f,      1.0f, 0.0f },
-        {  0.0f,  1.0f,  0.0f,      0.5f, 1.0f },
-    };
-    const VkBufferCreateInfo buf_info = {
-        .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
-        .pNext = NULL,
-        .size = sizeof(vb),
-        .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
-        .flags = 0,
-    };
-    VkMemoryAllocInfo mem_alloc = {
-        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
-        .pNext = NULL,
-        .allocationSize = 0,
-        .memProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
-        .memPriority = VK_MEMORY_PRIORITY_NORMAL,
-    };
-    VkMemoryRequirements *mem_reqs;
-    size_t mem_reqs_size = sizeof(VkMemoryRequirements);
-    uint32_t num_allocations = 0;
-    size_t num_alloc_size = sizeof(num_allocations);
-    VkResult err;
-    void *data;
-
-    memset(&demo->vertices, 0, sizeof(demo->vertices));
-
-    err = vkCreateBuffer(demo->device, &buf_info, &demo->vertices.buf);
-    assert(!err);
-
-    err = vkGetObjectInfo(demo->device,
-                           VK_OBJECT_TYPE_BUFFER, demo->vertices.buf,
-                           VK_OBJECT_INFO_TYPE_MEMORY_ALLOCATION_COUNT,
-                           &num_alloc_size, &num_allocations);
-    assert(!err && num_alloc_size == sizeof(num_allocations));
-    mem_reqs = malloc(num_allocations * sizeof(VkMemoryRequirements));
-    demo->vertices.mem = malloc(num_allocations * sizeof(VkDeviceMemory));
-    demo->vertices.num_mem = num_allocations;
-    err = vkGetObjectInfo(demo->device,
-            VK_OBJECT_TYPE_BUFFER, demo->vertices.buf,
-            VK_OBJECT_INFO_TYPE_MEMORY_REQUIREMENTS,
-            &mem_reqs_size, mem_reqs);
-    assert(!err && mem_reqs_size == sizeof(*mem_reqs));
-    for (uint32_t i = 0; i < num_allocations; i ++) {
-        mem_alloc.allocationSize = mem_reqs[i].size;
-
-        err = vkAllocMemory(demo->device, &mem_alloc, &demo->vertices.mem[i]);
-        assert(!err);
-
-        err = vkMapMemory(demo->device, demo->vertices.mem[i], 0, 0, 0, &data);
-        assert(!err);
-
-        memcpy(data, vb, sizeof(vb));
-
-        err = vkUnmapMemory(demo->device, demo->vertices.mem[i]);
-        assert(!err);
-
-        err = vkQueueBindObjectMemory(demo->queue,
-                VK_OBJECT_TYPE_BUFFER, demo->vertices.buf,
-                i, demo->vertices.mem[i], 0);
-        assert(!err);
-    }
-
-    demo_add_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem);
-
-    demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO;
-    demo->vertices.vi.pNext = NULL;
-    demo->vertices.vi.bindingCount = 1;
-    demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings;
-    demo->vertices.vi.attributeCount = 2;
-    demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs;
-
-    demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID;
-    demo->vertices.vi_bindings[0].strideInBytes = sizeof(vb[0]);
-    demo->vertices.vi_bindings[0].stepRate = VK_VERTEX_INPUT_STEP_RATE_VERTEX;
-
-    demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID;
-    demo->vertices.vi_attrs[0].location = 0;
-    demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
-    demo->vertices.vi_attrs[0].offsetInBytes = 0;
-
-    demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID;
-    demo->vertices.vi_attrs[1].location = 1;
-    demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
-    demo->vertices.vi_attrs[1].offsetInBytes = sizeof(float) * 3;
-}
-
-static void demo_prepare_descriptor_layout(struct demo *demo)
-{
-    const VkDescriptorSetLayoutBinding layout_binding = {
-        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-        .count = DEMO_TEXTURE_COUNT,
-        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
-        .pImmutableSamplers = NULL,
-    };
-    const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
-        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
-        .pNext = NULL,
-        .count = 1,
-        .pBinding = &layout_binding,
-    };
-    VkResult err;
-
-    err = vkCreateDescriptorSetLayout(demo->device,
-            &descriptor_layout, &demo->desc_layout);
-    assert(!err);
-
-    const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
-        .sType              = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
-        .pNext              = NULL,
-        .descriptorSetCount = 1,
-        .pSetLayouts        = &demo->desc_layout,
-    };
-
-    err = vkCreatePipelineLayout(demo->device,
-                                 &pPipelineLayoutCreateInfo,
-                                 &demo->pipeline_layout);
-    assert(!err);
-}
-
-static VkShader demo_prepare_shader(struct demo *demo,
-                                      VkShaderStage stage,
-                                      const void *code,
-                                      size_t size)
-{
-    VkShaderCreateInfo createInfo;
-    VkShader shader;
-    VkResult err;
-
-    createInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO;
-    createInfo.pNext = NULL;
-
-    // Create fake SPV structure to feed GLSL
-    // to the driver "under the covers"
-    createInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
-    createInfo.pCode = malloc(createInfo.codeSize);
-    createInfo.flags = 0;
-
-    /* try version 0 first: VkShaderStage followed by GLSL */
-    ((uint32_t *) createInfo.pCode)[0] = ICD_SPV_MAGIC;
-    ((uint32_t *) createInfo.pCode)[1] = 0;
-    ((uint32_t *) createInfo.pCode)[2] = stage;
-    memcpy(((uint32_t *) createInfo.pCode + 3), code, size + 1);
-
-    err = vkCreateShader(demo->device, &createInfo, &shader);
-    if (err) {
-        free((void *) createInfo.pCode);
-        return VK_NULL_HANDLE;
-    }
-
-    return shader;
-}
-
-static VkShader demo_prepare_vs(struct demo *demo)
-{
-    static const char *vertShaderText =
-            "#version 140\n"
-            "#extension GL_ARB_separate_shader_objects : enable\n"
-            "#extension GL_ARB_shading_language_420pack : enable\n"
-            "layout (location = 0) in vec4 pos;\n"
-            "layout (location = 1) in vec2 attr;\n"
-            "out vec2 texcoord;\n"
-            "void main() {\n"
-            "   texcoord = attr;\n"
-            "   gl_Position = pos;\n"
-            "}\n";
-
-    return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX,
-                               (const void *) vertShaderText,
-                               strlen(vertShaderText));
-}
-
-static VkShader demo_prepare_fs(struct demo *demo)
-{
-    static const char *fragShaderText =
-            "#version 140\n"
-            "#extension GL_ARB_separate_shader_objects : enable\n"
-            "#extension GL_ARB_shading_language_420pack : enable\n"
-            "layout (binding = 0) uniform sampler2D tex;\n"
-            "layout (location = 0) in vec2 texcoord;\n"
-            "void main() {\n"
-            "   gl_FragColor = texture(tex, texcoord);\n"
-            "}\n";
-
-    return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT,
-                               (const void *) fragShaderText,
-                               strlen(fragShaderText));
-}
-
-static void demo_prepare_pipeline(struct demo *demo)
-{
-    VkGraphicsPipelineCreateInfo pipeline;
-    VkPipelineVertexInputCreateInfo vi;
-    VkPipelineIaStateCreateInfo ia;
-    VkPipelineRsStateCreateInfo rs;
-    VkPipelineCbStateCreateInfo cb;
-    VkPipelineDsStateCreateInfo ds;
-    VkPipelineShaderStageCreateInfo vs;
-    VkPipelineShaderStageCreateInfo fs;
-    VkPipelineVpStateCreateInfo vp;
-    VkPipelineMsStateCreateInfo ms;
-    VkResult err;
-
-    memset(&pipeline, 0, sizeof(pipeline));
-    pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
-    pipeline.layout = demo->pipeline_layout;
-
-    vi = demo->vertices.vi;
-
-    memset(&ia, 0, sizeof(ia));
-    ia.sType = VK_STRUCTURE_TYPE_PIPELINE_IA_STATE_CREATE_INFO;
-    ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
-
-    memset(&rs, 0, sizeof(rs));
-    rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RS_STATE_CREATE_INFO;
-    rs.fillMode = VK_FILL_MODE_SOLID;
-    rs.cullMode = VK_CULL_MODE_NONE;
-    rs.frontFace = VK_FRONT_FACE_CCW;
-
-    memset(&cb, 0, sizeof(cb));
-    cb.sType = VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO;
-    VkPipelineCbAttachmentState att_state[1];
-    memset(att_state, 0, sizeof(att_state));
-    att_state[0].format = demo->format;
-    att_state[0].channelWriteMask = 0xf;
-    att_state[0].blendEnable = VK_FALSE;
-    cb.attachmentCount = 1;
-    cb.pAttachments = att_state;
-
-
-    memset(&vp, 0, sizeof(vp));
-    vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VP_STATE_CREATE_INFO;
-    vp.viewportCount = 1;
-    vp.clipOrigin = VK_COORDINATE_ORIGIN_UPPER_LEFT;
-
-    memset(&ds, 0, sizeof(ds));
-    ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DS_STATE_CREATE_INFO;
-    ds.format = demo->msaa_depth.format;
-    ds.depthTestEnable = VK_TRUE;
-    ds.depthWriteEnable = VK_TRUE;
-    ds.depthCompareOp = VK_COMPARE_OP_LESS_EQUAL;
-    ds.depthBoundsEnable = VK_FALSE;
-    ds.back.stencilFailOp = VK_STENCIL_OP_KEEP;
-    ds.back.stencilPassOp = VK_STENCIL_OP_KEEP;
-    ds.back.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
-    ds.stencilTestEnable = VK_FALSE;
-    ds.front = ds.back;
-
-    memset(&vs, 0, sizeof(vs));
-    vs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-    vs.shader.stage = VK_SHADER_STAGE_VERTEX;
-    vs.shader.shader = demo_prepare_vs(demo);
-    vs.shader.linkConstBufferCount = 0;
-
-    memset(&fs, 0, sizeof(fs));
-    fs.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-    fs.shader.stage = VK_SHADER_STAGE_FRAGMENT;
-    fs.shader.shader = demo_prepare_fs(demo);
-
-    memset(&ms, 0, sizeof(ms));
-    ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MS_STATE_CREATE_INFO;
-    ms.sampleMask = 0xffff;
-    ms.multisampleEnable = VK_TRUE;
-    ms.samples = 4;
-
-    pipeline.pNext = (const void *) &vi;
-    vi.pNext = (void *) &ia;
-    ia.pNext = (const void *) &rs;
-    rs.pNext = (const void *) &cb;
-    cb.pNext = (const void *) &ms;
-    ms.pNext = (const void *) &vp;
-    vp.pNext = (const void *) &ds;
-    ds.pNext = (const void *) &vs;
-    vs.pNext = (const void *) &fs;
-
-    err = vkCreateGraphicsPipeline(demo->device, &pipeline, &demo->pipeline);
-    assert(!err);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_SHADER, vs.shader.shader);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_SHADER, fs.shader.shader);
-}
-
-static void demo_prepare_dynamic_states(struct demo *demo)
-{
-    VkDynamicVpStateCreateInfo viewport_create;
-    VkDynamicRsStateCreateInfo raster;
-    VkDynamicCbStateCreateInfo color_blend;
-    VkDynamicDsStateCreateInfo depth_stencil;
-    VkResult err;
-
-    memset(&viewport_create, 0, sizeof(viewport_create));
-    viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VP_STATE_CREATE_INFO;
-    viewport_create.viewportAndScissorCount = 1;
-    VkViewport viewport;
-    memset(&viewport, 0, sizeof(viewport));
-    viewport.height = (float) demo->height;
-    viewport.width = (float) demo->width;
-    viewport.minDepth = (float) 0.0f;
-    viewport.maxDepth = (float) 1.0f;
-    viewport_create.pViewports = &viewport;
-    VkRect scissor;
-    memset(&scissor, 0, sizeof(scissor));
-    scissor.extent.width = demo->width;
-    scissor.extent.height = demo->height;
-    scissor.offset.x = 0;
-    scissor.offset.y = 0;
-    viewport_create.pScissors = &scissor;
-
-    memset(&raster, 0, sizeof(raster));
-    raster.sType = VK_STRUCTURE_TYPE_DYNAMIC_RS_STATE_CREATE_INFO;
-    raster.pointSize = 1.0;
-    raster.lineWidth = 1.0;
-
-    memset(&color_blend, 0, sizeof(color_blend));
-    color_blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_CB_STATE_CREATE_INFO;
-    color_blend.blendConst[0] = 1.0f;
-    color_blend.blendConst[1] = 1.0f;
-    color_blend.blendConst[2] = 1.0f;
-    color_blend.blendConst[3] = 1.0f;
-
-    memset(&depth_stencil, 0, sizeof(depth_stencil));
-    depth_stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_DS_STATE_CREATE_INFO;
-    depth_stencil.minDepth = 0.0f;
-    depth_stencil.maxDepth = 1.0f;
-    depth_stencil.stencilBackRef = 0;
-    depth_stencil.stencilFrontRef = 0;
-    depth_stencil.stencilReadMask = 0xff;
-    depth_stencil.stencilWriteMask = 0xff;
-
-    err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->viewport);
-    assert(!err);
-
-    err = vkCreateDynamicRasterState(demo->device, &raster, &demo->raster);
-    assert(!err);
-
-    err = vkCreateDynamicColorBlendState(demo->device,
-            &color_blend, &demo->color_blend);
-    assert(!err);
-
-    err = vkCreateDynamicDepthStencilState(demo->device,
-            &depth_stencil, &demo->depth_stencil);
-    assert(!err);
-}
-
-static void demo_prepare_descriptor_pool(struct demo *demo)
-{
-    const VkDescriptorTypeCount type_count = {
-        .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
-        .count = DEMO_TEXTURE_COUNT,
-    };
-    const VkDescriptorPoolCreateInfo descriptor_pool = {
-        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
-        .pNext = NULL,
-        .count = 1,
-        .pTypeCount = &type_count,
-    };
-    VkResult err;
-
-    err = vkCreateDescriptorPool(demo->device,
-            VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1,
-            &descriptor_pool, &demo->desc_pool);
-    assert(!err);
-}
-
-static void demo_prepare_descriptor_set(struct demo *demo)
-{
-    VkImageViewAttachInfo view_info[DEMO_TEXTURE_COUNT];
-    VkSamplerImageViewInfo combined_info[DEMO_TEXTURE_COUNT];
-    VkUpdateSamplerTextures update;
-    const void *update_array[1] = { &update };
-    VkResult err;
-    uint32_t count;
-    uint32_t i;
-
-    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
-        view_info[i].sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_ATTACH_INFO;
-        view_info[i].pNext = NULL;
-        view_info[i].view = demo->textures[i].view,
-        view_info[i].layout = VK_IMAGE_LAYOUT_GENERAL;
-
-        combined_info[i].sampler = demo->textures[i].sampler;
-        combined_info[i].pImageView = &view_info[i];
-    }
-
-    memset(&update, 0, sizeof(update));
-    update.sType = VK_STRUCTURE_TYPE_UPDATE_SAMPLER_TEXTURES;
-    update.count = DEMO_TEXTURE_COUNT;
-    update.pSamplerImageViews = combined_info;
-
-    err = vkAllocDescriptorSets(demo->device, demo->desc_pool,
-            VK_DESCRIPTOR_SET_USAGE_STATIC,
-            1, &demo->desc_layout,
-            &demo->desc_set, &count);
-    assert(!err && count == 1);
-
-    vkBeginDescriptorPoolUpdate(demo->device,
-            VK_DESCRIPTOR_UPDATE_MODE_FASTEST);
-
-    vkClearDescriptorSets(demo->device, demo->desc_pool, 1, &demo->desc_set);
-    vkUpdateDescriptors(demo->device, demo->desc_set, 1, update_array);
-
-    vkEndDescriptorPoolUpdate(demo->device, demo->cmd);
-}
-
-static void demo_prepare(struct demo *demo)
-{
-    const VkCmdBufferCreateInfo cmd = {
-        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
-        .pNext = NULL,
-        .queueNodeIndex = demo->graphics_queue_node_index,
-        .flags = 0,
-    };
-    VkResult err;
-
-    demo_prepare_buffers(demo);
-    demo_prepare_depth(demo);
-    demo_prepare_textures(demo);
-    demo_prepare_vertices(demo);
-    demo_prepare_descriptor_layout(demo);
-    demo_prepare_pipeline(demo);
-    demo_prepare_dynamic_states(demo);
-
-    err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
-    assert(!err);
-
-    demo_prepare_descriptor_pool(demo);
-    demo_prepare_descriptor_set(demo);
-    demo->prepared = true;
-}
-
-#ifdef _WIN32
-static void demo_run(struct demo *demo)
-{
-    if (!demo->prepared)
-        return;
-    demo_draw(demo);
-}
-
-// On MS-Windows, make this a global, so it's available to WndProc()
-struct demo demo;
-
-// MS-Windows event handling function:
-LRESULT CALLBACK WndProc(HWND hWnd,
-                         UINT uMsg,
-                         WPARAM wParam,
-                         LPARAM lParam)
-{
-    char tmp_str[] = APP_LONG_NAME;
-
-    switch(uMsg)
-    {
-    case WM_CREATE:
-        return 0;
-    case WM_CLOSE:
-        demo.prepared = false;
-        DestroyWindow(hWnd);
-        PostQuitMessage(0);
-        return 0;
-    case WM_PAINT:
-        demo_run(&demo);
-        return 0;
-    default:
-        break;
-    }
-    return (DefWindowProc(hWnd, uMsg, wParam, lParam));
-}
-
-static void demo_create_window(struct demo *demo)
-{
-    WNDCLASSEX  win_class;
-
-    // Initialize the window class structure:
-    win_class.cbSize = sizeof(WNDCLASSEX);
-    win_class.style = CS_HREDRAW | CS_VREDRAW;
-    win_class.lpfnWndProc = WndProc;
-    win_class.cbClsExtra = 0;
-    win_class.cbWndExtra = 0;
-    win_class.hInstance = demo->connection; // hInstance
-    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
-    win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
-    win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
-    win_class.lpszMenuName = NULL;
-    win_class.lpszClassName = demo->name;
-    win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
-    // Register window class:
-    if (!RegisterClassEx(&win_class)) {
-        // It didn't work, so try to give a useful error:
-        printf("Unexpected error trying to start the application!\n");
-        fflush(stdout);
-        WAIT_FOR_CONSOLE_DESTROY;
-        exit(1);
-    }
-    // Create window with the registered class:
-    demo->window = CreateWindowEx(0,
-                                  demo->name,           // class name
-                                  demo->name,           // app name
-                                  WS_OVERLAPPEDWINDOW | // window style
-                                  WS_VISIBLE |
-                                  WS_SYSMENU,
-                                  100,100,              // x/y coords
-                                  demo->width,          // width
-                                  demo->height,         // height
-                                  NULL,                 // handle to parent
-                                  NULL,                 // handle to menu
-                                  demo->connection,     // hInstance
-                                  NULL);                // no extra parameters
-    if (!demo->window) {
-        // It didn't work, so try to give a useful error:
-        printf("Cannot create a window in which to draw!\n");
-        fflush(stdout);
-        WAIT_FOR_CONSOLE_DESTROY;
-        exit(1);
-    }
-}
-#else  // _WIN32
-
-static void demo_handle_event(struct demo *demo,
-                              const xcb_generic_event_t *event)
-{
-    switch (event->response_type & 0x7f) {
-    case XCB_EXPOSE:
-        demo_draw(demo);
-        break;
-    case XCB_CLIENT_MESSAGE:
-        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
-           (*demo->atom_wm_delete_window).atom) {
-            demo->quit = true;
-        }
-        break;
-    case XCB_KEY_RELEASE:
-        {
-            const xcb_key_release_event_t *key =
-                (const xcb_key_release_event_t *) event;
-
-            if (key->detail == 0x9)
-                demo->quit = true;
-        }
-        break;
-    case XCB_DESTROY_NOTIFY:
-        demo->quit = true;
-        break;
-    default:
-        break;
-    }
-}
-
-static void demo_run(struct demo *demo)
-{
-    xcb_flush(demo->connection);
-
-    while (!demo->quit) {
-        xcb_generic_event_t *event;
-
-        event = xcb_wait_for_event(demo->connection);
-        if (event) {
-            demo_handle_event(demo, event);
-            free(event);
-        }
-    }
-}
-
-static void demo_create_window(struct demo *demo)
-{
-    uint32_t value_mask, value_list[32];
-
-    demo->window = xcb_generate_id(demo->connection);
-
-    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
-    value_list[0] = demo->screen->black_pixel;
-    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
-                    XCB_EVENT_MASK_EXPOSURE |
-                    XCB_EVENT_MASK_STRUCTURE_NOTIFY;
-
-    xcb_create_window(demo->connection,
-            XCB_COPY_FROM_PARENT,
-            demo->window, demo->screen->root,
-            0, 0, demo->width, demo->height, 0,
-            XCB_WINDOW_CLASS_INPUT_OUTPUT,
-            demo->screen->root_visual,
-            value_mask, value_list);
-
-    /* Magic code that will send notification when window is destroyed */
-    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
-                                                      "WM_PROTOCOLS");
-    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
-
-    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
-    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
-
-    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
-                        demo->window, (*reply).atom, 4, 32, 1,
-                        &(*demo->atom_wm_delete_window).atom);
-    free(reply);
-
-    xcb_map_window(demo->connection, demo->window);
-}
-#endif // _WIN32
-
-static void demo_init_vk(struct demo *demo)
-{
-    VkResult err;
-    // Extensions to enable
-    const char *ext_names[] = {
-        "VK_WSI_LunarG",
-    };
-    size_t extSize = sizeof(uint32_t);
-    uint32_t extCount = 0;
-    err = vkGetGlobalExtensionInfo(VK_EXTENSION_INFO_TYPE_COUNT, 0, &extSize, &extCount);
-    assert(!err);
-
-    VkExtensionProperties extProp;
-    extSize = sizeof(VkExtensionProperties);
-    bool32_t extFound = 0;
-    for (uint32_t i = 0; i < extCount; i++) {
-        err = vkGetGlobalExtensionInfo(VK_EXTENSION_INFO_TYPE_PROPERTIES, i, &extSize, &extProp);
-        if (!strcmp(ext_names[0], extProp.extName))
-            extFound = 1;
-    }
-    if (!extFound) {
-        ERR_EXIT("vkGetGlobalExtensionInfo failed to find the "
-                 "\"VK_WSI_LunarG\" extension.\n\nDo you have a compatible "
-                 "Vulkan installable client driver (ICD) installed?\nPlease "
-                 "look at the Getting Started guide for additional "
-                 "information.\n",
-                 "vkCreateInstance Failure");
-    }
-    const VkApplicationInfo app = {
-        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
-        .pNext = NULL,
-        .pAppName = APP_SHORT_NAME,
-        .appVersion = 0,
-        .pEngineName = APP_SHORT_NAME,
-        .engineVersion = 0,
-        .apiVersion = VK_API_VERSION,
-    };
-    const VkInstanceCreateInfo inst_info = {
-        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
-        .pNext = NULL,
-        .pAppInfo = &app,
-        .pAllocCb = NULL,
-        .extensionCount = 1,
-        .ppEnabledExtensionNames = ext_names,
-    };
-    const VkDeviceQueueCreateInfo queue = {
-        .queueNodeIndex = 0,
-        .queueCount = 1,
-    };
-    const VkDeviceCreateInfo device = {
-        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
-        .pNext = NULL,
-        .queueRecordCount = 1,
-        .pRequestedQueues = &queue,
-        .extensionCount = 1,
-        .ppEnabledExtensionNames = ext_names,
-        .flags = VK_DEVICE_CREATE_VALIDATION_BIT,
-    };
-    uint32_t gpu_count;
-    uint32_t i;
-    size_t data_size;
-    uint32_t queue_count;
-
-    err = vkCreateInstance(&inst_info, &demo->inst);
-    if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
-        ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
-                 "(ICD).\n\nPlease look at the Getting Started guide for "
-                 "additional information.\n",
-                 "vkCreateInstance Failure");
-    } else if (err) {
-        ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
-                 "installable client driver (ICD) installed?\nPlease look at "
-                 "the Getting Started guide for additional information.\n",
-                 "vkCreateInstance Failure");
-    }
-
-    gpu_count = 1;
-    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, &demo->gpu);
-    assert(!err && gpu_count == 1);
-
-    err = vkCreateDevice(demo->gpu, &device, &demo->device);
-    assert(!err);
-
-    err = vkGetPhysicalDeviceInfo(demo->gpu, VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES,
-                        &data_size, NULL);
-    assert(!err);
-
-    demo->gpu_props = (VkPhysicalDeviceProperties *) malloc(data_size);
-    err = vkGetPhysicalDeviceInfo(demo->gpu, VK_PHYSICAL_DEVICE_INFO_TYPE_PROPERTIES,
-                        &data_size, demo->gpu_props);
-    assert(!err);
-
-    err = vkGetPhysicalDeviceInfo(demo->gpu, VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PROPERTIES,
-                        &data_size, NULL);
-    assert(!err);
-
-    demo->queue_props = (VkPhysicalDeviceQueueProperties *) malloc(data_size);
-    err = vkGetPhysicalDeviceInfo(demo->gpu, VK_PHYSICAL_DEVICE_INFO_TYPE_QUEUE_PROPERTIES,
-                        &data_size, demo->queue_props);
-    assert(!err);
-    queue_count = (uint32_t) (data_size / sizeof(VkPhysicalDeviceQueueProperties));
-    assert(queue_count >= 1);
-
-    for (i = 0; i < queue_count; i++) {
-        if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
-            break;
-        if (demo->queue_props[i].queueFlags & VK_QUEUE_MEMMGR_BIT)
-            break;
-    }
-    assert(i < queue_count);
-    demo->graphics_queue_node_index = i;
-
-    err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
-            0, &demo->queue);
-    assert(!err);
-}
-
-static void demo_init_connection(struct demo *demo)
-{
-#ifndef _WIN32
-    const xcb_setup_t *setup;
-    xcb_screen_iterator_t iter;
-    int scr;
-
-    demo->connection = xcb_connect(NULL, &scr);
-    if (demo->connection == NULL) {
-        printf("Cannot find a compatible Vulkan installable client driver "
-               "(ICD).\nExiting ...\n");
-        fflush(stdout);
-        exit(1);
-    }
-
-    setup = xcb_get_setup(demo->connection);
-    iter = xcb_setup_roots_iterator(setup);
-    while (scr-- > 0)
-        xcb_screen_next(&iter);
-
-    demo->screen = iter.data;
-#endif // _WIN32
-}
-
-#ifdef _WIN32
-static void demo_init(struct demo *demo, HINSTANCE hInstance, LPSTR pCmdLine)
-#else  // _WIN32
-static void demo_init(struct demo *demo, const int argc, const char *argv[])
-#endif // _WIN32
-{
-    bool argv_error = false;
-
-    memset(demo, 0, sizeof(*demo));
-
-#ifdef _WIN32
-    demo->connection = hInstance;
-    strncpy(demo->name, APP_SHORT_NAME, APP_NAME_STR_LEN);
-
-    if (strncmp(pCmdLine, "--use_staging", strlen("--use_staging")) == 0)
-        demo->use_staging_buffer = true;
-    else if (strlen(pCmdLine) != 0) {
-        fprintf(stderr, "Do not recognize argument \"%s\".\n", pCmdLine);
-        argv_error = true;
-    }
-#else  // _WIN32
-    for (int i = 0; i < argc; i++) {
-        if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0)
-            demo->use_staging_buffer = true;
-    }
-#endif // _WIN32
-    if (argv_error) {
-        fprintf(stderr, "Usage:\n  %s [--use_staging]\n", APP_SHORT_NAME);
-        fflush(stderr);
-        WAIT_FOR_CONSOLE_DESTROY;
-        exit(1);
-    }
-
-    demo_init_connection(demo);
-    demo_init_vk(demo);
-
-    demo->width = 300;
-    demo->height = 300;
-    demo->format = VK_FORMAT_B8G8R8A8_UNORM;
-}
-
-static void demo_cleanup(struct demo *demo)
-{
-    uint32_t i, j;
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_SET, demo->desc_set);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_POOL, demo->desc_pool);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_COMMAND_BUFFER, demo->cmd);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_VP_STATE, demo->viewport);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_RS_STATE, demo->raster);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_CB_STATE, demo->color_blend);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DYNAMIC_DS_STATE, demo->depth_stencil);
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_PIPELINE, demo->pipeline);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_PIPELINE_LAYOUT, demo->pipeline_layout);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, demo->desc_layout);
-
-    vkQueueBindObjectMemory(demo->queue, VK_OBJECT_TYPE_BUFFER, demo->vertices.buf, 0, VK_NULL_HANDLE, 0);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_BUFFER, demo->vertices.buf);
-    demo_remove_mem_refs(demo, demo->vertices.num_mem, demo->vertices.mem);
-    for (j = 0; j < demo->vertices.num_mem; j++)
-        vkFreeMemory(demo->device, demo->vertices.mem[j]);
-
-    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
-        vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE_VIEW, demo->textures[i].view);
-        vkQueueBindObjectMemory(demo->queue, VK_OBJECT_TYPE_IMAGE, demo->textures[i].image, 0, VK_NULL_HANDLE, 0);
-        vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, demo->textures[i].image);
-        demo_remove_mem_refs(demo, demo->textures[i].num_mem, demo->textures[i].mem);
-        for (j = 0; j < demo->textures[i].num_mem; j++)
-            vkFreeMemory(demo->device, demo->textures[i].mem[j]);
-        free(demo->textures[i].mem);
-        vkDestroyObject(demo->device, VK_OBJECT_TYPE_SAMPLER, demo->textures[i].sampler);
-    }
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_COLOR_ATTACHMENT_VIEW, demo->msaa_color.view);
-    vkQueueBindObjectMemory(demo->queue, VK_OBJECT_TYPE_IMAGE, demo->msaa_color.image, 0, VK_NULL_HANDLE, 0);
-    demo_remove_mem_refs(demo, demo->msaa_color.num_mem, demo->msaa_color.mem);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, demo->msaa_color.image);
-    for (j = 0; j < demo->msaa_color.num_mem; j++) {
-        vkFreeMemory(demo->device, demo->msaa_color.mem[j]);
-    }
-
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_DEPTH_STENCIL_VIEW, demo->msaa_depth.view);
-    vkQueueBindObjectMemory(demo->queue, VK_OBJECT_TYPE_IMAGE, demo->msaa_depth.image, 0, VK_NULL_HANDLE, 0);
-    demo_remove_mem_refs(demo, demo->msaa_depth.num_mem, demo->msaa_depth.mem);
-    vkDestroyObject(demo->device, VK_OBJECT_TYPE_IMAGE, demo->msaa_depth.image);
-    for (j = 0; j < demo->msaa_depth.num_mem; j++) {
-        vkFreeMemory(demo->device, demo->msaa_depth.mem[j]);
-    }
-
-    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
-        demo_remove_mem_refs(demo, 1, &demo->buffers[i].mem);
-    }
-    vkDestroySwapChainWSI(demo->swap_chain);
-
-    vkDestroyDevice(demo->device);
-    vkDestroyInstance(demo->inst);
-
-#ifndef _WIN32
-    xcb_destroy_window(demo->connection, demo->window);
-    xcb_disconnect(demo->connection);
-#endif // _WIN32
-}
-
-#ifdef _WIN32
-// The following function was copied from the Vulkan loader:
-char *get_registry_string(const HKEY hive,
-                          const LPCTSTR sub_key,
-                          const char *value)
-{
-    DWORD access_flags = KEY_QUERY_VALUE;
-    DWORD value_type;
-    HKEY key;
-    VkResult  rtn_value;
-    char *rtn_str = NULL;
-    size_t rtn_len = 0;
-    size_t allocated_len = 0;
-
-    rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
-    if (rtn_value != ERROR_SUCCESS) {
-        // We didn't find the key.  Try the 32-bit hive (where we've seen the
-        // key end up on some people's systems):
-        access_flags |= KEY_WOW64_32KEY;
-        rtn_value = RegOpenKeyEx(hive, sub_key, 0, access_flags, &key);
-        if (rtn_value != ERROR_SUCCESS) {
-            // We still couldn't find the key, so give up:
-            return NULL;
-        }
-    }
-
-    rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
-                                (PVOID) rtn_str, (LPDWORD) &rtn_len);
-    if (rtn_value == ERROR_SUCCESS) {
-        // If we get to here, we found the key, and need to allocate memory
-        // large enough for rtn_str, and query again:
-        allocated_len = rtn_len + 4;
-        rtn_str = malloc(allocated_len);
-        rtn_value = RegQueryValueEx(key, value, NULL, &value_type,
-                                    (PVOID) rtn_str, (LPDWORD) &rtn_len);
-        if (rtn_value == ERROR_SUCCESS) {
-            // We added 4 extra bytes to rtn_str, so that we can ensure that
-            // the string is NULL-terminated (albeit, in a brute-force manner):
-            rtn_str[allocated_len-1] = '\0';
-        } else {
-            // This should never occur, but in case it does, clean up:
-            free(rtn_str);
-            rtn_str = NULL;
-        }
-    } // else - shouldn't happen, but if it does, return rtn_str, which is NULL
-
-    // Close the registry key that was opened:
-    RegCloseKey(key);
-
-    return rtn_str;
-}
-
-
-// The following function was copied from the Vulkan loader:
-static char *get_registry_and_env(const char *env_var,
-                                  const char *registry_value)
-{
-    char *env_str = getenv(env_var);
-    size_t env_len = (env_str == NULL) ? 0 : strlen(env_str);
-    char *registry_str = NULL;
-    DWORD registry_len = 0;
-    char *rtn_str = NULL;
-    size_t rtn_len;
-
-    registry_str = get_registry_string(HKEY_LOCAL_MACHINE,
-                                       "Software\\Vulkan",
-                                       registry_value);
-    registry_len = (registry_str) ? (DWORD) strlen(registry_str) : 0;
-
-    rtn_len = env_len + registry_len + 1;
-    if (rtn_len <= 2) {
-        // We found neither the desired registry value, nor the environment
-        // variable; return NULL:
-        return NULL;
-    } else {
-        // We found something, and so we need to allocate memory for the string
-        // to return:
-        rtn_str = malloc(rtn_len);
-    }
-
-    if (registry_len == 0) {
-        // We didn't find the desired registry value, and so we must have found
-        // only the environment variable:
-        _snprintf(rtn_str, rtn_len, "%s", env_str);
-    } else if (env_str != NULL) {
-        // We found both the desired registry value and the environment
-        // variable, so concatenate them both:
-        _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str);
-    } else {
-        // We must have only found the desired registry value:
-        _snprintf(rtn_str, rtn_len, "%s", registry_str);
-    }
-
-    if (registry_str) {
-      free(registry_str);
-    }
-
-    return(rtn_str);
-}
-
-// Create a console window with a large scrollback size to which to send stdout.
-// Returns true if console window was successfully created, false otherwise.
-bool SetStdOutToNewConsole()
-{
-    // don't do anything if we already have a console
-    if (GetStdHandle(STD_OUTPUT_HANDLE))
-        return false;
-
-    // allocate a console for this app
-    AllocConsole();
-
-    // redirect unbuffered STDOUT to the console
-    HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
-    int fileDescriptor = _open_osfhandle((intptr_t)consoleHandle, _O_TEXT);
-    FILE *fp = _fdopen( fileDescriptor, "w" );
-    *stdout = *fp;
-    setvbuf( stdout, NULL, _IONBF, 0 );
-
-    // make the console window bigger
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-    SMALL_RECT r;
-    COORD bufferSize;
-    if (!GetConsoleScreenBufferInfo(consoleHandle, &csbi))
-        return false;
-    bufferSize.X = csbi.dwSize.X;
-    bufferSize.Y = 1000;
-    if (!SetConsoleScreenBufferSize(consoleHandle, bufferSize))
-        return false;
-    r.Left = r.Top = 0;
-    r.Right = csbi.dwSize.X-1;
-    r.Bottom = 60;
-    if (!SetConsoleWindowInfo(consoleHandle, true, &r))
-        return false;
-
-    // change the console window title
-    if (!SetConsoleTitle(TEXT(APP_SHORT_NAME)))
-        return false;
-
-    return true;
-}
-
-int APIENTRY WinMain(HINSTANCE hInstance,
-                     HINSTANCE hPrevInstance,
-                     LPSTR pCmdLine,
-                     int nCmdShow)
-{
-    MSG msg;         // message
-    bool done;        // flag saying when app is complete
-    char *layers_enabled = get_registry_and_env(LAYER_NAMES_ENV,
-                                                LAYER_NAMES_REGISTRY_VALUE);
-
-    if (layers_enabled != NULL) {
-        consoleCreated = SetStdOutToNewConsole();
-        free(layers_enabled);
-    }
-
-    demo_init(&demo, hInstance, pCmdLine);
-    demo_create_window(&demo);
-
-    demo_prepare(&demo);
-
-    done = false; //initialize loop condition variable
-    /* main message loop*/
-    while(!done)
-    {
-        PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
-        if (msg.message == WM_QUIT) //check for a quit message
-        {
-            done = true; //if found, quit app
-        }
-        else
-        {
-            /* Translate and dispatch to event queue*/
-            TranslateMessage(&msg); 
-            DispatchMessage(&msg);
-        }
-    }
-
-    demo_cleanup(&demo);
-
-    if (consoleCreated) {
-        printf("\nPlease close this window when you are finished looking at "
-               "the console output.\n");
-        fflush(stdout);
-        WAIT_FOR_CONSOLE_DESTROY;
-    }
-
-    return (int) msg.wParam;
-}
-#else  // _WIN32
-int main(const int argc, const char *argv[])
-{
-    struct demo demo;
-
-    demo_init(&demo, argc, argv);
-    demo_create_window(&demo);
-
-    demo_prepare(&demo);
-    demo_run(&demo);
-
-    demo_cleanup(&demo);
-
-    return 0;
-}
-#endif // _WIN32