Home | History | Annotate | Download | only in demos
      1 /*
      2  * Copyright (c) 2015-2016 The Khronos Group Inc.
      3  * Copyright (c) 2015-2016 Valve Corporation
      4  * Copyright (c) 2015-2016 LunarG, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and/or associated documentation files (the "Materials"), to
      8  * deal in the Materials without restriction, including without limitation the
      9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     10  * sell copies of the Materials, and to permit persons to whom the Materials are
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice(s) and this permission notice shall be included in
     14  * all copies or substantial portions of the Materials.
     15  *
     16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     19  *
     20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     23  * USE OR OTHER DEALINGS IN THE MATERIALS.
     24  *
     25  * Author: Chia-I Wu <olv (at) lunarg.com>
     26  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     27  * Author: Ian Elliott <ian (at) LunarG.com>
     28  * Author: Jon Ashburn <jon (at) lunarg.com>
     29  */
     30 
     31 #define _GNU_SOURCE
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <stdbool.h>
     36 #include <assert.h>
     37 #include <signal.h>
     38 
     39 #ifdef _WIN32
     40 #pragma comment(linker, "/subsystem:windows")
     41 #define APP_NAME_STR_LEN 80
     42 #endif // _WIN32
     43 
     44 #include <vulkan/vulkan.h>
     45 
     46 #include <vulkan/vk_sdk_platform.h>
     47 #include "linmath.h"
     48 
     49 #define DEMO_TEXTURE_COUNT 1
     50 #define APP_SHORT_NAME "cube"
     51 #define APP_LONG_NAME "The Vulkan Cube Demo Program"
     52 
     53 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
     54 
     55 #if defined(NDEBUG) && defined(__GNUC__)
     56 #define U_ASSERT_ONLY __attribute__((unused))
     57 #else
     58 #define U_ASSERT_ONLY
     59 #endif
     60 
     61 #ifdef _WIN32
     62 #define ERR_EXIT(err_msg, err_class)                                           \
     63     do {                                                                       \
     64         MessageBox(NULL, err_msg, err_class, MB_OK);                           \
     65         exit(1);                                                               \
     66     } while (0)
     67 
     68 #else // _WIN32
     69 
     70 #define ERR_EXIT(err_msg, err_class)                                           \
     71     do {                                                                       \
     72         printf(err_msg);                                                       \
     73         fflush(stdout);                                                        \
     74         exit(1);                                                               \
     75     } while (0)
     76 #endif // _WIN32
     77 
     78 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                               \
     79     {                                                                          \
     80         demo->fp##entrypoint =                                                 \
     81             (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
     82         if (demo->fp##entrypoint == NULL) {                                    \
     83             ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint,    \
     84                      "vkGetInstanceProcAddr Failure");                         \
     85         }                                                                      \
     86     }
     87 
     88 static PFN_vkGetDeviceProcAddr g_gdpa = NULL;
     89 
     90 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                  \
     91     {                                                                          \
     92         if (!g_gdpa)                                                           \
     93             g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(           \
     94                 demo->inst, "vkGetDeviceProcAddr");                            \
     95         demo->fp##entrypoint =                                                 \
     96             (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint);                 \
     97         if (demo->fp##entrypoint == NULL) {                                    \
     98             ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint,      \
     99                      "vkGetDeviceProcAddr Failure");                           \
    100         }                                                                      \
    101     }
    102 
    103 /*
    104  * structure to track all objects related to a texture.
    105  */
    106 struct texture_object {
    107     VkSampler sampler;
    108 
    109     VkImage image;
    110     VkImageLayout imageLayout;
    111 
    112     VkMemoryAllocateInfo mem_alloc;
    113     VkDeviceMemory mem;
    114     VkImageView view;
    115     int32_t tex_width, tex_height;
    116 };
    117 
    118 static char *tex_files[] = {"lunarg.ppm"};
    119 
    120 static int validation_error = 0;
    121 
    122 struct vkcube_vs_uniform {
    123     // Must start with MVP
    124     float mvp[4][4];
    125     float position[12 * 3][4];
    126     float color[12 * 3][4];
    127 };
    128 
    129 struct vktexcube_vs_uniform {
    130     // Must start with MVP
    131     float mvp[4][4];
    132     float position[12 * 3][4];
    133     float attr[12 * 3][4];
    134 };
    135 
    136 //--------------------------------------------------------------------------------------
    137 // Mesh and VertexFormat Data
    138 //--------------------------------------------------------------------------------------
    139 // clang-format off
    140 struct Vertex
    141 {
    142     float     posX, posY, posZ, posW;    // Position data
    143     float     r, g, b, a;                // Color
    144 };
    145 
    146 struct VertexPosTex
    147 {
    148     float     posX, posY, posZ, posW;    // Position data
    149     float     u, v, s, t;                // Texcoord
    150 };
    151 
    152 #define XYZ1(_x_, _y_, _z_)         (_x_), (_y_), (_z_), 1.f
    153 #define UV(_u_, _v_)                (_u_), (_v_), 0.f, 1.f
    154 
    155 static const float g_vertex_buffer_data[] = {
    156     -1.0f,-1.0f,-1.0f,  // -X side
    157     -1.0f,-1.0f, 1.0f,
    158     -1.0f, 1.0f, 1.0f,
    159     -1.0f, 1.0f, 1.0f,
    160     -1.0f, 1.0f,-1.0f,
    161     -1.0f,-1.0f,-1.0f,
    162 
    163     -1.0f,-1.0f,-1.0f,  // -Z side
    164      1.0f, 1.0f,-1.0f,
    165      1.0f,-1.0f,-1.0f,
    166     -1.0f,-1.0f,-1.0f,
    167     -1.0f, 1.0f,-1.0f,
    168      1.0f, 1.0f,-1.0f,
    169 
    170     -1.0f,-1.0f,-1.0f,  // -Y side
    171      1.0f,-1.0f,-1.0f,
    172      1.0f,-1.0f, 1.0f,
    173     -1.0f,-1.0f,-1.0f,
    174      1.0f,-1.0f, 1.0f,
    175     -1.0f,-1.0f, 1.0f,
    176 
    177     -1.0f, 1.0f,-1.0f,  // +Y side
    178     -1.0f, 1.0f, 1.0f,
    179      1.0f, 1.0f, 1.0f,
    180     -1.0f, 1.0f,-1.0f,
    181      1.0f, 1.0f, 1.0f,
    182      1.0f, 1.0f,-1.0f,
    183 
    184      1.0f, 1.0f,-1.0f,  // +X side
    185      1.0f, 1.0f, 1.0f,
    186      1.0f,-1.0f, 1.0f,
    187      1.0f,-1.0f, 1.0f,
    188      1.0f,-1.0f,-1.0f,
    189      1.0f, 1.0f,-1.0f,
    190 
    191     -1.0f, 1.0f, 1.0f,  // +Z side
    192     -1.0f,-1.0f, 1.0f,
    193      1.0f, 1.0f, 1.0f,
    194     -1.0f,-1.0f, 1.0f,
    195      1.0f,-1.0f, 1.0f,
    196      1.0f, 1.0f, 1.0f,
    197 };
    198 
    199 static const float g_uv_buffer_data[] = {
    200     0.0f, 0.0f,  // -X side
    201     1.0f, 0.0f,
    202     1.0f, 1.0f,
    203     1.0f, 1.0f,
    204     0.0f, 1.0f,
    205     0.0f, 0.0f,
    206 
    207     1.0f, 0.0f,  // -Z side
    208     0.0f, 1.0f,
    209     0.0f, 0.0f,
    210     1.0f, 0.0f,
    211     1.0f, 1.0f,
    212     0.0f, 1.0f,
    213 
    214     1.0f, 1.0f,  // -Y side
    215     1.0f, 0.0f,
    216     0.0f, 0.0f,
    217     1.0f, 1.0f,
    218     0.0f, 0.0f,
    219     0.0f, 1.0f,
    220 
    221     1.0f, 1.0f,  // +Y side
    222     0.0f, 1.0f,
    223     0.0f, 0.0f,
    224     1.0f, 1.0f,
    225     0.0f, 0.0f,
    226     1.0f, 0.0f,
    227 
    228     1.0f, 1.0f,  // +X side
    229     0.0f, 1.0f,
    230     0.0f, 0.0f,
    231     0.0f, 0.0f,
    232     1.0f, 0.0f,
    233     1.0f, 1.0f,
    234 
    235     0.0f, 1.0f,  // +Z side
    236     0.0f, 0.0f,
    237     1.0f, 1.0f,
    238     0.0f, 0.0f,
    239     1.0f, 0.0f,
    240     1.0f, 1.0f,
    241 };
    242 // clang-format on
    243 
    244 void dumpMatrix(const char *note, mat4x4 MVP) {
    245     int i;
    246 
    247     printf("%s: \n", note);
    248     for (i = 0; i < 4; i++) {
    249         printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]);
    250     }
    251     printf("\n");
    252     fflush(stdout);
    253 }
    254 
    255 void dumpVec4(const char *note, vec4 vector) {
    256     printf("%s: \n", note);
    257     printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
    258     printf("\n");
    259     fflush(stdout);
    260 }
    261 
    262 VKAPI_ATTR VkBool32 VKAPI_CALL
    263 dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    264         uint64_t srcObject, size_t location, int32_t msgCode,
    265         const char *pLayerPrefix, const char *pMsg, void *pUserData) {
    266     char *message = (char *)malloc(strlen(pMsg) + 100);
    267 
    268     assert(message);
    269 
    270     if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    271         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode,
    272                 pMsg);
    273         validation_error = 1;
    274     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    275         // We know that we're submitting queues without fences, ignore this
    276         // warning
    277         if (strstr(pMsg,
    278                    "vkQueueSubmit parameter, VkFence fence, is null pointer")) {
    279             return false;
    280         }
    281         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode,
    282                 pMsg);
    283         validation_error = 1;
    284     } else {
    285         validation_error = 1;
    286         return false;
    287     }
    288 
    289 #ifdef _WIN32
    290     MessageBox(NULL, message, "Alert", MB_OK);
    291 #else
    292     printf("%s\n", message);
    293     fflush(stdout);
    294 #endif
    295     free(message);
    296 
    297     /*
    298      * false indicates that layer should not bail-out of an
    299      * API call that had validation failures. This may mean that the
    300      * app dies inside the driver due to invalid parameter(s).
    301      * That's what would happen without validation layers, so we'll
    302      * keep that behavior here.
    303      */
    304     return false;
    305 }
    306 
    307 VkBool32 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    308                        uint64_t srcObject, size_t location, int32_t msgCode,
    309                        const char *pLayerPrefix, const char *pMsg,
    310                        void *pUserData) {
    311 #ifndef WIN32
    312     raise(SIGTRAP);
    313 #else
    314     DebugBreak();
    315 #endif
    316 
    317     return false;
    318 }
    319 
    320 typedef struct _SwapchainBuffers {
    321     VkImage image;
    322     VkCommandBuffer cmd;
    323     VkImageView view;
    324 } SwapchainBuffers;
    325 
    326 struct demo {
    327 #ifdef _WIN32
    328 #define APP_NAME_STR_LEN 80
    329     HINSTANCE connection;        // hInstance - Windows Instance
    330     char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
    331     HWND window;                 // hWnd - window handle
    332 #else                            // _WIN32
    333     xcb_connection_t *connection;
    334     xcb_screen_t *screen;
    335     xcb_window_t window;
    336     xcb_intern_atom_reply_t *atom_wm_delete_window;
    337 #endif                           // _WIN32
    338     VkSurfaceKHR surface;
    339     bool prepared;
    340     bool use_staging_buffer;
    341 
    342     VkInstance inst;
    343     VkPhysicalDevice gpu;
    344     VkDevice device;
    345     VkQueue queue;
    346     uint32_t graphics_queue_node_index;
    347     VkPhysicalDeviceProperties gpu_props;
    348     VkQueueFamilyProperties *queue_props;
    349     VkPhysicalDeviceMemoryProperties memory_properties;
    350 
    351     uint32_t enabled_extension_count;
    352     uint32_t enabled_layer_count;
    353     char *extension_names[64];
    354     char *device_validation_layers[64];
    355 
    356     int width, height;
    357     VkFormat format;
    358     VkColorSpaceKHR color_space;
    359 
    360     PFN_vkGetPhysicalDeviceSurfaceSupportKHR
    361         fpGetPhysicalDeviceSurfaceSupportKHR;
    362     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
    363         fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
    364     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
    365         fpGetPhysicalDeviceSurfaceFormatsKHR;
    366     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
    367         fpGetPhysicalDeviceSurfacePresentModesKHR;
    368     PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
    369     PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
    370     PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
    371     PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
    372     PFN_vkQueuePresentKHR fpQueuePresentKHR;
    373     uint32_t swapchainImageCount;
    374     VkSwapchainKHR swapchain;
    375     SwapchainBuffers *buffers;
    376 
    377     VkCommandPool cmd_pool;
    378 
    379     struct {
    380         VkFormat format;
    381 
    382         VkImage image;
    383         VkMemoryAllocateInfo mem_alloc;
    384         VkDeviceMemory mem;
    385         VkImageView view;
    386     } depth;
    387 
    388     struct texture_object textures[DEMO_TEXTURE_COUNT];
    389 
    390     struct {
    391         VkBuffer buf;
    392         VkMemoryAllocateInfo mem_alloc;
    393         VkDeviceMemory mem;
    394         VkDescriptorBufferInfo buffer_info;
    395     } uniform_data;
    396 
    397     VkCommandBuffer cmd; // Buffer for initialization commands
    398     VkPipelineLayout pipeline_layout;
    399     VkDescriptorSetLayout desc_layout;
    400     VkPipelineCache pipelineCache;
    401     VkRenderPass render_pass;
    402     VkPipeline pipeline;
    403 
    404     mat4x4 projection_matrix;
    405     mat4x4 view_matrix;
    406     mat4x4 model_matrix;
    407 
    408     float spin_angle;
    409     float spin_increment;
    410     bool pause;
    411 
    412     VkShaderModule vert_shader_module;
    413     VkShaderModule frag_shader_module;
    414 
    415     VkDescriptorPool desc_pool;
    416     VkDescriptorSet desc_set;
    417 
    418     VkFramebuffer *framebuffers;
    419 
    420     bool quit;
    421     int32_t curFrame;
    422     int32_t frameCount;
    423     bool validate;
    424     bool use_break;
    425     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
    426     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
    427     VkDebugReportCallbackEXT msg_callback;
    428     PFN_vkDebugReportMessageEXT DebugReportMessage;
    429 
    430     uint32_t current_buffer;
    431     uint32_t queue_count;
    432 };
    433 
    434 // Forward declaration:
    435 static void demo_resize(struct demo *demo);
    436 
    437 static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
    438                                         VkFlags requirements_mask,
    439                                         uint32_t *typeIndex) {
    440     // Search memtypes to find first index with those properties
    441     for (uint32_t i = 0; i < 32; i++) {
    442         if ((typeBits & 1) == 1) {
    443             // Type is available, does it match user properties?
    444             if ((demo->memory_properties.memoryTypes[i].propertyFlags &
    445                  requirements_mask) == requirements_mask) {
    446                 *typeIndex = i;
    447                 return true;
    448             }
    449         }
    450         typeBits >>= 1;
    451     }
    452     // No memory types matched, return failure
    453     return false;
    454 }
    455 
    456 static void demo_flush_init_cmd(struct demo *demo) {
    457     VkResult U_ASSERT_ONLY err;
    458 
    459     if (demo->cmd == VK_NULL_HANDLE)
    460         return;
    461 
    462     err = vkEndCommandBuffer(demo->cmd);
    463     assert(!err);
    464 
    465     const VkCommandBuffer cmd_bufs[] = {demo->cmd};
    466     VkFence nullFence = VK_NULL_HANDLE;
    467     VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
    468                                 .pNext = NULL,
    469                                 .waitSemaphoreCount = 0,
    470                                 .pWaitSemaphores = NULL,
    471                                 .pWaitDstStageMask = NULL,
    472                                 .commandBufferCount = 1,
    473                                 .pCommandBuffers = cmd_bufs,
    474                                 .signalSemaphoreCount = 0,
    475                                 .pSignalSemaphores = NULL};
    476 
    477     err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
    478     assert(!err);
    479 
    480     err = vkQueueWaitIdle(demo->queue);
    481     assert(!err);
    482 
    483     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
    484     demo->cmd = VK_NULL_HANDLE;
    485 }
    486 
    487 static void demo_set_image_layout(struct demo *demo, VkImage image,
    488                                   VkImageAspectFlags aspectMask,
    489                                   VkImageLayout old_image_layout,
    490                                   VkImageLayout new_image_layout,
    491                                   VkAccessFlagBits srcAccessMask) {
    492     VkResult U_ASSERT_ONLY err;
    493 
    494     if (demo->cmd == VK_NULL_HANDLE) {
    495         const VkCommandBufferAllocateInfo cmd = {
    496             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    497             .pNext = NULL,
    498             .commandPool = demo->cmd_pool,
    499             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    500             .commandBufferCount = 1,
    501         };
    502 
    503         err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd);
    504         assert(!err);
    505 
    506         VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
    507             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
    508             .pNext = NULL,
    509             .renderPass = VK_NULL_HANDLE,
    510             .subpass = 0,
    511             .framebuffer = VK_NULL_HANDLE,
    512             .occlusionQueryEnable = VK_FALSE,
    513             .queryFlags = 0,
    514             .pipelineStatistics = 0,
    515         };
    516         VkCommandBufferBeginInfo cmd_buf_info = {
    517             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    518             .pNext = NULL,
    519             .flags = 0,
    520             .pInheritanceInfo = &cmd_buf_hinfo,
    521         };
    522         err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
    523         assert(!err);
    524     }
    525 
    526     VkImageMemoryBarrier image_memory_barrier = {
    527         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    528         .pNext = NULL,
    529         .srcAccessMask = srcAccessMask,
    530         .dstAccessMask = 0,
    531         .oldLayout = old_image_layout,
    532         .newLayout = new_image_layout,
    533         .image = image,
    534         .subresourceRange = {aspectMask, 0, 1, 0, 1}};
    535 
    536     if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
    537         /* Make sure anything that was copying from this image has completed */
    538         image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
    539     }
    540 
    541     if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
    542         image_memory_barrier.dstAccessMask =
    543             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    544     }
    545 
    546     if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
    547         image_memory_barrier.dstAccessMask =
    548             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    549     }
    550 
    551     if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
    552         /* Make sure any Copy or CPU writes to image are flushed */
    553         image_memory_barrier.dstAccessMask =
    554             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
    555     }
    556 
    557     VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
    558 
    559     VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    560     VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    561 
    562     vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, 0, 0, NULL, 0,
    563                          NULL, 1, pmemory_barrier);
    564 }
    565 
    566 static void demo_draw_build_cmd(struct demo *demo, VkCommandBuffer cmd_buf) {
    567     VkCommandBufferInheritanceInfo cmd_buf_hinfo = {
    568         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
    569         .pNext = NULL,
    570         .renderPass = VK_NULL_HANDLE,
    571         .subpass = 0,
    572         .framebuffer = VK_NULL_HANDLE,
    573         .occlusionQueryEnable = VK_FALSE,
    574         .queryFlags = 0,
    575         .pipelineStatistics = 0,
    576     };
    577     const VkCommandBufferBeginInfo cmd_buf_info = {
    578         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    579         .pNext = NULL,
    580         .flags = 0,
    581         .pInheritanceInfo = &cmd_buf_hinfo,
    582     };
    583     const VkClearValue clear_values[2] = {
    584             [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
    585             [1] = {.depthStencil = {1.0f, 0}},
    586     };
    587     const VkRenderPassBeginInfo rp_begin = {
    588         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
    589         .pNext = NULL,
    590         .renderPass = demo->render_pass,
    591         .framebuffer = demo->framebuffers[demo->current_buffer],
    592         .renderArea.offset.x = 0,
    593         .renderArea.offset.y = 0,
    594         .renderArea.extent.width = demo->width,
    595         .renderArea.extent.height = demo->height,
    596         .clearValueCount = 2,
    597         .pClearValues = clear_values,
    598     };
    599     VkResult U_ASSERT_ONLY err;
    600 
    601     err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
    602     assert(!err);
    603 
    604     vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
    605 
    606     vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline);
    607     vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
    608                             demo->pipeline_layout, 0, 1, &demo->desc_set, 0,
    609                             NULL);
    610 
    611     VkViewport viewport;
    612     memset(&viewport, 0, sizeof(viewport));
    613     viewport.height = (float)demo->height;
    614     viewport.width = (float)demo->width;
    615     viewport.minDepth = (float)0.0f;
    616     viewport.maxDepth = (float)1.0f;
    617     vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
    618 
    619     VkRect2D scissor;
    620     memset(&scissor, 0, sizeof(scissor));
    621     scissor.extent.width = demo->width;
    622     scissor.extent.height = demo->height;
    623     scissor.offset.x = 0;
    624     scissor.offset.y = 0;
    625     vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
    626 
    627     vkCmdDraw(cmd_buf, 12 * 3, 1, 0, 0);
    628     vkCmdEndRenderPass(cmd_buf);
    629 
    630     VkImageMemoryBarrier prePresentBarrier = {
    631         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    632         .pNext = NULL,
    633         .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    634         .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
    635         .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    636         .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    637         .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
    638         .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
    639         .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
    640 
    641     prePresentBarrier.image = demo->buffers[demo->current_buffer].image;
    642     VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
    643     vkCmdPipelineBarrier(cmd_buf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
    644                          VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0,
    645                          NULL, 1, pmemory_barrier);
    646 
    647     err = vkEndCommandBuffer(cmd_buf);
    648     assert(!err);
    649 }
    650 
    651 void demo_update_data_buffer(struct demo *demo) {
    652     mat4x4 MVP, Model, VP;
    653     int matrixSize = sizeof(MVP);
    654     uint8_t *pData;
    655     VkResult U_ASSERT_ONLY err;
    656 
    657     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
    658 
    659     // Rotate 22.5 degrees around the Y axis
    660     mat4x4_dup(Model, demo->model_matrix);
    661     mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f,
    662                   (float)degreesToRadians(demo->spin_angle));
    663     mat4x4_mul(MVP, VP, demo->model_matrix);
    664 
    665     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
    666                       demo->uniform_data.mem_alloc.allocationSize, 0,
    667                       (void **)&pData);
    668     assert(!err);
    669 
    670     memcpy(pData, (const void *)&MVP[0][0], matrixSize);
    671 
    672     vkUnmapMemory(demo->device, demo->uniform_data.mem);
    673 }
    674 
    675 static void demo_draw(struct demo *demo) {
    676     VkResult U_ASSERT_ONLY err;
    677     VkSemaphore presentCompleteSemaphore;
    678     VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
    679         .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
    680         .pNext = NULL,
    681         .flags = 0,
    682     };
    683     VkFence nullFence = VK_NULL_HANDLE;
    684 
    685     err = vkCreateSemaphore(demo->device, &presentCompleteSemaphoreCreateInfo,
    686                             NULL, &presentCompleteSemaphore);
    687     assert(!err);
    688 
    689     // Get the index of the next available swapchain image:
    690     err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
    691                                       presentCompleteSemaphore,
    692                                       (VkFence)0, // TODO: Show use of fence
    693                                       &demo->current_buffer);
    694     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    695         // demo->swapchain is out of date (e.g. the window was resized) and
    696         // must be recreated:
    697         demo_resize(demo);
    698         demo_draw(demo);
    699         vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
    700         return;
    701     } else if (err == VK_SUBOPTIMAL_KHR) {
    702         // demo->swapchain is not as optimal as it could be, but the platform's
    703         // presentation engine will still present the image correctly.
    704     } else {
    705         assert(!err);
    706     }
    707 
    708     // Assume the command buffer has been run on current_buffer before so
    709     // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL
    710     demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image,
    711                           VK_IMAGE_ASPECT_COLOR_BIT,
    712                           VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    713                           VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    714                           0);
    715     demo_flush_init_cmd(demo);
    716 
    717     // Wait for the present complete semaphore to be signaled to ensure
    718     // that the image won't be rendered to until the presentation
    719     // engine has fully released ownership to the application, and it is
    720     // okay to render to the image.
    721 
    722     // FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
    723     VkPipelineStageFlags pipe_stage_flags =
    724         VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    725     VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
    726                                 .pNext = NULL,
    727                                 .waitSemaphoreCount = 1,
    728                                 .pWaitSemaphores = &presentCompleteSemaphore,
    729                                 .pWaitDstStageMask = &pipe_stage_flags,
    730                                 .commandBufferCount = 1,
    731                                 .pCommandBuffers =
    732                                     &demo->buffers[demo->current_buffer].cmd,
    733                                 .signalSemaphoreCount = 0,
    734                                 .pSignalSemaphores = NULL};
    735 
    736     err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
    737     assert(!err);
    738 
    739     VkPresentInfoKHR present = {
    740         .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
    741         .pNext = NULL,
    742         .swapchainCount = 1,
    743         .pSwapchains = &demo->swapchain,
    744         .pImageIndices = &demo->current_buffer,
    745     };
    746 
    747     // TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
    748     err = demo->fpQueuePresentKHR(demo->queue, &present);
    749     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    750         // demo->swapchain is out of date (e.g. the window was resized) and
    751         // must be recreated:
    752         demo_resize(demo);
    753     } else if (err == VK_SUBOPTIMAL_KHR) {
    754         // demo->swapchain is not as optimal as it could be, but the platform's
    755         // presentation engine will still present the image correctly.
    756     } else {
    757         assert(!err);
    758     }
    759 
    760     err = vkQueueWaitIdle(demo->queue);
    761     assert(err == VK_SUCCESS);
    762 
    763     vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
    764 }
    765 
    766 static void demo_prepare_buffers(struct demo *demo) {
    767     VkResult U_ASSERT_ONLY err;
    768     VkSwapchainKHR oldSwapchain = demo->swapchain;
    769 
    770     // Check the surface capabilities and formats
    771     VkSurfaceCapabilitiesKHR surfCapabilities;
    772     err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(
    773         demo->gpu, demo->surface, &surfCapabilities);
    774     assert(!err);
    775 
    776     uint32_t presentModeCount;
    777     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
    778         demo->gpu, demo->surface, &presentModeCount, NULL);
    779     assert(!err);
    780     VkPresentModeKHR *presentModes =
    781         (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
    782     assert(presentModes);
    783     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
    784         demo->gpu, demo->surface, &presentModeCount, presentModes);
    785     assert(!err);
    786 
    787     VkExtent2D swapchainExtent;
    788     // width and height are either both -1, or both not -1.
    789     if (surfCapabilities.currentExtent.width == (uint32_t)-1) {
    790         // If the surface size is undefined, the size is set to
    791         // the size of the images requested.
    792         swapchainExtent.width = demo->width;
    793         swapchainExtent.height = demo->height;
    794     } else {
    795         // If the surface size is defined, the swap chain size must match
    796         swapchainExtent = surfCapabilities.currentExtent;
    797         demo->width = surfCapabilities.currentExtent.width;
    798         demo->height = surfCapabilities.currentExtent.height;
    799     }
    800 
    801     // If mailbox mode is available, use it, as is the lowest-latency non-
    802     // tearing mode.  If not, try IMMEDIATE which will usually be available,
    803     // and is fastest (though it tears).  If not, fall back to FIFO which is
    804     // always available.
    805     VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
    806     for (size_t i = 0; i < presentModeCount; i++) {
    807         if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
    808             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
    809             break;
    810         }
    811         if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) &&
    812             (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
    813             swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
    814         }
    815     }
    816 
    817     // Determine the number of VkImage's to use in the swap chain (we desire to
    818     // own only 1 image at a time, besides the images being displayed and
    819     // queued for display):
    820     uint32_t desiredNumberOfSwapchainImages =
    821         surfCapabilities.minImageCount + 1;
    822     if ((surfCapabilities.maxImageCount > 0) &&
    823         (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount)) {
    824         // Application must settle for fewer images than desired:
    825         desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
    826     }
    827 
    828     VkSurfaceTransformFlagsKHR preTransform;
    829     if (surfCapabilities.supportedTransforms &
    830         VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
    831         preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    832     } else {
    833         preTransform = surfCapabilities.currentTransform;
    834     }
    835 
    836     const VkSwapchainCreateInfoKHR swapchain = {
    837         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    838         .pNext = NULL,
    839         .surface = demo->surface,
    840         .minImageCount = desiredNumberOfSwapchainImages,
    841         .imageFormat = demo->format,
    842         .imageColorSpace = demo->color_space,
    843         .imageExtent =
    844             {
    845              .width = swapchainExtent.width, .height = swapchainExtent.height,
    846             },
    847         .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
    848         .preTransform = preTransform,
    849         .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
    850         .imageArrayLayers = 1,
    851         .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
    852         .queueFamilyIndexCount = 0,
    853         .pQueueFamilyIndices = NULL,
    854         .presentMode = swapchainPresentMode,
    855         .oldSwapchain = oldSwapchain,
    856         .clipped = true,
    857     };
    858     uint32_t i;
    859 
    860     err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, NULL,
    861                                      &demo->swapchain);
    862     assert(!err);
    863 
    864     // If we just re-created an existing swapchain, we should destroy the old
    865     // swapchain at this point.
    866     // Note: destroying the swapchain also cleans up all its associated
    867     // presentable images once the platform is done with them.
    868     if (oldSwapchain != VK_NULL_HANDLE) {
    869         demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
    870     }
    871 
    872     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
    873                                         &demo->swapchainImageCount, NULL);
    874     assert(!err);
    875 
    876     VkImage *swapchainImages =
    877         (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage));
    878     assert(swapchainImages);
    879     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
    880                                         &demo->swapchainImageCount,
    881                                         swapchainImages);
    882     assert(!err);
    883 
    884     demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) *
    885                                                demo->swapchainImageCount);
    886     assert(demo->buffers);
    887 
    888     for (i = 0; i < demo->swapchainImageCount; i++) {
    889         VkImageViewCreateInfo color_image_view = {
    890             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
    891             .pNext = NULL,
    892             .format = demo->format,
    893             .components =
    894                 {
    895                  .r = VK_COMPONENT_SWIZZLE_R,
    896                  .g = VK_COMPONENT_SWIZZLE_G,
    897                  .b = VK_COMPONENT_SWIZZLE_B,
    898                  .a = VK_COMPONENT_SWIZZLE_A,
    899                 },
    900             .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
    901                                  .baseMipLevel = 0,
    902                                  .levelCount = 1,
    903                                  .baseArrayLayer = 0,
    904                                  .layerCount = 1},
    905             .viewType = VK_IMAGE_VIEW_TYPE_2D,
    906             .flags = 0,
    907         };
    908 
    909         demo->buffers[i].image = swapchainImages[i];
    910 
    911         // Render loop will expect image to have been used before and in
    912         // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
    913         // layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image
    914         // to that state
    915         demo_set_image_layout(
    916             demo, demo->buffers[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
    917             VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    918             0);
    919 
    920         color_image_view.image = demo->buffers[i].image;
    921 
    922         err = vkCreateImageView(demo->device, &color_image_view, NULL,
    923                                 &demo->buffers[i].view);
    924         assert(!err);
    925     }
    926 
    927     if (NULL != presentModes) {
    928         free(presentModes);
    929     }
    930 }
    931 
    932 static void demo_prepare_depth(struct demo *demo) {
    933     const VkFormat depth_format = VK_FORMAT_D16_UNORM;
    934     const VkImageCreateInfo image = {
    935         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
    936         .pNext = NULL,
    937         .imageType = VK_IMAGE_TYPE_2D,
    938         .format = depth_format,
    939         .extent = {demo->width, demo->height, 1},
    940         .mipLevels = 1,
    941         .arrayLayers = 1,
    942         .samples = VK_SAMPLE_COUNT_1_BIT,
    943         .tiling = VK_IMAGE_TILING_OPTIMAL,
    944         .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
    945         .flags = 0,
    946     };
    947 
    948     VkImageViewCreateInfo view = {
    949         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
    950         .pNext = NULL,
    951         .image = VK_NULL_HANDLE,
    952         .format = depth_format,
    953         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
    954                              .baseMipLevel = 0,
    955                              .levelCount = 1,
    956                              .baseArrayLayer = 0,
    957                              .layerCount = 1},
    958         .flags = 0,
    959         .viewType = VK_IMAGE_VIEW_TYPE_2D,
    960     };
    961 
    962     VkMemoryRequirements mem_reqs;
    963     VkResult U_ASSERT_ONLY err;
    964     bool U_ASSERT_ONLY pass;
    965 
    966     demo->depth.format = depth_format;
    967 
    968     /* create image */
    969     err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image);
    970     assert(!err);
    971 
    972     vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs);
    973     assert(!err);
    974 
    975     demo->depth.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
    976     demo->depth.mem_alloc.pNext = NULL;
    977     demo->depth.mem_alloc.allocationSize = mem_reqs.size;
    978     demo->depth.mem_alloc.memoryTypeIndex = 0;
    979 
    980     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
    981                                        0, /* No requirements */
    982                                        &demo->depth.mem_alloc.memoryTypeIndex);
    983     assert(pass);
    984 
    985     /* allocate memory */
    986     err = vkAllocateMemory(demo->device, &demo->depth.mem_alloc, NULL,
    987                            &demo->depth.mem);
    988     assert(!err);
    989 
    990     /* bind memory */
    991     err =
    992         vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0);
    993     assert(!err);
    994 
    995     demo_set_image_layout(demo, demo->depth.image, VK_IMAGE_ASPECT_DEPTH_BIT,
    996                           VK_IMAGE_LAYOUT_UNDEFINED,
    997                           VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
    998                           0);
    999 
   1000     /* create image view */
   1001     view.image = demo->depth.image;
   1002     err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
   1003     assert(!err);
   1004 }
   1005 
   1006 /* Load a ppm file into memory */
   1007 bool loadTexture(const char *filename, uint8_t *rgba_data,
   1008                  VkSubresourceLayout *layout, int32_t *width, int32_t *height) {
   1009     FILE *fPtr = fopen(filename, "rb");
   1010     char header[256], *cPtr, *tmp;
   1011 
   1012     if (!fPtr)
   1013         return false;
   1014 
   1015     cPtr = fgets(header, 256, fPtr); // P6
   1016     if (cPtr == NULL || strncmp(header, "P6\n", 3)) {
   1017         fclose(fPtr);
   1018         return false;
   1019     }
   1020 
   1021     do {
   1022         cPtr = fgets(header, 256, fPtr);
   1023         if (cPtr == NULL) {
   1024             fclose(fPtr);
   1025             return false;
   1026         }
   1027     } while (!strncmp(header, "#", 1));
   1028 
   1029     sscanf(header, "%u %u", height, width);
   1030     if (rgba_data == NULL) {
   1031         fclose(fPtr);
   1032         return true;
   1033     }
   1034     tmp = fgets(header, 256, fPtr); // Format
   1035     (void)tmp;
   1036     if (cPtr == NULL || strncmp(header, "255\n", 3)) {
   1037         fclose(fPtr);
   1038         return false;
   1039     }
   1040 
   1041     for (int y = 0; y < *height; y++) {
   1042         uint8_t *rowPtr = rgba_data;
   1043         for (int x = 0; x < *width; x++) {
   1044             size_t s = fread(rowPtr, 3, 1, fPtr);
   1045             (void)s;
   1046             rowPtr[3] = 255; /* Alpha of 1 */
   1047             rowPtr += 4;
   1048         }
   1049         rgba_data += layout->rowPitch;
   1050     }
   1051     fclose(fPtr);
   1052     return true;
   1053 }
   1054 
   1055 static void demo_prepare_texture_image(struct demo *demo, const char *filename,
   1056                                        struct texture_object *tex_obj,
   1057                                        VkImageTiling tiling,
   1058                                        VkImageUsageFlags usage,
   1059                                        VkFlags required_props) {
   1060     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
   1061     int32_t tex_width;
   1062     int32_t tex_height;
   1063     VkResult U_ASSERT_ONLY err;
   1064     bool U_ASSERT_ONLY pass;
   1065 
   1066     if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) {
   1067         printf("Failed to load textures\n");
   1068         fflush(stdout);
   1069         exit(1);
   1070     }
   1071 
   1072     tex_obj->tex_width = tex_width;
   1073     tex_obj->tex_height = tex_height;
   1074 
   1075     const VkImageCreateInfo image_create_info = {
   1076         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
   1077         .pNext = NULL,
   1078         .imageType = VK_IMAGE_TYPE_2D,
   1079         .format = tex_format,
   1080         .extent = {tex_width, tex_height, 1},
   1081         .mipLevels = 1,
   1082         .arrayLayers = 1,
   1083         .samples = VK_SAMPLE_COUNT_1_BIT,
   1084         .tiling = tiling,
   1085         .usage = usage,
   1086         .flags = 0,
   1087         .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
   1088     };
   1089 
   1090     VkMemoryRequirements mem_reqs;
   1091 
   1092     err =
   1093         vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image);
   1094     assert(!err);
   1095 
   1096     vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
   1097 
   1098     tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   1099     tex_obj->mem_alloc.pNext = NULL;
   1100     tex_obj->mem_alloc.allocationSize = mem_reqs.size;
   1101     tex_obj->mem_alloc.memoryTypeIndex = 0;
   1102 
   1103     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
   1104                                        required_props,
   1105                                        &tex_obj->mem_alloc.memoryTypeIndex);
   1106     assert(pass);
   1107 
   1108     /* allocate memory */
   1109     err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL,
   1110                            &(tex_obj->mem));
   1111     assert(!err);
   1112 
   1113     /* bind memory */
   1114     err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0);
   1115     assert(!err);
   1116 
   1117     if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
   1118         const VkImageSubresource subres = {
   1119             .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
   1120             .mipLevel = 0,
   1121             .arrayLayer = 0,
   1122         };
   1123         VkSubresourceLayout layout;
   1124         void *data;
   1125 
   1126         vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres,
   1127                                     &layout);
   1128 
   1129         err = vkMapMemory(demo->device, tex_obj->mem, 0,
   1130                           tex_obj->mem_alloc.allocationSize, 0, &data);
   1131         assert(!err);
   1132 
   1133         if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) {
   1134             fprintf(stderr, "Error loading texture: %s\n", filename);
   1135         }
   1136 
   1137         vkUnmapMemory(demo->device, tex_obj->mem);
   1138     }
   1139 
   1140     tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
   1141     demo_set_image_layout(demo, tex_obj->image, VK_IMAGE_ASPECT_COLOR_BIT,
   1142                           VK_IMAGE_LAYOUT_PREINITIALIZED, tex_obj->imageLayout,
   1143                           VK_ACCESS_HOST_WRITE_BIT);
   1144     /* setting the image layout does not reference the actual memory so no need
   1145      * to add a mem ref */
   1146 }
   1147 
   1148 static void demo_destroy_texture_image(struct demo *demo,
   1149                                        struct texture_object *tex_objs) {
   1150     /* clean up staging resources */
   1151     vkFreeMemory(demo->device, tex_objs->mem, NULL);
   1152     vkDestroyImage(demo->device, tex_objs->image, NULL);
   1153 }
   1154 
   1155 static void demo_prepare_textures(struct demo *demo) {
   1156     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
   1157     VkFormatProperties props;
   1158     uint32_t i;
   1159 
   1160     vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
   1161 
   1162     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1163         VkResult U_ASSERT_ONLY err;
   1164 
   1165         if ((props.linearTilingFeatures &
   1166              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
   1167             !demo->use_staging_buffer) {
   1168             /* Device can texture using linear textures */
   1169             demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i],
   1170                                        VK_IMAGE_TILING_LINEAR,
   1171                                        VK_IMAGE_USAGE_SAMPLED_BIT,
   1172                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
   1173         } else if (props.optimalTilingFeatures &
   1174                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
   1175             /* Must use staging buffer to copy linear texture to optimized */
   1176             struct texture_object staging_texture;
   1177 
   1178             memset(&staging_texture, 0, sizeof(staging_texture));
   1179             demo_prepare_texture_image(demo, tex_files[i], &staging_texture,
   1180                                        VK_IMAGE_TILING_LINEAR,
   1181                                        VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
   1182                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
   1183 
   1184             demo_prepare_texture_image(
   1185                 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL,
   1186                 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
   1187                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
   1188 
   1189             demo_set_image_layout(demo, staging_texture.image,
   1190                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1191                                   staging_texture.imageLayout,
   1192                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
   1193                                   0);
   1194 
   1195             demo_set_image_layout(demo, demo->textures[i].image,
   1196                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1197                                   demo->textures[i].imageLayout,
   1198                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
   1199                                   0);
   1200 
   1201             VkImageCopy copy_region = {
   1202                 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
   1203                 .srcOffset = {0, 0, 0},
   1204                 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
   1205                 .dstOffset = {0, 0, 0},
   1206                 .extent = {staging_texture.tex_width,
   1207                            staging_texture.tex_height, 1},
   1208             };
   1209             vkCmdCopyImage(
   1210                 demo->cmd, staging_texture.image,
   1211                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image,
   1212                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
   1213 
   1214             demo_set_image_layout(demo, demo->textures[i].image,
   1215                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1216                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
   1217                                   demo->textures[i].imageLayout,
   1218                                   0);
   1219 
   1220             demo_flush_init_cmd(demo);
   1221 
   1222             demo_destroy_texture_image(demo, &staging_texture);
   1223         } else {
   1224             /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */
   1225             assert(!"No support for R8G8B8A8_UNORM as texture image format");
   1226         }
   1227 
   1228         const VkSamplerCreateInfo sampler = {
   1229             .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
   1230             .pNext = NULL,
   1231             .magFilter = VK_FILTER_NEAREST,
   1232             .minFilter = VK_FILTER_NEAREST,
   1233             .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
   1234             .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1235             .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1236             .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1237             .mipLodBias = 0.0f,
   1238             .anisotropyEnable = VK_FALSE,
   1239             .maxAnisotropy = 1,
   1240             .compareOp = VK_COMPARE_OP_NEVER,
   1241             .minLod = 0.0f,
   1242             .maxLod = 0.0f,
   1243             .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
   1244             .unnormalizedCoordinates = VK_FALSE,
   1245         };
   1246 
   1247         VkImageViewCreateInfo view = {
   1248             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
   1249             .pNext = NULL,
   1250             .image = VK_NULL_HANDLE,
   1251             .viewType = VK_IMAGE_VIEW_TYPE_2D,
   1252             .format = tex_format,
   1253             .components =
   1254                 {
   1255                  VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
   1256                  VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
   1257                 },
   1258             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
   1259             .flags = 0,
   1260         };
   1261 
   1262         /* create sampler */
   1263         err = vkCreateSampler(demo->device, &sampler, NULL,
   1264                               &demo->textures[i].sampler);
   1265         assert(!err);
   1266 
   1267         /* create image view */
   1268         view.image = demo->textures[i].image;
   1269         err = vkCreateImageView(demo->device, &view, NULL,
   1270                                 &demo->textures[i].view);
   1271         assert(!err);
   1272     }
   1273 }
   1274 
   1275 void demo_prepare_cube_data_buffer(struct demo *demo) {
   1276     VkBufferCreateInfo buf_info;
   1277     VkMemoryRequirements mem_reqs;
   1278     uint8_t *pData;
   1279     int i;
   1280     mat4x4 MVP, VP;
   1281     VkResult U_ASSERT_ONLY err;
   1282     bool U_ASSERT_ONLY pass;
   1283     struct vktexcube_vs_uniform data;
   1284 
   1285     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
   1286     mat4x4_mul(MVP, VP, demo->model_matrix);
   1287     memcpy(data.mvp, MVP, sizeof(MVP));
   1288     //    dumpMatrix("MVP", MVP);
   1289 
   1290     for (i = 0; i < 12 * 3; i++) {
   1291         data.position[i][0] = g_vertex_buffer_data[i * 3];
   1292         data.position[i][1] = g_vertex_buffer_data[i * 3 + 1];
   1293         data.position[i][2] = g_vertex_buffer_data[i * 3 + 2];
   1294         data.position[i][3] = 1.0f;
   1295         data.attr[i][0] = g_uv_buffer_data[2 * i];
   1296         data.attr[i][1] = g_uv_buffer_data[2 * i + 1];
   1297         data.attr[i][2] = 0;
   1298         data.attr[i][3] = 0;
   1299     }
   1300 
   1301     memset(&buf_info, 0, sizeof(buf_info));
   1302     buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
   1303     buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
   1304     buf_info.size = sizeof(data);
   1305     err =
   1306         vkCreateBuffer(demo->device, &buf_info, NULL, &demo->uniform_data.buf);
   1307     assert(!err);
   1308 
   1309     vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf,
   1310                                   &mem_reqs);
   1311 
   1312     demo->uniform_data.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   1313     demo->uniform_data.mem_alloc.pNext = NULL;
   1314     demo->uniform_data.mem_alloc.allocationSize = mem_reqs.size;
   1315     demo->uniform_data.mem_alloc.memoryTypeIndex = 0;
   1316 
   1317     pass = memory_type_from_properties(
   1318         demo, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
   1319         &demo->uniform_data.mem_alloc.memoryTypeIndex);
   1320     assert(pass);
   1321 
   1322     err = vkAllocateMemory(demo->device, &demo->uniform_data.mem_alloc, NULL,
   1323                            &(demo->uniform_data.mem));
   1324     assert(!err);
   1325 
   1326     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
   1327                       demo->uniform_data.mem_alloc.allocationSize, 0,
   1328                       (void **)&pData);
   1329     assert(!err);
   1330 
   1331     memcpy(pData, &data, sizeof data);
   1332 
   1333     vkUnmapMemory(demo->device, demo->uniform_data.mem);
   1334 
   1335     err = vkBindBufferMemory(demo->device, demo->uniform_data.buf,
   1336                              demo->uniform_data.mem, 0);
   1337     assert(!err);
   1338 
   1339     demo->uniform_data.buffer_info.buffer = demo->uniform_data.buf;
   1340     demo->uniform_data.buffer_info.offset = 0;
   1341     demo->uniform_data.buffer_info.range = sizeof(data);
   1342 }
   1343 
   1344 static void demo_prepare_descriptor_layout(struct demo *demo) {
   1345     const VkDescriptorSetLayoutBinding layout_bindings[2] = {
   1346             [0] =
   1347                 {
   1348                  .binding = 0,
   1349                  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
   1350                  .descriptorCount = 1,
   1351                  .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
   1352                  .pImmutableSamplers = NULL,
   1353                 },
   1354             [1] =
   1355                 {
   1356                  .binding = 1,
   1357                  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
   1358                  .descriptorCount = DEMO_TEXTURE_COUNT,
   1359                  .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
   1360                  .pImmutableSamplers = NULL,
   1361                 },
   1362     };
   1363     const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
   1364         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
   1365         .pNext = NULL,
   1366         .bindingCount = 2,
   1367         .pBindings = layout_bindings,
   1368     };
   1369     VkResult U_ASSERT_ONLY err;
   1370 
   1371     err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL,
   1372                                       &demo->desc_layout);
   1373     assert(!err);
   1374 
   1375     const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
   1376         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
   1377         .pNext = NULL,
   1378         .setLayoutCount = 1,
   1379         .pSetLayouts = &demo->desc_layout,
   1380     };
   1381 
   1382     err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL,
   1383                                  &demo->pipeline_layout);
   1384     assert(!err);
   1385 }
   1386 
   1387 static void demo_prepare_render_pass(struct demo *demo) {
   1388     const VkAttachmentDescription attachments[2] = {
   1389             [0] =
   1390                 {
   1391                  .format = demo->format,
   1392                  .samples = VK_SAMPLE_COUNT_1_BIT,
   1393                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
   1394                  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
   1395                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
   1396                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1397                  .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
   1398                  .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
   1399                 },
   1400             [1] =
   1401                 {
   1402                  .format = demo->depth.format,
   1403                  .samples = VK_SAMPLE_COUNT_1_BIT,
   1404                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
   1405                  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1406                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
   1407                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1408                  .initialLayout =
   1409                      VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
   1410                  .finalLayout =
   1411                      VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
   1412                 },
   1413     };
   1414     const VkAttachmentReference color_reference = {
   1415         .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
   1416     };
   1417     const VkAttachmentReference depth_reference = {
   1418         .attachment = 1,
   1419         .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
   1420     };
   1421     const VkSubpassDescription subpass = {
   1422         .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
   1423         .flags = 0,
   1424         .inputAttachmentCount = 0,
   1425         .pInputAttachments = NULL,
   1426         .colorAttachmentCount = 1,
   1427         .pColorAttachments = &color_reference,
   1428         .pResolveAttachments = NULL,
   1429         .pDepthStencilAttachment = &depth_reference,
   1430         .preserveAttachmentCount = 0,
   1431         .pPreserveAttachments = NULL,
   1432     };
   1433     const VkRenderPassCreateInfo rp_info = {
   1434         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
   1435         .pNext = NULL,
   1436         .attachmentCount = 2,
   1437         .pAttachments = attachments,
   1438         .subpassCount = 1,
   1439         .pSubpasses = &subpass,
   1440         .dependencyCount = 0,
   1441         .pDependencies = NULL,
   1442     };
   1443     VkResult U_ASSERT_ONLY err;
   1444 
   1445     err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
   1446     assert(!err);
   1447 }
   1448 
   1449 static VkShaderModule
   1450 demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) {
   1451     VkShaderModule module;
   1452     VkShaderModuleCreateInfo moduleCreateInfo;
   1453     VkResult U_ASSERT_ONLY err;
   1454 
   1455     moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   1456     moduleCreateInfo.pNext = NULL;
   1457 
   1458     moduleCreateInfo.codeSize = size;
   1459     moduleCreateInfo.pCode = code;
   1460     moduleCreateInfo.flags = 0;
   1461     err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
   1462     assert(!err);
   1463 
   1464     return module;
   1465 }
   1466 
   1467 char *demo_read_spv(const char *filename, size_t *psize) {
   1468     long int size;
   1469     size_t U_ASSERT_ONLY retval;
   1470     void *shader_code;
   1471 
   1472     FILE *fp = fopen(filename, "rb");
   1473     if (!fp)
   1474         return NULL;
   1475 
   1476     fseek(fp, 0L, SEEK_END);
   1477     size = ftell(fp);
   1478 
   1479     fseek(fp, 0L, SEEK_SET);
   1480 
   1481     shader_code = malloc(size);
   1482     retval = fread(shader_code, size, 1, fp);
   1483     assert(retval == 1);
   1484 
   1485     *psize = size;
   1486 
   1487     fclose(fp);
   1488     return shader_code;
   1489 }
   1490 
   1491 static VkShaderModule demo_prepare_vs(struct demo *demo) {
   1492     void *vertShaderCode;
   1493     size_t size;
   1494 
   1495     vertShaderCode = demo_read_spv("cube-vert.spv", &size);
   1496 
   1497     demo->vert_shader_module =
   1498         demo_prepare_shader_module(demo, vertShaderCode, size);
   1499 
   1500     free(vertShaderCode);
   1501 
   1502     return demo->vert_shader_module;
   1503 }
   1504 
   1505 static VkShaderModule demo_prepare_fs(struct demo *demo) {
   1506     void *fragShaderCode;
   1507     size_t size;
   1508 
   1509     fragShaderCode = demo_read_spv("cube-frag.spv", &size);
   1510 
   1511     demo->frag_shader_module =
   1512         demo_prepare_shader_module(demo, fragShaderCode, size);
   1513 
   1514     free(fragShaderCode);
   1515 
   1516     return demo->frag_shader_module;
   1517 }
   1518 
   1519 static void demo_prepare_pipeline(struct demo *demo) {
   1520     VkGraphicsPipelineCreateInfo pipeline;
   1521     VkPipelineCacheCreateInfo pipelineCache;
   1522     VkPipelineVertexInputStateCreateInfo vi;
   1523     VkPipelineInputAssemblyStateCreateInfo ia;
   1524     VkPipelineRasterizationStateCreateInfo rs;
   1525     VkPipelineColorBlendStateCreateInfo cb;
   1526     VkPipelineDepthStencilStateCreateInfo ds;
   1527     VkPipelineViewportStateCreateInfo vp;
   1528     VkPipelineMultisampleStateCreateInfo ms;
   1529     VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
   1530     VkPipelineDynamicStateCreateInfo dynamicState;
   1531     VkResult U_ASSERT_ONLY err;
   1532 
   1533     memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
   1534     memset(&dynamicState, 0, sizeof dynamicState);
   1535     dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
   1536     dynamicState.pDynamicStates = dynamicStateEnables;
   1537 
   1538     memset(&pipeline, 0, sizeof(pipeline));
   1539     pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
   1540     pipeline.layout = demo->pipeline_layout;
   1541 
   1542     memset(&vi, 0, sizeof(vi));
   1543     vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
   1544 
   1545     memset(&ia, 0, sizeof(ia));
   1546     ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
   1547     ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
   1548 
   1549     memset(&rs, 0, sizeof(rs));
   1550     rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
   1551     rs.polygonMode = VK_POLYGON_MODE_FILL;
   1552     rs.cullMode = VK_CULL_MODE_BACK_BIT;
   1553     rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
   1554     rs.depthClampEnable = VK_FALSE;
   1555     rs.rasterizerDiscardEnable = VK_FALSE;
   1556     rs.depthBiasEnable = VK_FALSE;
   1557 
   1558     memset(&cb, 0, sizeof(cb));
   1559     cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
   1560     VkPipelineColorBlendAttachmentState att_state[1];
   1561     memset(att_state, 0, sizeof(att_state));
   1562     att_state[0].colorWriteMask = 0xf;
   1563     att_state[0].blendEnable = VK_FALSE;
   1564     cb.attachmentCount = 1;
   1565     cb.pAttachments = att_state;
   1566 
   1567     memset(&vp, 0, sizeof(vp));
   1568     vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
   1569     vp.viewportCount = 1;
   1570     dynamicStateEnables[dynamicState.dynamicStateCount++] =
   1571         VK_DYNAMIC_STATE_VIEWPORT;
   1572     vp.scissorCount = 1;
   1573     dynamicStateEnables[dynamicState.dynamicStateCount++] =
   1574         VK_DYNAMIC_STATE_SCISSOR;
   1575 
   1576     memset(&ds, 0, sizeof(ds));
   1577     ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
   1578     ds.depthTestEnable = VK_TRUE;
   1579     ds.depthWriteEnable = VK_TRUE;
   1580     ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
   1581     ds.depthBoundsTestEnable = VK_FALSE;
   1582     ds.back.failOp = VK_STENCIL_OP_KEEP;
   1583     ds.back.passOp = VK_STENCIL_OP_KEEP;
   1584     ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
   1585     ds.stencilTestEnable = VK_FALSE;
   1586     ds.front = ds.back;
   1587 
   1588     memset(&ms, 0, sizeof(ms));
   1589     ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
   1590     ms.pSampleMask = NULL;
   1591     ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
   1592 
   1593     // Two stages: vs and fs
   1594     pipeline.stageCount = 2;
   1595     VkPipelineShaderStageCreateInfo shaderStages[2];
   1596     memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
   1597 
   1598     shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   1599     shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
   1600     shaderStages[0].module = demo_prepare_vs(demo);
   1601     shaderStages[0].pName = "main";
   1602 
   1603     shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   1604     shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
   1605     shaderStages[1].module = demo_prepare_fs(demo);
   1606     shaderStages[1].pName = "main";
   1607 
   1608     memset(&pipelineCache, 0, sizeof(pipelineCache));
   1609     pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
   1610 
   1611     err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL,
   1612                                 &demo->pipelineCache);
   1613     assert(!err);
   1614 
   1615     pipeline.pVertexInputState = &vi;
   1616     pipeline.pInputAssemblyState = &ia;
   1617     pipeline.pRasterizationState = &rs;
   1618     pipeline.pColorBlendState = &cb;
   1619     pipeline.pMultisampleState = &ms;
   1620     pipeline.pViewportState = &vp;
   1621     pipeline.pDepthStencilState = &ds;
   1622     pipeline.pStages = shaderStages;
   1623     pipeline.renderPass = demo->render_pass;
   1624     pipeline.pDynamicState = &dynamicState;
   1625 
   1626     pipeline.renderPass = demo->render_pass;
   1627 
   1628     err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1,
   1629                                     &pipeline, NULL, &demo->pipeline);
   1630     assert(!err);
   1631 
   1632     vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
   1633     vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
   1634 }
   1635 
   1636 static void demo_prepare_descriptor_pool(struct demo *demo) {
   1637     const VkDescriptorPoolSize type_counts[2] = {
   1638             [0] =
   1639                 {
   1640                  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
   1641                  .descriptorCount = 1,
   1642                 },
   1643             [1] =
   1644                 {
   1645                  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
   1646                  .descriptorCount = DEMO_TEXTURE_COUNT,
   1647                 },
   1648     };
   1649     const VkDescriptorPoolCreateInfo descriptor_pool = {
   1650         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
   1651         .pNext = NULL,
   1652         .maxSets = 1,
   1653         .poolSizeCount = 2,
   1654         .pPoolSizes = type_counts,
   1655     };
   1656     VkResult U_ASSERT_ONLY err;
   1657 
   1658     err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL,
   1659                                  &demo->desc_pool);
   1660     assert(!err);
   1661 }
   1662 
   1663 static void demo_prepare_descriptor_set(struct demo *demo) {
   1664     VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
   1665     VkWriteDescriptorSet writes[2];
   1666     VkResult U_ASSERT_ONLY err;
   1667     uint32_t i;
   1668 
   1669     VkDescriptorSetAllocateInfo alloc_info = {
   1670         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
   1671         .pNext = NULL,
   1672         .descriptorPool = demo->desc_pool,
   1673         .descriptorSetCount = 1,
   1674         .pSetLayouts = &demo->desc_layout};
   1675     err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
   1676     assert(!err);
   1677 
   1678     memset(&tex_descs, 0, sizeof(tex_descs));
   1679     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1680         tex_descs[i].sampler = demo->textures[i].sampler;
   1681         tex_descs[i].imageView = demo->textures[i].view;
   1682         tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
   1683     }
   1684 
   1685     memset(&writes, 0, sizeof(writes));
   1686 
   1687     writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
   1688     writes[0].dstSet = demo->desc_set;
   1689     writes[0].descriptorCount = 1;
   1690     writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
   1691     writes[0].pBufferInfo = &demo->uniform_data.buffer_info;
   1692 
   1693     writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
   1694     writes[1].dstSet = demo->desc_set;
   1695     writes[1].dstBinding = 1;
   1696     writes[1].descriptorCount = DEMO_TEXTURE_COUNT;
   1697     writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
   1698     writes[1].pImageInfo = tex_descs;
   1699 
   1700     vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL);
   1701 }
   1702 
   1703 static void demo_prepare_framebuffers(struct demo *demo) {
   1704     VkImageView attachments[2];
   1705     attachments[1] = demo->depth.view;
   1706 
   1707     const VkFramebufferCreateInfo fb_info = {
   1708         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
   1709         .pNext = NULL,
   1710         .renderPass = demo->render_pass,
   1711         .attachmentCount = 2,
   1712         .pAttachments = attachments,
   1713         .width = demo->width,
   1714         .height = demo->height,
   1715         .layers = 1,
   1716     };
   1717     VkResult U_ASSERT_ONLY err;
   1718     uint32_t i;
   1719 
   1720     demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount *
   1721                                                  sizeof(VkFramebuffer));
   1722     assert(demo->framebuffers);
   1723 
   1724     for (i = 0; i < demo->swapchainImageCount; i++) {
   1725         attachments[0] = demo->buffers[i].view;
   1726         err = vkCreateFramebuffer(demo->device, &fb_info, NULL,
   1727                                   &demo->framebuffers[i]);
   1728         assert(!err);
   1729     }
   1730 }
   1731 
   1732 static void demo_prepare(struct demo *demo) {
   1733     VkResult U_ASSERT_ONLY err;
   1734 
   1735     const VkCommandPoolCreateInfo cmd_pool_info = {
   1736         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
   1737         .pNext = NULL,
   1738         .queueFamilyIndex = demo->graphics_queue_node_index,
   1739         .flags = 0,
   1740     };
   1741     err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
   1742                               &demo->cmd_pool);
   1743     assert(!err);
   1744 
   1745     const VkCommandBufferAllocateInfo cmd = {
   1746         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
   1747         .pNext = NULL,
   1748         .commandPool = demo->cmd_pool,
   1749         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
   1750         .commandBufferCount = 1,
   1751     };
   1752 
   1753     demo_prepare_buffers(demo);
   1754     demo_prepare_depth(demo);
   1755     demo_prepare_textures(demo);
   1756     demo_prepare_cube_data_buffer(demo);
   1757 
   1758     demo_prepare_descriptor_layout(demo);
   1759     demo_prepare_render_pass(demo);
   1760     demo_prepare_pipeline(demo);
   1761 
   1762     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
   1763         err =
   1764             vkAllocateCommandBuffers(demo->device, &cmd, &demo->buffers[i].cmd);
   1765         assert(!err);
   1766     }
   1767 
   1768     demo_prepare_descriptor_pool(demo);
   1769     demo_prepare_descriptor_set(demo);
   1770 
   1771     demo_prepare_framebuffers(demo);
   1772 
   1773     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
   1774         demo->current_buffer = i;
   1775         demo_draw_build_cmd(demo, demo->buffers[i].cmd);
   1776     }
   1777 
   1778     /*
   1779      * Prepare functions above may generate pipeline commands
   1780      * that need to be flushed before beginning the render loop.
   1781      */
   1782     demo_flush_init_cmd(demo);
   1783 
   1784     demo->current_buffer = 0;
   1785     demo->prepared = true;
   1786 }
   1787 
   1788 static void demo_cleanup(struct demo *demo) {
   1789     uint32_t i;
   1790 
   1791     demo->prepared = false;
   1792 
   1793     for (i = 0; i < demo->swapchainImageCount; i++) {
   1794         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
   1795     }
   1796     free(demo->framebuffers);
   1797     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
   1798 
   1799     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
   1800     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
   1801     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
   1802     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
   1803     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
   1804 
   1805     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1806         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
   1807         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
   1808         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
   1809         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
   1810     }
   1811     demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
   1812 
   1813     vkDestroyImageView(demo->device, demo->depth.view, NULL);
   1814     vkDestroyImage(demo->device, demo->depth.image, NULL);
   1815     vkFreeMemory(demo->device, demo->depth.mem, NULL);
   1816 
   1817     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
   1818     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
   1819 
   1820     for (i = 0; i < demo->swapchainImageCount; i++) {
   1821         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
   1822         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
   1823                              &demo->buffers[i].cmd);
   1824     }
   1825     free(demo->buffers);
   1826 
   1827     free(demo->queue_props);
   1828 
   1829     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
   1830     vkDestroyDevice(demo->device, NULL);
   1831     if (demo->validate) {
   1832         demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
   1833     }
   1834     vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
   1835     vkDestroyInstance(demo->inst, NULL);
   1836 
   1837 #ifndef _WIN32
   1838     xcb_destroy_window(demo->connection, demo->window);
   1839     xcb_disconnect(demo->connection);
   1840     free(demo->atom_wm_delete_window);
   1841 #endif // _WIN32
   1842 }
   1843 
   1844 static void demo_resize(struct demo *demo) {
   1845     uint32_t i;
   1846 
   1847     // Don't react to resize until after first initialization.
   1848     if (!demo->prepared) {
   1849         return;
   1850     }
   1851     // In order to properly resize the window, we must re-create the swapchain
   1852     // AND redo the command buffers, etc.
   1853     //
   1854     // First, perform part of the demo_cleanup() function:
   1855     demo->prepared = false;
   1856 
   1857     for (i = 0; i < demo->swapchainImageCount; i++) {
   1858         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
   1859     }
   1860     free(demo->framebuffers);
   1861     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
   1862 
   1863     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
   1864     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
   1865     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
   1866     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
   1867     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
   1868 
   1869     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1870         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
   1871         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
   1872         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
   1873         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
   1874     }
   1875 
   1876     vkDestroyImageView(demo->device, demo->depth.view, NULL);
   1877     vkDestroyImage(demo->device, demo->depth.image, NULL);
   1878     vkFreeMemory(demo->device, demo->depth.mem, NULL);
   1879 
   1880     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
   1881     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
   1882 
   1883     for (i = 0; i < demo->swapchainImageCount; i++) {
   1884         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
   1885         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
   1886                              &demo->buffers[i].cmd);
   1887     }
   1888     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
   1889     free(demo->buffers);
   1890 
   1891     // Second, re-perform the demo_prepare() function, which will re-create the
   1892     // swapchain:
   1893     demo_prepare(demo);
   1894 }
   1895 
   1896 // On MS-Windows, make this a global, so it's available to WndProc()
   1897 struct demo demo;
   1898 
   1899 #ifdef _WIN32
   1900 static void demo_run(struct demo *demo) {
   1901     if (!demo->prepared)
   1902         return;
   1903     // Wait for work to finish before updating MVP.
   1904     vkDeviceWaitIdle(demo->device);
   1905     demo_update_data_buffer(demo);
   1906 
   1907     demo_draw(demo);
   1908 
   1909     // Wait for work to finish before updating MVP.
   1910     vkDeviceWaitIdle(demo->device);
   1911 
   1912     demo->curFrame++;
   1913 
   1914     if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) {
   1915         demo->quit = true;
   1916         demo_cleanup(demo);
   1917         ExitProcess(0);
   1918     }
   1919 }
   1920 
   1921 // MS-Windows event handling function:
   1922 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
   1923     switch (uMsg) {
   1924     case WM_CLOSE:
   1925         PostQuitMessage(validation_error);
   1926         break;
   1927     case WM_PAINT:
   1928         demo_run(&demo);
   1929         break;
   1930     case WM_SIZE:
   1931         // Resize the application to the new window size, except when
   1932         // it was minimized. Vulkan doesn't support images or swapchains
   1933         // with width=0 and height=0.
   1934         if (wParam != SIZE_MINIMIZED) {
   1935             demo.width = lParam & 0xffff;
   1936             demo.height = lParam & 0xffff0000 >> 16;
   1937             demo_resize(&demo);
   1938         }
   1939         break;
   1940     default:
   1941         break;
   1942     }
   1943     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
   1944 }
   1945 
   1946 static void demo_create_window(struct demo *demo) {
   1947     WNDCLASSEX win_class;
   1948 
   1949     // Initialize the window class structure:
   1950     win_class.cbSize = sizeof(WNDCLASSEX);
   1951     win_class.style = CS_HREDRAW | CS_VREDRAW;
   1952     win_class.lpfnWndProc = WndProc;
   1953     win_class.cbClsExtra = 0;
   1954     win_class.cbWndExtra = 0;
   1955     win_class.hInstance = demo->connection; // hInstance
   1956     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   1957     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
   1958     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
   1959     win_class.lpszMenuName = NULL;
   1960     win_class.lpszClassName = demo->name;
   1961     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
   1962     // Register window class:
   1963     if (!RegisterClassEx(&win_class)) {
   1964         // It didn't work, so try to give a useful error:
   1965         printf("Unexpected error trying to start the application!\n");
   1966         fflush(stdout);
   1967         exit(1);
   1968     }
   1969     // Create window with the registered class:
   1970     RECT wr = {0, 0, demo->width, demo->height};
   1971     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
   1972     demo->window = CreateWindowEx(0,
   1973                                   demo->name,           // class name
   1974                                   demo->name,           // app name
   1975                                   WS_OVERLAPPEDWINDOW | // window style
   1976                                       WS_VISIBLE | WS_SYSMENU,
   1977                                   100, 100,           // x/y coords
   1978                                   wr.right - wr.left, // width
   1979                                   wr.bottom - wr.top, // height
   1980                                   NULL,               // handle to parent
   1981                                   NULL,               // handle to menu
   1982                                   demo->connection,   // hInstance
   1983                                   NULL);              // no extra parameters
   1984     if (!demo->window) {
   1985         // It didn't work, so try to give a useful error:
   1986         printf("Cannot create a window in which to draw!\n");
   1987         fflush(stdout);
   1988         exit(1);
   1989     }
   1990 }
   1991 #else  // _WIN32
   1992 static void demo_handle_event(struct demo *demo,
   1993                               const xcb_generic_event_t *event) {
   1994     uint8_t event_code = event->response_type & 0x7f;
   1995     switch (event_code) {
   1996     case XCB_EXPOSE:
   1997         // TODO: Resize window
   1998         break;
   1999     case XCB_CLIENT_MESSAGE:
   2000         if ((*(xcb_client_message_event_t *)event).data.data32[0] ==
   2001             (*demo->atom_wm_delete_window).atom) {
   2002             demo->quit = true;
   2003         }
   2004         break;
   2005     case XCB_KEY_RELEASE: {
   2006         const xcb_key_release_event_t *key =
   2007             (const xcb_key_release_event_t *)event;
   2008 
   2009         switch (key->detail) {
   2010         case 0x9: // Escape
   2011             demo->quit = true;
   2012             break;
   2013         case 0x71: // left arrow key
   2014             demo->spin_angle += demo->spin_increment;
   2015             break;
   2016         case 0x72: // right arrow key
   2017             demo->spin_angle -= demo->spin_increment;
   2018             break;
   2019         case 0x41:
   2020             demo->pause = !demo->pause;
   2021             break;
   2022         }
   2023     } break;
   2024     case XCB_CONFIGURE_NOTIFY: {
   2025         const xcb_configure_notify_event_t *cfg =
   2026             (const xcb_configure_notify_event_t *)event;
   2027         if ((demo->width != cfg->width) || (demo->height != cfg->height)) {
   2028             demo->width = cfg->width;
   2029             demo->height = cfg->height;
   2030             demo_resize(demo);
   2031         }
   2032     } break;
   2033     default:
   2034         break;
   2035     }
   2036 }
   2037 
   2038 static void demo_run(struct demo *demo) {
   2039     xcb_flush(demo->connection);
   2040 
   2041     while (!demo->quit) {
   2042         xcb_generic_event_t *event;
   2043 
   2044         if (demo->pause) {
   2045             event = xcb_wait_for_event(demo->connection);
   2046         } else {
   2047             event = xcb_poll_for_event(demo->connection);
   2048         }
   2049         if (event) {
   2050             demo_handle_event(demo, event);
   2051             free(event);
   2052         }
   2053 
   2054         // Wait for work to finish before updating MVP.
   2055         vkDeviceWaitIdle(demo->device);
   2056         demo_update_data_buffer(demo);
   2057 
   2058         demo_draw(demo);
   2059 
   2060         // Wait for work to finish before updating MVP.
   2061         vkDeviceWaitIdle(demo->device);
   2062         demo->curFrame++;
   2063         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
   2064             demo->quit = true;
   2065     }
   2066 }
   2067 
   2068 static void demo_create_window(struct demo *demo) {
   2069     uint32_t value_mask, value_list[32];
   2070 
   2071     demo->window = xcb_generate_id(demo->connection);
   2072 
   2073     value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
   2074     value_list[0] = demo->screen->black_pixel;
   2075     value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
   2076                     XCB_EVENT_MASK_STRUCTURE_NOTIFY;
   2077 
   2078     xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, demo->window,
   2079                       demo->screen->root, 0, 0, demo->width, demo->height, 0,
   2080                       XCB_WINDOW_CLASS_INPUT_OUTPUT, demo->screen->root_visual,
   2081                       value_mask, value_list);
   2082 
   2083     /* Magic code that will send notification when window is destroyed */
   2084     xcb_intern_atom_cookie_t cookie =
   2085         xcb_intern_atom(demo->connection, 1, 12, "WM_PROTOCOLS");
   2086     xcb_intern_atom_reply_t *reply =
   2087         xcb_intern_atom_reply(demo->connection, cookie, 0);
   2088 
   2089     xcb_intern_atom_cookie_t cookie2 =
   2090         xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
   2091     demo->atom_wm_delete_window =
   2092         xcb_intern_atom_reply(demo->connection, cookie2, 0);
   2093 
   2094     xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, demo->window,
   2095                         (*reply).atom, 4, 32, 1,
   2096                         &(*demo->atom_wm_delete_window).atom);
   2097     free(reply);
   2098 
   2099     xcb_map_window(demo->connection, demo->window);
   2100 
   2101     // Force the x/y coordinates to 100,100 results are identical in consecutive
   2102     // runs
   2103     const uint32_t coords[] = {100, 100};
   2104     xcb_configure_window(demo->connection, demo->window,
   2105                          XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
   2106 }
   2107 #endif // _WIN32
   2108 
   2109 /*
   2110  * Return 1 (true) if all layer names specified in check_names
   2111  * can be found in given layer properties.
   2112  */
   2113 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
   2114                                   uint32_t layer_count,
   2115                                   VkLayerProperties *layers) {
   2116     for (uint32_t i = 0; i < check_count; i++) {
   2117         VkBool32 found = 0;
   2118         for (uint32_t j = 0; j < layer_count; j++) {
   2119             if (!strcmp(check_names[i], layers[j].layerName)) {
   2120                 found = 1;
   2121                 break;
   2122             }
   2123         }
   2124         if (!found) {
   2125             fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
   2126             return 0;
   2127         }
   2128     }
   2129     return 1;
   2130 }
   2131 
   2132 static void demo_init_vk(struct demo *demo) {
   2133     VkResult err;
   2134     char *extension_names[64];
   2135     uint32_t instance_extension_count = 0;
   2136     uint32_t instance_layer_count = 0;
   2137     uint32_t device_validation_layer_count = 0;
   2138     uint32_t enabled_extension_count = 0;
   2139     uint32_t enabled_layer_count = 0;
   2140 
   2141     char *instance_validation_layers[] = {
   2142         "VK_LAYER_GOOGLE_threading",     "VK_LAYER_LUNARG_parameter_validation",
   2143         "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
   2144         "VK_LAYER_LUNARG_image",         "VK_LAYER_LUNARG_core_validation",
   2145         "VK_LAYER_LUNARG_swapchain",
   2146         "VK_LAYER_GOOGLE_unique_objects"
   2147     };
   2148 
   2149     demo->device_validation_layers[0] = "VK_LAYER_GOOGLE_threading";
   2150     demo->device_validation_layers[1] = "VK_LAYER_LUNARG_parameter_validation";
   2151     demo->device_validation_layers[2] = "VK_LAYER_LUNARG_device_limits";
   2152     demo->device_validation_layers[3] = "VK_LAYER_LUNARG_object_tracker";
   2153     demo->device_validation_layers[4] = "VK_LAYER_LUNARG_image";
   2154     demo->device_validation_layers[5] = "VK_LAYER_LUNARG_core_validation";
   2155     demo->device_validation_layers[6] = "VK_LAYER_LUNARG_swapchain";
   2156     demo->device_validation_layers[7] = "VK_LAYER_GOOGLE_unique_objects";
   2157     device_validation_layer_count = 8;
   2158 
   2159     /* Look for validation layers */
   2160     VkBool32 validation_found = 0;
   2161     err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
   2162     assert(!err);
   2163 
   2164     if (instance_layer_count > 0) {
   2165         VkLayerProperties *instance_layers =
   2166             malloc(sizeof(VkLayerProperties) * instance_layer_count);
   2167         err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
   2168                                                  instance_layers);
   2169         assert(!err);
   2170 
   2171         if (demo->validate) {
   2172             validation_found = demo_check_layers(
   2173                 ARRAY_SIZE(instance_validation_layers),
   2174                 instance_validation_layers, instance_layer_count,
   2175                 instance_layers);
   2176 
   2177             enabled_layer_count = ARRAY_SIZE(instance_validation_layers);
   2178         }
   2179 
   2180         free(instance_layers);
   2181     }
   2182 
   2183     if (demo->validate && !validation_found) {
   2184         ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
   2185                  "required validation layer.\n\n"
   2186                  "Please look at the Getting Started guide for additional "
   2187                  "information.\n",
   2188                  "vkCreateInstance Failure");
   2189     }
   2190 
   2191     /* Look for instance extensions */
   2192     VkBool32 surfaceExtFound = 0;
   2193     VkBool32 platformSurfaceExtFound = 0;
   2194     memset(extension_names, 0, sizeof(extension_names));
   2195 
   2196     err = vkEnumerateInstanceExtensionProperties(
   2197         NULL, &instance_extension_count, NULL);
   2198     assert(!err);
   2199 
   2200     if (instance_extension_count > 0) {
   2201         VkExtensionProperties *instance_extensions =
   2202             malloc(sizeof(VkExtensionProperties) * instance_extension_count);
   2203         err = vkEnumerateInstanceExtensionProperties(
   2204             NULL, &instance_extension_count, instance_extensions);
   2205         assert(!err);
   2206         for (uint32_t i = 0; i < instance_extension_count; i++) {
   2207             if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
   2208                         instance_extensions[i].extensionName)) {
   2209                 surfaceExtFound = 1;
   2210                 extension_names[enabled_extension_count++] =
   2211                     VK_KHR_SURFACE_EXTENSION_NAME;
   2212             }
   2213 #ifdef _WIN32
   2214             if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
   2215                         instance_extensions[i].extensionName)) {
   2216                 platformSurfaceExtFound = 1;
   2217                 extension_names[enabled_extension_count++] =
   2218                     VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
   2219             }
   2220 #else  // _WIN32
   2221             if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
   2222                         instance_extensions[i].extensionName)) {
   2223                 platformSurfaceExtFound = 1;
   2224                 extension_names[enabled_extension_count++] =
   2225                     VK_KHR_XCB_SURFACE_EXTENSION_NAME;
   2226             }
   2227 #endif // _WIN32
   2228             if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
   2229                         instance_extensions[i].extensionName)) {
   2230                 if (demo->validate) {
   2231                     extension_names[enabled_extension_count++] =
   2232                         VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
   2233                 }
   2234             }
   2235             assert(enabled_extension_count < 64);
   2236         }
   2237 
   2238         free(instance_extensions);
   2239     }
   2240 
   2241     if (!surfaceExtFound) {
   2242         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2243                  "the " VK_KHR_SURFACE_EXTENSION_NAME
   2244                  " extension.\n\nDo you have a compatible "
   2245                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2246                  "look at the Getting Started guide for additional "
   2247                  "information.\n",
   2248                  "vkCreateInstance Failure");
   2249     }
   2250     if (!platformSurfaceExtFound) {
   2251 #ifdef _WIN32
   2252         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2253                  "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
   2254                  " extension.\n\nDo you have a compatible "
   2255                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2256                  "look at the Getting Started guide for additional "
   2257                  "information.\n",
   2258                  "vkCreateInstance Failure");
   2259 #else  // _WIN32
   2260         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2261                  "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME
   2262                  " extension.\n\nDo you have a compatible "
   2263                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2264                  "look at the Getting Started guide for additional "
   2265                  "information.\n",
   2266                  "vkCreateInstance Failure");
   2267 #endif // _WIN32
   2268     }
   2269     const VkApplicationInfo app = {
   2270         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
   2271         .pNext = NULL,
   2272         .pApplicationName = APP_SHORT_NAME,
   2273         .applicationVersion = 0,
   2274         .pEngineName = APP_SHORT_NAME,
   2275         .engineVersion = 0,
   2276         .apiVersion = VK_API_VERSION_1_0,
   2277     };
   2278     VkInstanceCreateInfo inst_info = {
   2279         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
   2280         .pNext = NULL,
   2281         .pApplicationInfo = &app,
   2282         .enabledLayerCount = enabled_layer_count,
   2283         .ppEnabledLayerNames =
   2284             (const char *const *)((demo->validate) ? instance_validation_layers
   2285                                                    : NULL),
   2286         .enabledExtensionCount = enabled_extension_count,
   2287         .ppEnabledExtensionNames = (const char *const *)extension_names,
   2288     };
   2289 
   2290     uint32_t gpu_count;
   2291 
   2292     err = vkCreateInstance(&inst_info, NULL, &demo->inst);
   2293     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
   2294         ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
   2295                  "(ICD).\n\nPlease look at the Getting Started guide for "
   2296                  "additional information.\n",
   2297                  "vkCreateInstance Failure");
   2298     } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
   2299         ERR_EXIT("Cannot find a specified extension library"
   2300                  ".\nMake sure your layers path is set appropriately.\n",
   2301                  "vkCreateInstance Failure");
   2302     } else if (err) {
   2303         ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
   2304                  "installable client driver (ICD) installed?\nPlease look at "
   2305                  "the Getting Started guide for additional information.\n",
   2306                  "vkCreateInstance Failure");
   2307     }
   2308 
   2309     /* Make initial call to query gpu_count, then second call for gpu info*/
   2310     err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
   2311     assert(!err && gpu_count > 0);
   2312 
   2313     if (gpu_count > 0) {
   2314         VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
   2315         err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
   2316         assert(!err);
   2317         /* For cube demo we just grab the first physical device */
   2318         demo->gpu = physical_devices[0];
   2319         free(physical_devices);
   2320     } else {
   2321         ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
   2322                  "Do you have a compatible Vulkan installable client driver (ICD) "
   2323                  "installed?\nPlease look at the Getting Started guide for "
   2324                  "additional information.\n",
   2325                  "vkEnumeratePhysicalDevices Failure");
   2326     }
   2327 
   2328     /* Look for validation layers */
   2329     validation_found = 0;
   2330     demo->enabled_layer_count = 0;
   2331     uint32_t device_layer_count = 0;
   2332     err =
   2333         vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
   2334     assert(!err);
   2335 
   2336     if (device_layer_count > 0) {
   2337         VkLayerProperties *device_layers =
   2338             malloc(sizeof(VkLayerProperties) * device_layer_count);
   2339         err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
   2340                                                device_layers);
   2341         assert(!err);
   2342 
   2343         if (demo->validate) {
   2344             validation_found = demo_check_layers(device_validation_layer_count,
   2345                                                  demo->device_validation_layers,
   2346                                                  device_layer_count,
   2347                                                  device_layers);
   2348             demo->enabled_layer_count = device_validation_layer_count;
   2349         }
   2350 
   2351         free(device_layers);
   2352     }
   2353 
   2354     if (demo->validate && !validation_found) {
   2355         ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find"
   2356                  "a required validation layer.\n\n"
   2357                  "Please look at the Getting Started guide for additional "
   2358                  "information.\n",
   2359                  "vkCreateDevice Failure");
   2360     }
   2361 
   2362     /* Look for device extensions */
   2363     uint32_t device_extension_count = 0;
   2364     VkBool32 swapchainExtFound = 0;
   2365     demo->enabled_extension_count = 0;
   2366     memset(extension_names, 0, sizeof(extension_names));
   2367 
   2368     err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
   2369                                                &device_extension_count, NULL);
   2370     assert(!err);
   2371 
   2372     if (device_extension_count > 0) {
   2373         VkExtensionProperties *device_extensions =
   2374             malloc(sizeof(VkExtensionProperties) * device_extension_count);
   2375         err = vkEnumerateDeviceExtensionProperties(
   2376             demo->gpu, NULL, &device_extension_count, device_extensions);
   2377         assert(!err);
   2378 
   2379         for (uint32_t i = 0; i < device_extension_count; i++) {
   2380             if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
   2381                         device_extensions[i].extensionName)) {
   2382                 swapchainExtFound = 1;
   2383                 demo->extension_names[demo->enabled_extension_count++] =
   2384                     VK_KHR_SWAPCHAIN_EXTENSION_NAME;
   2385             }
   2386             assert(demo->enabled_extension_count < 64);
   2387         }
   2388 
   2389         free(device_extensions);
   2390     }
   2391 
   2392     if (!swapchainExtFound) {
   2393         ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
   2394                  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
   2395                  " extension.\n\nDo you have a compatible "
   2396                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2397                  "look at the Getting Started guide for additional "
   2398                  "information.\n",
   2399                  "vkCreateInstance Failure");
   2400     }
   2401 
   2402     if (demo->validate) {
   2403         demo->CreateDebugReportCallback =
   2404             (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
   2405                 demo->inst, "vkCreateDebugReportCallbackEXT");
   2406         demo->DestroyDebugReportCallback =
   2407             (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
   2408                 demo->inst, "vkDestroyDebugReportCallbackEXT");
   2409         if (!demo->CreateDebugReportCallback) {
   2410             ERR_EXIT(
   2411                 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
   2412                 "vkGetProcAddr Failure");
   2413         }
   2414         if (!demo->DestroyDebugReportCallback) {
   2415             ERR_EXIT(
   2416                 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
   2417                 "vkGetProcAddr Failure");
   2418         }
   2419         demo->DebugReportMessage =
   2420             (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
   2421                 demo->inst, "vkDebugReportMessageEXT");
   2422         if (!demo->DebugReportMessage) {
   2423             ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
   2424                      "vkGetProcAddr Failure");
   2425         }
   2426 
   2427         PFN_vkDebugReportCallbackEXT callback;
   2428 
   2429         if (!demo->use_break) {
   2430             callback = dbgFunc;
   2431         } else {
   2432             callback = dbgFunc;
   2433             // TODO add a break callback defined locally since there is no
   2434             // longer
   2435             // one included in the loader
   2436         }
   2437         VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
   2438         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
   2439         dbgCreateInfo.pNext = NULL;
   2440         dbgCreateInfo.pfnCallback = callback;
   2441         dbgCreateInfo.pUserData = NULL;
   2442         dbgCreateInfo.flags =
   2443             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
   2444         err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
   2445                                               &demo->msg_callback);
   2446         switch (err) {
   2447         case VK_SUCCESS:
   2448             break;
   2449         case VK_ERROR_OUT_OF_HOST_MEMORY:
   2450             ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
   2451                      "CreateDebugReportCallback Failure");
   2452             break;
   2453         default:
   2454             ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
   2455                      "CreateDebugReportCallback Failure");
   2456             break;
   2457         }
   2458     }
   2459     vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
   2460 
   2461     /* Call with NULL data to get count */
   2462     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
   2463                                              NULL);
   2464     assert(demo->queue_count >= 1);
   2465 
   2466     demo->queue_props = (VkQueueFamilyProperties *)malloc(
   2467         demo->queue_count * sizeof(VkQueueFamilyProperties));
   2468     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
   2469                                              demo->queue_props);
   2470     // Find a queue that supports gfx
   2471     uint32_t gfx_queue_idx = 0;
   2472     for (gfx_queue_idx = 0; gfx_queue_idx < demo->queue_count;
   2473          gfx_queue_idx++) {
   2474         if (demo->queue_props[gfx_queue_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
   2475             break;
   2476     }
   2477     assert(gfx_queue_idx < demo->queue_count);
   2478     // Query fine-grained feature support for this device.
   2479     //  If app has specific feature requirements it should check supported
   2480     //  features based on this query
   2481     VkPhysicalDeviceFeatures physDevFeatures;
   2482     vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures);
   2483 
   2484     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
   2485     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
   2486     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
   2487     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
   2488     GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
   2489 }
   2490 
   2491 static void demo_create_device(struct demo *demo) {
   2492     VkResult U_ASSERT_ONLY err;
   2493     float queue_priorities[1] = {0.0};
   2494     const VkDeviceQueueCreateInfo queue = {
   2495         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
   2496         .pNext = NULL,
   2497         .queueFamilyIndex = demo->graphics_queue_node_index,
   2498         .queueCount = 1,
   2499         .pQueuePriorities = queue_priorities};
   2500 
   2501     VkDeviceCreateInfo device = {
   2502         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
   2503         .pNext = NULL,
   2504         .queueCreateInfoCount = 1,
   2505         .pQueueCreateInfos = &queue,
   2506         .enabledLayerCount = demo->enabled_layer_count,
   2507         .ppEnabledLayerNames =
   2508             (const char *const *)((demo->validate)
   2509                                       ? demo->device_validation_layers
   2510                                       : NULL),
   2511         .enabledExtensionCount = demo->enabled_extension_count,
   2512         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
   2513         .pEnabledFeatures =
   2514             NULL, // If specific features are required, pass them in here
   2515     };
   2516 
   2517     err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
   2518     assert(!err);
   2519 }
   2520 
   2521 static void demo_init_vk_swapchain(struct demo *demo) {
   2522     VkResult U_ASSERT_ONLY err;
   2523     uint32_t i;
   2524 
   2525 // Create a WSI surface for the window:
   2526 #ifdef _WIN32
   2527     VkWin32SurfaceCreateInfoKHR createInfo;
   2528     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
   2529     createInfo.pNext = NULL;
   2530     createInfo.flags = 0;
   2531     createInfo.hinstance = demo->connection;
   2532     createInfo.hwnd = demo->window;
   2533 
   2534     err =
   2535         vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
   2536 
   2537 #else  // _WIN32
   2538     VkXcbSurfaceCreateInfoKHR createInfo;
   2539     createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
   2540     createInfo.pNext = NULL;
   2541     createInfo.flags = 0;
   2542     createInfo.connection = demo->connection;
   2543     createInfo.window = demo->window;
   2544 
   2545     err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
   2546 #endif // _WIN32
   2547 
   2548     // Iterate over each queue to learn whether it supports presenting:
   2549     VkBool32 *supportsPresent =
   2550         (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
   2551     for (i = 0; i < demo->queue_count; i++) {
   2552         demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
   2553                                                    &supportsPresent[i]);
   2554     }
   2555 
   2556     // Search for a graphics and a present queue in the array of queue
   2557     // families, try to find one that supports both
   2558     uint32_t graphicsQueueNodeIndex = UINT32_MAX;
   2559     uint32_t presentQueueNodeIndex = UINT32_MAX;
   2560     for (i = 0; i < demo->queue_count; i++) {
   2561         if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
   2562             if (graphicsQueueNodeIndex == UINT32_MAX) {
   2563                 graphicsQueueNodeIndex = i;
   2564             }
   2565 
   2566             if (supportsPresent[i] == VK_TRUE) {
   2567                 graphicsQueueNodeIndex = i;
   2568                 presentQueueNodeIndex = i;
   2569                 break;
   2570             }
   2571         }
   2572     }
   2573     if (presentQueueNodeIndex == UINT32_MAX) {
   2574         // If didn't find a queue that supports both graphics and present, then
   2575         // find a separate present queue.
   2576         for (uint32_t i = 0; i < demo->queue_count; ++i) {
   2577             if (supportsPresent[i] == VK_TRUE) {
   2578                 presentQueueNodeIndex = i;
   2579                 break;
   2580             }
   2581         }
   2582     }
   2583     free(supportsPresent);
   2584 
   2585     // Generate error if could not find both a graphics and a present queue
   2586     if (graphicsQueueNodeIndex == UINT32_MAX ||
   2587         presentQueueNodeIndex == UINT32_MAX) {
   2588         ERR_EXIT("Could not find a graphics and a present queue\n",
   2589                  "Swapchain Initialization Failure");
   2590     }
   2591 
   2592     // TODO: Add support for separate queues, including presentation,
   2593     //       synchronization, and appropriate tracking for QueueSubmit.
   2594     // NOTE: While it is possible for an application to use a separate graphics
   2595     //       and a present queues, this demo program assumes it is only using
   2596     //       one:
   2597     if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
   2598         ERR_EXIT("Could not find a common graphics and a present queue\n",
   2599                  "Swapchain Initialization Failure");
   2600     }
   2601 
   2602     demo->graphics_queue_node_index = graphicsQueueNodeIndex;
   2603 
   2604     demo_create_device(demo);
   2605 
   2606     GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR);
   2607     GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR);
   2608     GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR);
   2609     GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR);
   2610     GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR);
   2611 
   2612     vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
   2613                      &demo->queue);
   2614 
   2615     // Get the list of VkFormat's that are supported:
   2616     uint32_t formatCount;
   2617     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
   2618                                                      &formatCount, NULL);
   2619     assert(!err);
   2620     VkSurfaceFormatKHR *surfFormats =
   2621         (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
   2622     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
   2623                                                      &formatCount, surfFormats);
   2624     assert(!err);
   2625     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
   2626     // the surface has no preferred format.  Otherwise, at least one
   2627     // supported format will be returned.
   2628     if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
   2629         demo->format = VK_FORMAT_B8G8R8A8_UNORM;
   2630     } else {
   2631         assert(formatCount >= 1);
   2632         demo->format = surfFormats[0].format;
   2633     }
   2634     demo->color_space = surfFormats[0].colorSpace;
   2635 
   2636     demo->quit = false;
   2637     demo->curFrame = 0;
   2638 
   2639     // Get Memory information and properties
   2640     vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
   2641 }
   2642 
   2643 static void demo_init_connection(struct demo *demo) {
   2644 #ifndef _WIN32
   2645     const xcb_setup_t *setup;
   2646     xcb_screen_iterator_t iter;
   2647     int scr;
   2648 
   2649     demo->connection = xcb_connect(NULL, &scr);
   2650     if (demo->connection == NULL) {
   2651         printf("Cannot find a compatible Vulkan installable client driver "
   2652                "(ICD).\nExiting ...\n");
   2653         fflush(stdout);
   2654         exit(1);
   2655     }
   2656 
   2657     setup = xcb_get_setup(demo->connection);
   2658     iter = xcb_setup_roots_iterator(setup);
   2659     while (scr-- > 0)
   2660         xcb_screen_next(&iter);
   2661 
   2662     demo->screen = iter.data;
   2663 #endif // _WIN32
   2664 }
   2665 
   2666 static void demo_init(struct demo *demo, int argc, char **argv) {
   2667     vec3 eye = {0.0f, 3.0f, 5.0f};
   2668     vec3 origin = {0, 0, 0};
   2669     vec3 up = {0.0f, 1.0f, 0.0};
   2670 
   2671     memset(demo, 0, sizeof(*demo));
   2672     demo->frameCount = INT32_MAX;
   2673 
   2674     for (int i = 1; i < argc; i++) {
   2675         if (strcmp(argv[i], "--use_staging") == 0) {
   2676             demo->use_staging_buffer = true;
   2677             continue;
   2678         }
   2679         if (strcmp(argv[i], "--break") == 0) {
   2680             demo->use_break = true;
   2681             continue;
   2682         }
   2683         if (strcmp(argv[i], "--validate") == 0) {
   2684             demo->validate = true;
   2685             continue;
   2686         }
   2687         if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
   2688             i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
   2689             demo->frameCount >= 0) {
   2690             i++;
   2691             continue;
   2692         }
   2693 
   2694         fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] "
   2695                         "[--c <framecount>]\n",
   2696                 APP_SHORT_NAME);
   2697         fflush(stderr);
   2698         exit(1);
   2699     }
   2700 
   2701     demo_init_connection(demo);
   2702     demo_init_vk(demo);
   2703 
   2704     demo->width = 500;
   2705     demo->height = 500;
   2706 
   2707     demo->spin_angle = 0.01f;
   2708     demo->spin_increment = 0.01f;
   2709     demo->pause = false;
   2710 
   2711     mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f),
   2712                        1.0f, 0.1f, 100.0f);
   2713     mat4x4_look_at(demo->view_matrix, eye, origin, up);
   2714     mat4x4_identity(demo->model_matrix);
   2715 }
   2716 
   2717 #ifdef _WIN32
   2718 // Include header required for parsing the command line options.
   2719 #include <shellapi.h>
   2720 
   2721 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine,
   2722                    int nCmdShow) {
   2723     MSG msg;   // message
   2724     bool done; // flag saying when app is complete
   2725     int argc;
   2726     char **argv;
   2727 
   2728     // Use the CommandLine functions to get the command line arguments.
   2729     // Unfortunately, Microsoft outputs
   2730     // this information as wide characters for Unicode, and we simply want the
   2731     // Ascii version to be compatible
   2732     // with the non-Windows side.  So, we have to convert the information to
   2733     // Ascii character strings.
   2734     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
   2735     if (NULL == commandLineArgs) {
   2736         argc = 0;
   2737     }
   2738 
   2739     if (argc > 0) {
   2740         argv = (char **)malloc(sizeof(char *) * argc);
   2741         if (argv == NULL) {
   2742             argc = 0;
   2743         } else {
   2744             for (int iii = 0; iii < argc; iii++) {
   2745                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
   2746                 size_t numConverted = 0;
   2747 
   2748                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
   2749                 if (argv[iii] != NULL) {
   2750                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
   2751                                commandLineArgs[iii], wideCharLen + 1);
   2752                 }
   2753             }
   2754         }
   2755     } else {
   2756         argv = NULL;
   2757     }
   2758 
   2759     demo_init(&demo, argc, argv);
   2760 
   2761     // Free up the items we had to allocate for the command line arguments.
   2762     if (argc > 0 && argv != NULL) {
   2763         for (int iii = 0; iii < argc; iii++) {
   2764             if (argv[iii] != NULL) {
   2765                 free(argv[iii]);
   2766             }
   2767         }
   2768         free(argv);
   2769     }
   2770 
   2771     demo.connection = hInstance;
   2772     strncpy(demo.name, "cube", APP_NAME_STR_LEN);
   2773     demo_create_window(&demo);
   2774     demo_init_vk_swapchain(&demo);
   2775 
   2776     demo_prepare(&demo);
   2777 
   2778     done = false; // initialize loop condition variable
   2779 
   2780     // main message loop
   2781     while (!done) {
   2782         PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
   2783         if (msg.message == WM_QUIT) // check for a quit message
   2784         {
   2785             done = true; // if found, quit app
   2786         } else {
   2787             /* Translate and dispatch to event queue*/
   2788             TranslateMessage(&msg);
   2789             DispatchMessage(&msg);
   2790         }
   2791         RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
   2792     }
   2793 
   2794     demo_cleanup(&demo);
   2795 
   2796     return (int)msg.wParam;
   2797 }
   2798 #else  // _WIN32
   2799 int main(int argc, char **argv) {
   2800     struct demo demo;
   2801 
   2802     demo_init(&demo, argc, argv);
   2803     demo_create_window(&demo);
   2804     demo_init_vk_swapchain(&demo);
   2805 
   2806     demo_prepare(&demo);
   2807     demo_run(&demo);
   2808 
   2809     demo_cleanup(&demo);
   2810 
   2811     return validation_error;
   2812 }
   2813 #endif // _WIN32
   2814