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