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 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *     http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 *
     18 * Author: Chia-I Wu <olv (at) lunarg.com>
     19 * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     20 * Author: Ian Elliott <ian (at) LunarG.com>
     21 * Author: Jon Ashburn <jon (at) lunarg.com>
     22 * Author: Gwan-gyeong Mun <elongbug (at) gmail.com>
     23 * Author: Tony Barbour <tony (at) LunarG.com>
     24 */
     25 
     26 #define _GNU_SOURCE
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <stdbool.h>
     31 #include <assert.h>
     32 #include <signal.h>
     33 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
     34 #include <X11/Xutil.h>
     35 #endif
     36 
     37 #ifdef _WIN32
     38 #pragma comment(linker, "/subsystem:windows")
     39 #define APP_NAME_STR_LEN 80
     40 #endif // _WIN32
     41 
     42 #ifdef ANDROID
     43 #include "vulkan_wrapper.h"
     44 #else
     45 #include <vulkan/vulkan.h>
     46 #endif
     47 
     48 #include <vulkan/vk_sdk_platform.h>
     49 #include "linmath.h"
     50 
     51 #define DEMO_TEXTURE_COUNT 1
     52 #define APP_SHORT_NAME "cube"
     53 #define APP_LONG_NAME "The Vulkan Cube Demo Program"
     54 
     55 // Allow a maximum of two outstanding presentation operations.
     56 #define FRAME_LAG 2
     57 
     58 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
     59 
     60 #if defined(NDEBUG) && defined(__GNUC__)
     61 #define U_ASSERT_ONLY __attribute__((unused))
     62 #else
     63 #define U_ASSERT_ONLY
     64 #endif
     65 
     66 #if defined(__GNUC__)
     67 #define UNUSED __attribute__((unused))
     68 #else
     69 #define UNUSED
     70 #endif
     71 
     72 #ifdef _WIN32
     73 bool in_callback = false;
     74 #define ERR_EXIT(err_msg, err_class)                                           \
     75     do {                                                                       \
     76         if (!demo->suppress_popups)                                            \
     77             MessageBox(NULL, err_msg, err_class, MB_OK);                       \
     78         exit(1);                                                               \
     79     } while (0)
     80 
     81 #elif defined __ANDROID__
     82 #include <android/log.h>
     83 #define ERR_EXIT(err_msg, err_class)                                           \
     84     do {                                                                       \
     85         ((void)__android_log_print(ANDROID_LOG_INFO, "Cube", err_msg));        \
     86         exit(1);                                                               \
     87     } while (0)
     88 #else
     89 #define ERR_EXIT(err_msg, err_class)                                           \
     90     do {                                                                       \
     91         printf(err_msg);                                                       \
     92         fflush(stdout);                                                        \
     93         exit(1);                                                               \
     94     } while (0)
     95 #endif
     96 
     97 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                               \
     98     {                                                                          \
     99         demo->fp##entrypoint =                                                 \
    100             (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
    101         if (demo->fp##entrypoint == NULL) {                                    \
    102             ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint,    \
    103                      "vkGetInstanceProcAddr Failure");                         \
    104         }                                                                      \
    105     }
    106 
    107 static PFN_vkGetDeviceProcAddr g_gdpa = NULL;
    108 
    109 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                  \
    110     {                                                                          \
    111         if (!g_gdpa)                                                           \
    112             g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(           \
    113                 demo->inst, "vkGetDeviceProcAddr");                            \
    114         demo->fp##entrypoint =                                                 \
    115             (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint);                 \
    116         if (demo->fp##entrypoint == NULL) {                                    \
    117             ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint,      \
    118                      "vkGetDeviceProcAddr Failure");                           \
    119         }                                                                      \
    120     }
    121 
    122 /*
    123  * structure to track all objects related to a texture.
    124  */
    125 struct texture_object {
    126     VkSampler sampler;
    127 
    128     VkImage image;
    129     VkImageLayout imageLayout;
    130 
    131     VkMemoryAllocateInfo mem_alloc;
    132     VkDeviceMemory mem;
    133     VkImageView view;
    134     int32_t tex_width, tex_height;
    135 };
    136 
    137 static char *tex_files[] = {"lunarg.ppm"};
    138 
    139 static int validation_error = 0;
    140 
    141 struct vkcube_vs_uniform {
    142     // Must start with MVP
    143     float mvp[4][4];
    144     float position[12 * 3][4];
    145     float color[12 * 3][4];
    146 };
    147 
    148 struct vktexcube_vs_uniform {
    149     // Must start with MVP
    150     float mvp[4][4];
    151     float position[12 * 3][4];
    152     float attr[12 * 3][4];
    153 };
    154 
    155 //--------------------------------------------------------------------------------------
    156 // Mesh and VertexFormat Data
    157 //--------------------------------------------------------------------------------------
    158 // clang-format off
    159 static const float g_vertex_buffer_data[] = {
    160     -1.0f,-1.0f,-1.0f,  // -X side
    161     -1.0f,-1.0f, 1.0f,
    162     -1.0f, 1.0f, 1.0f,
    163     -1.0f, 1.0f, 1.0f,
    164     -1.0f, 1.0f,-1.0f,
    165     -1.0f,-1.0f,-1.0f,
    166 
    167     -1.0f,-1.0f,-1.0f,  // -Z side
    168      1.0f, 1.0f,-1.0f,
    169      1.0f,-1.0f,-1.0f,
    170     -1.0f,-1.0f,-1.0f,
    171     -1.0f, 1.0f,-1.0f,
    172      1.0f, 1.0f,-1.0f,
    173 
    174     -1.0f,-1.0f,-1.0f,  // -Y side
    175      1.0f,-1.0f,-1.0f,
    176      1.0f,-1.0f, 1.0f,
    177     -1.0f,-1.0f,-1.0f,
    178      1.0f,-1.0f, 1.0f,
    179     -1.0f,-1.0f, 1.0f,
    180 
    181     -1.0f, 1.0f,-1.0f,  // +Y side
    182     -1.0f, 1.0f, 1.0f,
    183      1.0f, 1.0f, 1.0f,
    184     -1.0f, 1.0f,-1.0f,
    185      1.0f, 1.0f, 1.0f,
    186      1.0f, 1.0f,-1.0f,
    187 
    188      1.0f, 1.0f,-1.0f,  // +X side
    189      1.0f, 1.0f, 1.0f,
    190      1.0f,-1.0f, 1.0f,
    191      1.0f,-1.0f, 1.0f,
    192      1.0f,-1.0f,-1.0f,
    193      1.0f, 1.0f,-1.0f,
    194 
    195     -1.0f, 1.0f, 1.0f,  // +Z side
    196     -1.0f,-1.0f, 1.0f,
    197      1.0f, 1.0f, 1.0f,
    198     -1.0f,-1.0f, 1.0f,
    199      1.0f,-1.0f, 1.0f,
    200      1.0f, 1.0f, 1.0f,
    201 };
    202 
    203 static const float g_uv_buffer_data[] = {
    204     0.0f, 1.0f,  // -X side
    205     1.0f, 1.0f,
    206     1.0f, 0.0f,
    207     1.0f, 0.0f,
    208     0.0f, 0.0f,
    209     0.0f, 1.0f,
    210 
    211     1.0f, 1.0f,  // -Z side
    212     0.0f, 0.0f,
    213     0.0f, 1.0f,
    214     1.0f, 1.0f,
    215     1.0f, 0.0f,
    216     0.0f, 0.0f,
    217 
    218     1.0f, 0.0f,  // -Y side
    219     1.0f, 1.0f,
    220     0.0f, 1.0f,
    221     1.0f, 0.0f,
    222     0.0f, 1.0f,
    223     0.0f, 0.0f,
    224 
    225     1.0f, 0.0f,  // +Y side
    226     0.0f, 0.0f,
    227     0.0f, 1.0f,
    228     1.0f, 0.0f,
    229     0.0f, 1.0f,
    230     1.0f, 1.0f,
    231 
    232     1.0f, 0.0f,  // +X side
    233     0.0f, 0.0f,
    234     0.0f, 1.0f,
    235     0.0f, 1.0f,
    236     1.0f, 1.0f,
    237     1.0f, 0.0f,
    238 
    239     0.0f, 0.0f,  // +Z side
    240     0.0f, 1.0f,
    241     1.0f, 0.0f,
    242     0.0f, 1.0f,
    243     1.0f, 1.0f,
    244     1.0f, 0.0f,
    245 };
    246 // clang-format on
    247 
    248 void dumpMatrix(const char *note, mat4x4 MVP) {
    249     int i;
    250 
    251     printf("%s: \n", note);
    252     for (i = 0; i < 4; i++) {
    253         printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]);
    254     }
    255     printf("\n");
    256     fflush(stdout);
    257 }
    258 
    259 void dumpVec4(const char *note, vec4 vector) {
    260     printf("%s: \n", note);
    261     printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
    262     printf("\n");
    263     fflush(stdout);
    264 }
    265 
    266 VKAPI_ATTR VkBool32 VKAPI_CALL
    267 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    268               uint64_t srcObject, size_t location, int32_t msgCode,
    269               const char *pLayerPrefix, const char *pMsg,
    270               void *pUserData) {
    271 #ifndef WIN32
    272     raise(SIGTRAP);
    273 #else
    274     DebugBreak();
    275 #endif
    276 
    277     return false;
    278 }
    279 
    280 typedef struct {
    281     VkImage image;
    282     VkCommandBuffer cmd;
    283     VkCommandBuffer graphics_to_present_cmd;
    284     VkImageView view;
    285 } SwapchainBuffers;
    286 
    287 struct demo {
    288 #if defined(VK_USE_PLATFORM_WIN32_KHR)
    289 #define APP_NAME_STR_LEN 80
    290     HINSTANCE connection;        // hInstance - Windows Instance
    291     char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
    292     HWND window;                 // hWnd - window handle
    293     POINT minsize;               // minimum window size
    294 #elif defined(VK_USE_PLATFORM_XLIB_KHR) | defined(VK_USE_PLATFORM_XCB_KHR)
    295     Display* display;
    296     Window xlib_window;
    297     Atom xlib_wm_delete_window;
    298 
    299     xcb_connection_t *connection;
    300     xcb_screen_t *screen;
    301     xcb_window_t xcb_window;
    302     xcb_intern_atom_reply_t *atom_wm_delete_window;
    303 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
    304     struct wl_display *display;
    305     struct wl_registry *registry;
    306     struct wl_compositor *compositor;
    307     struct wl_surface *window;
    308     struct wl_shell *shell;
    309     struct wl_shell_surface *shell_surface;
    310 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
    311     ANativeWindow* window;
    312 #endif
    313     VkSurfaceKHR surface;
    314     bool prepared;
    315     bool use_staging_buffer;
    316     bool use_xlib;
    317     bool separate_present_queue;
    318 
    319     VkInstance inst;
    320     VkPhysicalDevice gpu;
    321     VkDevice device;
    322     VkQueue graphics_queue;
    323     VkQueue present_queue;
    324     uint32_t graphics_queue_family_index;
    325     uint32_t present_queue_family_index;
    326     VkSemaphore image_acquired_semaphores[FRAME_LAG];
    327     VkSemaphore draw_complete_semaphores[FRAME_LAG];
    328     VkSemaphore image_ownership_semaphores[FRAME_LAG];
    329     VkPhysicalDeviceProperties gpu_props;
    330     VkQueueFamilyProperties *queue_props;
    331     VkPhysicalDeviceMemoryProperties memory_properties;
    332 
    333     uint32_t enabled_extension_count;
    334     uint32_t enabled_layer_count;
    335     char *extension_names[64];
    336     char *enabled_layers[64];
    337 
    338     int width, height;
    339     VkFormat format;
    340     VkColorSpaceKHR color_space;
    341 
    342     PFN_vkGetPhysicalDeviceSurfaceSupportKHR
    343         fpGetPhysicalDeviceSurfaceSupportKHR;
    344     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
    345         fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
    346     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
    347         fpGetPhysicalDeviceSurfaceFormatsKHR;
    348     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
    349         fpGetPhysicalDeviceSurfacePresentModesKHR;
    350     PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
    351     PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
    352     PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
    353     PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
    354     PFN_vkQueuePresentKHR fpQueuePresentKHR;
    355     uint32_t swapchainImageCount;
    356     VkSwapchainKHR swapchain;
    357     SwapchainBuffers *buffers;
    358     VkFence fences[FRAME_LAG];
    359     int frame_index;
    360 
    361     VkCommandPool cmd_pool;
    362     VkCommandPool present_cmd_pool;
    363 
    364     struct {
    365         VkFormat format;
    366 
    367         VkImage image;
    368         VkMemoryAllocateInfo mem_alloc;
    369         VkDeviceMemory mem;
    370         VkImageView view;
    371     } depth;
    372 
    373     struct texture_object textures[DEMO_TEXTURE_COUNT];
    374 
    375     struct {
    376         VkBuffer buf;
    377         VkMemoryAllocateInfo mem_alloc;
    378         VkDeviceMemory mem;
    379         VkDescriptorBufferInfo buffer_info;
    380     } uniform_data;
    381 
    382     VkCommandBuffer cmd; // Buffer for initialization commands
    383     VkPipelineLayout pipeline_layout;
    384     VkDescriptorSetLayout desc_layout;
    385     VkPipelineCache pipelineCache;
    386     VkRenderPass render_pass;
    387     VkPipeline pipeline;
    388 
    389     mat4x4 projection_matrix;
    390     mat4x4 view_matrix;
    391     mat4x4 model_matrix;
    392 
    393     float spin_angle;
    394     float spin_increment;
    395     bool pause;
    396 
    397     VkShaderModule vert_shader_module;
    398     VkShaderModule frag_shader_module;
    399 
    400     VkDescriptorPool desc_pool;
    401     VkDescriptorSet desc_set;
    402 
    403     VkFramebuffer *framebuffers;
    404 
    405     bool quit;
    406     int32_t curFrame;
    407     int32_t frameCount;
    408     bool validate;
    409     bool use_break;
    410     bool suppress_popups;
    411     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
    412     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
    413     VkDebugReportCallbackEXT msg_callback;
    414     PFN_vkDebugReportMessageEXT DebugReportMessage;
    415 
    416     uint32_t current_buffer;
    417     uint32_t queue_family_count;
    418 };
    419 
    420 VKAPI_ATTR VkBool32 VKAPI_CALL
    421 dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    422     uint64_t srcObject, size_t location, int32_t msgCode,
    423     const char *pLayerPrefix, const char *pMsg, void *pUserData) {
    424 
    425     // clang-format off
    426     char *message = (char *)malloc(strlen(pMsg) + 100);
    427 
    428     assert(message);
    429 
    430     // We know we're submitting queues without fences, ignore this
    431     if (strstr(pMsg, "vkQueueSubmit parameter, VkFence fence, is null pointer"))
    432         return false;
    433 
    434     if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
    435         sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    436         validation_error = 1;
    437     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    438         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    439         validation_error = 1;
    440     } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
    441         sprintf(message, "PERFORMANCE WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    442         validation_error = 1;
    443     } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    444         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    445         validation_error = 1;
    446     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
    447         sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    448         validation_error = 1;
    449     } else {
    450         sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    451         validation_error = 1;
    452     }
    453 
    454 #ifdef _WIN32
    455 
    456     in_callback = true;
    457     struct demo *demo = (struct demo*) pUserData;
    458     if (!demo->suppress_popups)
    459         MessageBox(NULL, message, "Alert", MB_OK);
    460     in_callback = false;
    461 
    462 #elif defined(ANDROID)
    463 
    464     if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
    465         __android_log_print(ANDROID_LOG_INFO,  APP_SHORT_NAME, "%s", message);
    466     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    467         __android_log_print(ANDROID_LOG_WARN,  APP_SHORT_NAME, "%s", message);
    468     } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
    469         __android_log_print(ANDROID_LOG_WARN,  APP_SHORT_NAME, "%s", message);
    470     } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    471         __android_log_print(ANDROID_LOG_ERROR, APP_SHORT_NAME, "%s", message);
    472     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
    473         __android_log_print(ANDROID_LOG_DEBUG, APP_SHORT_NAME, "%s", message);
    474     } else {
    475         __android_log_print(ANDROID_LOG_INFO,  APP_SHORT_NAME, "%s", message);
    476     }
    477 
    478 #else
    479 
    480     printf("%s\n", message);
    481     fflush(stdout);
    482 
    483 #endif
    484 
    485     free(message);
    486 
    487     //clang-format on
    488 
    489     /*
    490     * false indicates that layer should not bail-out of an
    491     * API call that had validation failures. This may mean that the
    492     * app dies inside the driver due to invalid parameter(s).
    493     * That's what would happen without validation layers, so we'll
    494     * keep that behavior here.
    495     */
    496     return false;
    497 }
    498 
    499 // Forward declaration:
    500 static void demo_resize(struct demo *demo);
    501 
    502 static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
    503                                         VkFlags requirements_mask,
    504                                         uint32_t *typeIndex) {
    505     // Search memtypes to find first index with those properties
    506     for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
    507         if ((typeBits & 1) == 1) {
    508             // Type is available, does it match user properties?
    509             if ((demo->memory_properties.memoryTypes[i].propertyFlags &
    510                  requirements_mask) == requirements_mask) {
    511                 *typeIndex = i;
    512                 return true;
    513             }
    514         }
    515         typeBits >>= 1;
    516     }
    517     // No memory types matched, return failure
    518     return false;
    519 }
    520 
    521 static void demo_flush_init_cmd(struct demo *demo) {
    522     VkResult U_ASSERT_ONLY err;
    523 
    524     // This function could get called twice if the texture uses a staging buffer
    525     // In that case the second call should be ignored
    526     if (demo->cmd == VK_NULL_HANDLE)
    527         return;
    528 
    529     err = vkEndCommandBuffer(demo->cmd);
    530     assert(!err);
    531 
    532     VkFence fence;
    533     VkFenceCreateInfo fence_ci = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
    534                                   .pNext = NULL,
    535                                   .flags = 0};
    536     vkCreateFence(demo->device, &fence_ci, NULL, &fence);
    537     const VkCommandBuffer cmd_bufs[] = {demo->cmd};
    538     VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
    539                                 .pNext = NULL,
    540                                 .waitSemaphoreCount = 0,
    541                                 .pWaitSemaphores = NULL,
    542                                 .pWaitDstStageMask = NULL,
    543                                 .commandBufferCount = 1,
    544                                 .pCommandBuffers = cmd_bufs,
    545                                 .signalSemaphoreCount = 0,
    546                                 .pSignalSemaphores = NULL};
    547 
    548     err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence);
    549     assert(!err);
    550 
    551     err = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX);
    552     assert(!err);
    553 
    554     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
    555     vkDestroyFence(demo->device, fence, NULL);
    556     demo->cmd = VK_NULL_HANDLE;
    557 }
    558 
    559 static void demo_set_image_layout(struct demo *demo, VkImage image,
    560                                   VkImageAspectFlags aspectMask,
    561                                   VkImageLayout old_image_layout,
    562                                   VkImageLayout new_image_layout,
    563                                   VkAccessFlagBits srcAccessMask,
    564                                   VkPipelineStageFlags src_stages,
    565                                   VkPipelineStageFlags dest_stages) {
    566     VkResult U_ASSERT_ONLY err;
    567 
    568     if (demo->cmd == VK_NULL_HANDLE) {
    569         const VkCommandBufferAllocateInfo cmd = {
    570             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
    571             .pNext = NULL,
    572             .commandPool = demo->cmd_pool,
    573             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
    574             .commandBufferCount = 1,
    575         };
    576 
    577         err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd);
    578         assert(!err);
    579         VkCommandBufferBeginInfo cmd_buf_info = {
    580             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    581             .pNext = NULL,
    582             .flags = 0,
    583             .pInheritanceInfo = NULL,
    584         };
    585         err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
    586         assert(!err);
    587     }
    588 
    589     VkImageMemoryBarrier image_memory_barrier = {
    590         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    591         .pNext = NULL,
    592         .srcAccessMask = srcAccessMask,
    593         .dstAccessMask = 0,
    594         .oldLayout = old_image_layout,
    595         .newLayout = new_image_layout,
    596         .image = image,
    597         .subresourceRange = {aspectMask, 0, 1, 0, 1}};
    598 
    599     switch (new_image_layout) {
    600     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
    601         /* Make sure anything that was copying from this image has completed */
    602         image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    603         break;
    604 
    605     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
    606         image_memory_barrier.dstAccessMask =
    607             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    608         break;
    609 
    610     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
    611         image_memory_barrier.dstAccessMask =
    612             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    613         break;
    614 
    615     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
    616         image_memory_barrier.dstAccessMask =
    617             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
    618         break;
    619 
    620     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
    621         image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
    622         break;
    623 
    624     case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
    625         image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    626         break;
    627 
    628     default:
    629         image_memory_barrier.dstAccessMask = 0;
    630         break;
    631     }
    632 
    633 
    634     VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
    635 
    636     vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, 0, 0, NULL, 0,
    637                          NULL, 1, pmemory_barrier);
    638 }
    639 
    640 static void demo_draw_build_cmd(struct demo *demo, VkCommandBuffer cmd_buf) {
    641     const VkCommandBufferBeginInfo cmd_buf_info = {
    642         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    643         .pNext = NULL,
    644         .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
    645         .pInheritanceInfo = NULL,
    646     };
    647     const VkClearValue clear_values[2] = {
    648             [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
    649             [1] = {.depthStencil = {1.0f, 0}},
    650     };
    651     const VkRenderPassBeginInfo rp_begin = {
    652         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
    653         .pNext = NULL,
    654         .renderPass = demo->render_pass,
    655         .framebuffer = demo->framebuffers[demo->current_buffer],
    656         .renderArea.offset.x = 0,
    657         .renderArea.offset.y = 0,
    658         .renderArea.extent.width = demo->width,
    659         .renderArea.extent.height = demo->height,
    660         .clearValueCount = 2,
    661         .pClearValues = clear_values,
    662     };
    663     VkResult U_ASSERT_ONLY err;
    664 
    665     err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
    666     assert(!err);
    667     vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
    668     vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline);
    669     vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
    670                             demo->pipeline_layout, 0, 1, &demo->desc_set, 0,
    671                             NULL);
    672     VkViewport viewport;
    673     memset(&viewport, 0, sizeof(viewport));
    674     viewport.height = (float)demo->height;
    675     viewport.width = (float)demo->width;
    676     viewport.minDepth = (float)0.0f;
    677     viewport.maxDepth = (float)1.0f;
    678     vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
    679 
    680     VkRect2D scissor;
    681     memset(&scissor, 0, sizeof(scissor));
    682     scissor.extent.width = demo->width;
    683     scissor.extent.height = demo->height;
    684     scissor.offset.x = 0;
    685     scissor.offset.y = 0;
    686     vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
    687     vkCmdDraw(cmd_buf, 12 * 3, 1, 0, 0);
    688     // Note that ending the renderpass changes the image's layout from
    689     // COLOR_ATTACHMENT_OPTIMAL to PRESENT_SRC_KHR
    690     vkCmdEndRenderPass(cmd_buf);
    691 
    692     if (demo->separate_present_queue) {
    693         // We have to transfer ownership from the graphics queue family to the
    694         // present queue family to be able to present.  Note that we don't have
    695         // to transfer from present queue family back to graphics queue family at
    696         // the start of the next frame because we don't care about the image's
    697         // contents at that point.
    698         VkImageMemoryBarrier image_ownership_barrier = {
    699             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    700             .pNext = NULL,
    701             .srcAccessMask = 0,
    702             .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    703             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    704             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    705             .srcQueueFamilyIndex = demo->graphics_queue_family_index,
    706             .dstQueueFamilyIndex = demo->present_queue_family_index,
    707             .image = demo->buffers[demo->current_buffer].image,
    708             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
    709 
    710         vkCmdPipelineBarrier(cmd_buf,
    711                              VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    712                              VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
    713                              0, NULL, 0, NULL, 1, &image_ownership_barrier);
    714     }
    715     err = vkEndCommandBuffer(cmd_buf);
    716     assert(!err);
    717 }
    718 
    719 void demo_build_image_ownership_cmd(struct demo *demo, int i) {
    720     VkResult U_ASSERT_ONLY err;
    721 
    722     const VkCommandBufferBeginInfo cmd_buf_info = {
    723         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
    724         .pNext = NULL,
    725         .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
    726         .pInheritanceInfo = NULL,
    727     };
    728     err = vkBeginCommandBuffer(demo->buffers[i].graphics_to_present_cmd,
    729                                &cmd_buf_info);
    730     assert(!err);
    731 
    732     VkImageMemoryBarrier image_ownership_barrier = {
    733         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
    734         .pNext = NULL,
    735         .srcAccessMask = 0,
    736         .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    737         .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    738         .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
    739         .srcQueueFamilyIndex = demo->graphics_queue_family_index,
    740         .dstQueueFamilyIndex = demo->present_queue_family_index,
    741         .image = demo->buffers[i].image,
    742         .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
    743 
    744     vkCmdPipelineBarrier(demo->buffers[i].graphics_to_present_cmd,
    745                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
    746                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0,
    747                          NULL, 0, NULL, 1, &image_ownership_barrier);
    748     err = vkEndCommandBuffer(demo->buffers[i].graphics_to_present_cmd);
    749     assert(!err);
    750 }
    751 
    752 void demo_update_data_buffer(struct demo *demo) {
    753     mat4x4 MVP, Model, VP;
    754     int matrixSize = sizeof(MVP);
    755     uint8_t *pData;
    756     VkResult U_ASSERT_ONLY err;
    757 
    758     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
    759 
    760     // Rotate 22.5 degrees around the Y axis
    761     mat4x4_dup(Model, demo->model_matrix);
    762     mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f,
    763                   (float)degreesToRadians(demo->spin_angle));
    764     mat4x4_mul(MVP, VP, demo->model_matrix);
    765 
    766     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
    767                       demo->uniform_data.mem_alloc.allocationSize, 0,
    768                       (void **)&pData);
    769     assert(!err);
    770 
    771     memcpy(pData, (const void *)&MVP[0][0], matrixSize);
    772 
    773     vkUnmapMemory(demo->device, demo->uniform_data.mem);
    774 }
    775 
    776 static void demo_draw(struct demo *demo) {
    777     VkResult U_ASSERT_ONLY err;
    778 
    779     // Ensure no more than FRAME_LAG presentations are outstanding
    780     vkWaitForFences(demo->device, 1, &demo->fences[demo->frame_index], VK_TRUE, UINT64_MAX);
    781     vkResetFences(demo->device, 1, &demo->fences[demo->frame_index]);
    782 
    783     // Get the index of the next available swapchain image:
    784     err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
    785                                       demo->image_acquired_semaphores[demo->frame_index], demo->fences[demo->frame_index],
    786                                       &demo->current_buffer);
    787 
    788     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    789         // demo->swapchain is out of date (e.g. the window was resized) and
    790         // must be recreated:
    791         demo->frame_index += 1;
    792         demo->frame_index %= FRAME_LAG;
    793 
    794         demo_resize(demo);
    795         demo_draw(demo);
    796         return;
    797     } else if (err == VK_SUBOPTIMAL_KHR) {
    798         // demo->swapchain is not as optimal as it could be, but the platform's
    799         // presentation engine will still present the image correctly.
    800     } else {
    801         assert(!err);
    802     }
    803     // Wait for the image acquired semaphore to be signaled to ensure
    804     // that the image won't be rendered to until the presentation
    805     // engine has fully released ownership to the application, and it is
    806     // okay to render to the image.
    807     VkFence nullFence = VK_NULL_HANDLE;
    808     VkPipelineStageFlags pipe_stage_flags;
    809     VkSubmitInfo submit_info;
    810     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    811     submit_info.pNext = NULL;
    812     submit_info.pWaitDstStageMask = &pipe_stage_flags;
    813     pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    814     submit_info.waitSemaphoreCount = 1;
    815     submit_info.pWaitSemaphores = &demo->image_acquired_semaphores[demo->frame_index];
    816     submit_info.commandBufferCount = 1;
    817     submit_info.pCommandBuffers = &demo->buffers[demo->current_buffer].cmd;
    818     submit_info.signalSemaphoreCount = 1;
    819     submit_info.pSignalSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
    820     err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, nullFence);
    821     assert(!err);
    822 
    823     if (demo->separate_present_queue) {
    824         // If we are using separate queues, change image ownership to the
    825         // present queue before presenting, waiting for the draw complete
    826         // semaphore and signalling the ownership released semaphore when finished
    827         pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    828         submit_info.waitSemaphoreCount = 1;
    829         submit_info.pWaitSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
    830         submit_info.commandBufferCount = 1;
    831         submit_info.pCommandBuffers =
    832             &demo->buffers[demo->current_buffer].graphics_to_present_cmd;
    833         submit_info.signalSemaphoreCount = 1;
    834         submit_info.pSignalSemaphores = &demo->image_ownership_semaphores[demo->frame_index];
    835         err = vkQueueSubmit(demo->present_queue, 1, &submit_info, nullFence);
    836         assert(!err);
    837     }
    838 
    839     // If we are using separate queues we have to wait for image ownership,
    840     // otherwise wait for draw complete
    841     VkPresentInfoKHR present = {
    842         .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
    843         .pNext = NULL,
    844         .waitSemaphoreCount = 1,
    845         .pWaitSemaphores = (demo->separate_present_queue)
    846                                ? &demo->image_ownership_semaphores[demo->frame_index]
    847                                : &demo->draw_complete_semaphores[demo->frame_index],
    848         .swapchainCount = 1,
    849         .pSwapchains = &demo->swapchain,
    850         .pImageIndices = &demo->current_buffer,
    851     };
    852 
    853     err = demo->fpQueuePresentKHR(demo->present_queue, &present);
    854     demo->frame_index += 1;
    855     demo->frame_index %= FRAME_LAG;
    856 
    857     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
    858         // demo->swapchain is out of date (e.g. the window was resized) and
    859         // must be recreated:
    860         demo_resize(demo);
    861     } else if (err == VK_SUBOPTIMAL_KHR) {
    862         // demo->swapchain is not as optimal as it could be, but the platform's
    863         // presentation engine will still present the image correctly.
    864     } else {
    865         assert(!err);
    866     }
    867 }
    868 
    869 static void demo_prepare_buffers(struct demo *demo) {
    870     VkResult U_ASSERT_ONLY err;
    871     VkSwapchainKHR oldSwapchain = demo->swapchain;
    872 
    873     // Check the surface capabilities and formats
    874     VkSurfaceCapabilitiesKHR surfCapabilities;
    875     err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(
    876         demo->gpu, demo->surface, &surfCapabilities);
    877     assert(!err);
    878 
    879     uint32_t presentModeCount;
    880     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
    881         demo->gpu, demo->surface, &presentModeCount, NULL);
    882     assert(!err);
    883     VkPresentModeKHR *presentModes =
    884         (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
    885     assert(presentModes);
    886     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
    887         demo->gpu, demo->surface, &presentModeCount, presentModes);
    888     assert(!err);
    889 
    890     VkExtent2D swapchainExtent;
    891     // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
    892     if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
    893         // If the surface size is undefined, the size is set to the size
    894         // of the images requested, which must fit within the minimum and
    895         // maximum values.
    896         swapchainExtent.width = demo->width;
    897         swapchainExtent.height = demo->height;
    898 
    899         if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
    900             swapchainExtent.width = surfCapabilities.minImageExtent.width;
    901         } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) {
    902             swapchainExtent.width = surfCapabilities.maxImageExtent.width;
    903         }
    904 
    905         if (swapchainExtent.height < surfCapabilities.minImageExtent.height) {
    906             swapchainExtent.height = surfCapabilities.minImageExtent.height;
    907         } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {
    908             swapchainExtent.height = surfCapabilities.maxImageExtent.height;
    909         }
    910     } else {
    911         // If the surface size is defined, the swap chain size must match
    912         swapchainExtent = surfCapabilities.currentExtent;
    913         demo->width = surfCapabilities.currentExtent.width;
    914         demo->height = surfCapabilities.currentExtent.height;
    915     }
    916 
    917     // The FIFO present mode is guaranteed by the spec to be supported
    918     // and to have no tearing.  It's a great default present mode to use.
    919     VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
    920     //  There are times when you may wish to use another present mode.  The
    921     //  following code shows how to select them, and the comments provide some
    922     //  reasons you may wish to use them.
    923     //
    924     // It should be noted that Vulkan 1.0 doesn't provide a method for
    925     // synchronizing rendering with the presentation engine's display.  There
    926     // is a method provided for throttling rendering with the display, but
    927     // there are some presentation engines for which this method will not work.
    928     // If an application doesn't throttle its rendering, and if it renders much
    929     // faster than the refresh rate of the display, this can waste power on
    930     // mobile devices.  That is because power is being spent rendering images
    931     // that may never be seen.
    932 //#define DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR
    933 //#define DESIRE_VK_PRESENT_MODE_MAILBOX_KHR
    934 //#define DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR
    935 #if defined(DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR)
    936     // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
    937     // tearing, or have some way of synchronizing their rendering with the
    938     // display.
    939     for (size_t i = 0; i < presentModeCount; ++i) {
    940         if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
    941             swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
    942             break;
    943         }
    944     }
    945 #elif defined(DESIRE_VK_PRESENT_MODE_MAILBOX_KHR)
    946     // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
    947     // generally render a new presentable image every refresh cycle, but are
    948     // occasionally early.  In this case, the application wants the new image
    949     // to be displayed instead of the previously-queued-for-presentation image
    950     // that has not yet been displayed.
    951     for (size_t i = 0; i < presentModeCount; ++i) {
    952         if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
    953             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
    954             break;
    955         }
    956     }
    957 #elif defined(DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR)
    958     // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
    959     // render a new presentable image every refresh cycle, but are occasionally
    960     // late.  In this case (perhaps because of stuttering/latency concerns),
    961     // the application wants the late image to be immediately displayed, even
    962     // though that may mean some tearing.
    963     for (size_t i = 0; i < presentModeCount; ++i) {
    964         if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
    965             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
    966             break;
    967         }
    968     }
    969 #endif
    970 
    971     // Determine the number of VkImage's to use in the swap chain.
    972     // Application desires to only acquire 1 image at a time (which is
    973     // "surfCapabilities.minImageCount").
    974     uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
    975     // If maxImageCount is 0, we can ask for as many images as we want;
    976     // otherwise we're limited to maxImageCount
    977     if ((surfCapabilities.maxImageCount > 0) &&
    978         (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
    979         // Application must settle for fewer images than desired:
    980         desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
    981     }
    982 
    983     VkSurfaceTransformFlagsKHR preTransform;
    984     if (surfCapabilities.supportedTransforms &
    985         VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
    986         preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    987     } else {
    988         preTransform = surfCapabilities.currentTransform;
    989     }
    990 
    991     VkSwapchainCreateInfoKHR swapchain_ci = {
    992         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
    993         .pNext = NULL,
    994         .surface = demo->surface,
    995         .minImageCount = desiredNumOfSwapchainImages,
    996         .imageFormat = demo->format,
    997         .imageColorSpace = demo->color_space,
    998         .imageExtent =
    999             {
   1000              .width = swapchainExtent.width, .height = swapchainExtent.height,
   1001             },
   1002         .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
   1003         .preTransform = preTransform,
   1004         .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
   1005         .imageArrayLayers = 1,
   1006         .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
   1007         .queueFamilyIndexCount = 0,
   1008         .pQueueFamilyIndices = NULL,
   1009         .presentMode = swapchainPresentMode,
   1010         .oldSwapchain = oldSwapchain,
   1011         .clipped = true,
   1012     };
   1013     uint32_t i;
   1014     err = demo->fpCreateSwapchainKHR(demo->device, &swapchain_ci, NULL,
   1015                                      &demo->swapchain);
   1016     assert(!err);
   1017 
   1018     // If we just re-created an existing swapchain, we should destroy the old
   1019     // swapchain at this point.
   1020     // Note: destroying the swapchain also cleans up all its associated
   1021     // presentable images once the platform is done with them.
   1022     if (oldSwapchain != VK_NULL_HANDLE) {
   1023         demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
   1024     }
   1025 
   1026     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
   1027                                         &demo->swapchainImageCount, NULL);
   1028     assert(!err);
   1029 
   1030     VkImage *swapchainImages =
   1031         (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage));
   1032     assert(swapchainImages);
   1033     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
   1034                                         &demo->swapchainImageCount,
   1035                                         swapchainImages);
   1036     assert(!err);
   1037 
   1038     demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) *
   1039                                                demo->swapchainImageCount);
   1040     assert(demo->buffers);
   1041 
   1042     for (i = 0; i < demo->swapchainImageCount; i++) {
   1043         VkImageViewCreateInfo color_image_view = {
   1044             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
   1045             .pNext = NULL,
   1046             .format = demo->format,
   1047             .components =
   1048                 {
   1049                  .r = VK_COMPONENT_SWIZZLE_R,
   1050                  .g = VK_COMPONENT_SWIZZLE_G,
   1051                  .b = VK_COMPONENT_SWIZZLE_B,
   1052                  .a = VK_COMPONENT_SWIZZLE_A,
   1053                 },
   1054             .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
   1055                                  .baseMipLevel = 0,
   1056                                  .levelCount = 1,
   1057                                  .baseArrayLayer = 0,
   1058                                  .layerCount = 1},
   1059             .viewType = VK_IMAGE_VIEW_TYPE_2D,
   1060             .flags = 0,
   1061         };
   1062 
   1063         demo->buffers[i].image = swapchainImages[i];
   1064 
   1065         color_image_view.image = demo->buffers[i].image;
   1066 
   1067         err = vkCreateImageView(demo->device, &color_image_view, NULL,
   1068                                 &demo->buffers[i].view);
   1069         assert(!err);
   1070 
   1071     }
   1072 
   1073     if (NULL != presentModes) {
   1074         free(presentModes);
   1075     }
   1076 }
   1077 
   1078 static void demo_prepare_depth(struct demo *demo) {
   1079     const VkFormat depth_format = VK_FORMAT_D16_UNORM;
   1080     const VkImageCreateInfo image = {
   1081         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
   1082         .pNext = NULL,
   1083         .imageType = VK_IMAGE_TYPE_2D,
   1084         .format = depth_format,
   1085         .extent = {demo->width, demo->height, 1},
   1086         .mipLevels = 1,
   1087         .arrayLayers = 1,
   1088         .samples = VK_SAMPLE_COUNT_1_BIT,
   1089         .tiling = VK_IMAGE_TILING_OPTIMAL,
   1090         .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
   1091         .flags = 0,
   1092     };
   1093 
   1094     VkImageViewCreateInfo view = {
   1095         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
   1096         .pNext = NULL,
   1097         .image = VK_NULL_HANDLE,
   1098         .format = depth_format,
   1099         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
   1100                              .baseMipLevel = 0,
   1101                              .levelCount = 1,
   1102                              .baseArrayLayer = 0,
   1103                              .layerCount = 1},
   1104         .flags = 0,
   1105         .viewType = VK_IMAGE_VIEW_TYPE_2D,
   1106     };
   1107 
   1108     VkMemoryRequirements mem_reqs;
   1109     VkResult U_ASSERT_ONLY err;
   1110     bool U_ASSERT_ONLY pass;
   1111 
   1112     demo->depth.format = depth_format;
   1113 
   1114     /* create image */
   1115     err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image);
   1116     assert(!err);
   1117 
   1118     vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs);
   1119     assert(!err);
   1120 
   1121     demo->depth.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   1122     demo->depth.mem_alloc.pNext = NULL;
   1123     demo->depth.mem_alloc.allocationSize = mem_reqs.size;
   1124     demo->depth.mem_alloc.memoryTypeIndex = 0;
   1125 
   1126     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
   1127                                        0, /* No requirements */
   1128                                        &demo->depth.mem_alloc.memoryTypeIndex);
   1129     assert(pass);
   1130 
   1131     /* allocate memory */
   1132     err = vkAllocateMemory(demo->device, &demo->depth.mem_alloc, NULL,
   1133                            &demo->depth.mem);
   1134     assert(!err);
   1135 
   1136     /* bind memory */
   1137     err =
   1138         vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0);
   1139     assert(!err);
   1140 
   1141     /* create image view */
   1142     view.image = demo->depth.image;
   1143     err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
   1144     assert(!err);
   1145 }
   1146 
   1147 /* Load a ppm file into memory */
   1148 bool loadTexture(const char *filename, uint8_t *rgba_data,
   1149                  VkSubresourceLayout *layout, int32_t *width, int32_t *height) {
   1150 #ifdef __ANDROID__
   1151 #include <lunarg.ppm.h>
   1152     char *cPtr;
   1153     cPtr = (char*)lunarg_ppm;
   1154     if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "P6\n", 3)) {
   1155         return false;
   1156     }
   1157     while(strncmp(cPtr++, "\n", 1));
   1158     sscanf(cPtr, "%u %u", width, height);
   1159     if (rgba_data == NULL) {
   1160         return true;
   1161     }
   1162     while(strncmp(cPtr++, "\n", 1));
   1163     if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "255\n", 4)) {
   1164         return false;
   1165     }
   1166     while(strncmp(cPtr++, "\n", 1));
   1167 
   1168     for (int y = 0; y < *height; y++) {
   1169         uint8_t *rowPtr = rgba_data;
   1170         for (int x = 0; x < *width; x++) {
   1171             memcpy(rowPtr, cPtr, 3);
   1172             rowPtr[3] = 255; /* Alpha of 1 */
   1173             rowPtr += 4;
   1174             cPtr += 3;
   1175         }
   1176         rgba_data += layout->rowPitch;
   1177     }
   1178 
   1179     return true;
   1180 #else
   1181     FILE *fPtr = fopen(filename, "rb");
   1182     char header[256], *cPtr, *tmp;
   1183 
   1184     if (!fPtr)
   1185         return false;
   1186 
   1187     cPtr = fgets(header, 256, fPtr); // P6
   1188     if (cPtr == NULL || strncmp(header, "P6\n", 3)) {
   1189         fclose(fPtr);
   1190         return false;
   1191     }
   1192 
   1193     do {
   1194         cPtr = fgets(header, 256, fPtr);
   1195         if (cPtr == NULL) {
   1196             fclose(fPtr);
   1197             return false;
   1198         }
   1199     } while (!strncmp(header, "#", 1));
   1200 
   1201     sscanf(header, "%u %u", width, height);
   1202     if (rgba_data == NULL) {
   1203         fclose(fPtr);
   1204         return true;
   1205     }
   1206     tmp = fgets(header, 256, fPtr); // Format
   1207     (void)tmp;
   1208     if (cPtr == NULL || strncmp(header, "255\n", 3)) {
   1209         fclose(fPtr);
   1210         return false;
   1211     }
   1212 
   1213     for (int y = 0; y < *height; y++) {
   1214         uint8_t *rowPtr = rgba_data;
   1215         for (int x = 0; x < *width; x++) {
   1216             size_t s = fread(rowPtr, 3, 1, fPtr);
   1217             (void)s;
   1218             rowPtr[3] = 255; /* Alpha of 1 */
   1219             rowPtr += 4;
   1220         }
   1221         rgba_data += layout->rowPitch;
   1222     }
   1223     fclose(fPtr);
   1224     return true;
   1225 #endif
   1226 }
   1227 
   1228 static void demo_prepare_texture_image(struct demo *demo, const char *filename,
   1229                                        struct texture_object *tex_obj,
   1230                                        VkImageTiling tiling,
   1231                                        VkImageUsageFlags usage,
   1232                                        VkFlags required_props) {
   1233     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
   1234     int32_t tex_width;
   1235     int32_t tex_height;
   1236     VkResult U_ASSERT_ONLY err;
   1237     bool U_ASSERT_ONLY pass;
   1238 
   1239     if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) {
   1240         ERR_EXIT("Failed to load textures", "Load Texture Failure");
   1241     }
   1242 
   1243     tex_obj->tex_width = tex_width;
   1244     tex_obj->tex_height = tex_height;
   1245 
   1246     const VkImageCreateInfo image_create_info = {
   1247         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
   1248         .pNext = NULL,
   1249         .imageType = VK_IMAGE_TYPE_2D,
   1250         .format = tex_format,
   1251         .extent = {tex_width, tex_height, 1},
   1252         .mipLevels = 1,
   1253         .arrayLayers = 1,
   1254         .samples = VK_SAMPLE_COUNT_1_BIT,
   1255         .tiling = tiling,
   1256         .usage = usage,
   1257         .flags = 0,
   1258         .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
   1259     };
   1260 
   1261     VkMemoryRequirements mem_reqs;
   1262 
   1263     err =
   1264         vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image);
   1265     assert(!err);
   1266 
   1267     vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
   1268 
   1269     tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   1270     tex_obj->mem_alloc.pNext = NULL;
   1271     tex_obj->mem_alloc.allocationSize = mem_reqs.size;
   1272     tex_obj->mem_alloc.memoryTypeIndex = 0;
   1273 
   1274     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
   1275                                        required_props,
   1276                                        &tex_obj->mem_alloc.memoryTypeIndex);
   1277     assert(pass);
   1278 
   1279     /* allocate memory */
   1280     err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL,
   1281                            &(tex_obj->mem));
   1282     assert(!err);
   1283 
   1284     /* bind memory */
   1285     err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0);
   1286     assert(!err);
   1287 
   1288     if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
   1289         const VkImageSubresource subres = {
   1290             .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
   1291             .mipLevel = 0,
   1292             .arrayLayer = 0,
   1293         };
   1294         VkSubresourceLayout layout;
   1295         void *data;
   1296 
   1297         vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres,
   1298                                     &layout);
   1299 
   1300         err = vkMapMemory(demo->device, tex_obj->mem, 0,
   1301                           tex_obj->mem_alloc.allocationSize, 0, &data);
   1302         assert(!err);
   1303 
   1304         if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) {
   1305             fprintf(stderr, "Error loading texture: %s\n", filename);
   1306         }
   1307 
   1308         vkUnmapMemory(demo->device, tex_obj->mem);
   1309     }
   1310 
   1311     tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
   1312 }
   1313 
   1314 static void demo_destroy_texture_image(struct demo *demo,
   1315                                        struct texture_object *tex_objs) {
   1316     /* clean up staging resources */
   1317     vkFreeMemory(demo->device, tex_objs->mem, NULL);
   1318     vkDestroyImage(demo->device, tex_objs->image, NULL);
   1319 }
   1320 
   1321 static void demo_prepare_textures(struct demo *demo) {
   1322     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
   1323     VkFormatProperties props;
   1324     uint32_t i;
   1325 
   1326     vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
   1327 
   1328     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1329         VkResult U_ASSERT_ONLY err;
   1330 
   1331         if ((props.linearTilingFeatures &
   1332              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
   1333             !demo->use_staging_buffer) {
   1334             /* Device can texture using linear textures */
   1335             demo_prepare_texture_image(
   1336                 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_LINEAR,
   1337                 VK_IMAGE_USAGE_SAMPLED_BIT,
   1338                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
   1339                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
   1340             // Nothing in the pipeline needs to be complete to start, and don't allow fragment
   1341             // shader to run until layout transition completes
   1342             demo_set_image_layout(demo, demo->textures[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
   1343                                   VK_IMAGE_LAYOUT_PREINITIALIZED, demo->textures[i].imageLayout,
   1344                                   VK_ACCESS_HOST_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
   1345                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
   1346         } else if (props.optimalTilingFeatures &
   1347                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
   1348             /* Must use staging buffer to copy linear texture to optimized */
   1349             struct texture_object staging_texture;
   1350 
   1351             memset(&staging_texture, 0, sizeof(staging_texture));
   1352             demo_prepare_texture_image(
   1353                 demo, tex_files[i], &staging_texture, VK_IMAGE_TILING_LINEAR,
   1354                 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
   1355                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
   1356                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
   1357 
   1358             demo_prepare_texture_image(
   1359                 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL,
   1360                 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
   1361                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
   1362 
   1363             demo_set_image_layout(demo, staging_texture.image,
   1364                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1365                                   VK_IMAGE_LAYOUT_PREINITIALIZED,
   1366                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
   1367                                   VK_ACCESS_HOST_WRITE_BIT,
   1368                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
   1369                                   VK_PIPELINE_STAGE_TRANSFER_BIT);
   1370 
   1371             demo_set_image_layout(demo, demo->textures[i].image,
   1372                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1373                                   VK_IMAGE_LAYOUT_PREINITIALIZED,
   1374                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
   1375                                   VK_ACCESS_HOST_WRITE_BIT,
   1376                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
   1377                                   VK_PIPELINE_STAGE_TRANSFER_BIT);
   1378 
   1379             VkImageCopy copy_region = {
   1380                 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
   1381                 .srcOffset = {0, 0, 0},
   1382                 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
   1383                 .dstOffset = {0, 0, 0},
   1384                 .extent = {staging_texture.tex_width,
   1385                            staging_texture.tex_height, 1},
   1386             };
   1387             vkCmdCopyImage(
   1388                 demo->cmd, staging_texture.image,
   1389                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image,
   1390                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
   1391 
   1392             demo_set_image_layout(demo, demo->textures[i].image,
   1393                                   VK_IMAGE_ASPECT_COLOR_BIT,
   1394                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
   1395                                   demo->textures[i].imageLayout,
   1396                                   VK_ACCESS_TRANSFER_WRITE_BIT,
   1397                                   VK_PIPELINE_STAGE_TRANSFER_BIT,
   1398                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
   1399 
   1400             demo_flush_init_cmd(demo);
   1401 
   1402             demo_destroy_texture_image(demo, &staging_texture);
   1403         } else {
   1404             /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */
   1405             assert(!"No support for R8G8B8A8_UNORM as texture image format");
   1406         }
   1407 
   1408         const VkSamplerCreateInfo sampler = {
   1409             .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
   1410             .pNext = NULL,
   1411             .magFilter = VK_FILTER_NEAREST,
   1412             .minFilter = VK_FILTER_NEAREST,
   1413             .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
   1414             .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1415             .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1416             .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
   1417             .mipLodBias = 0.0f,
   1418             .anisotropyEnable = VK_FALSE,
   1419             .maxAnisotropy = 1,
   1420             .compareOp = VK_COMPARE_OP_NEVER,
   1421             .minLod = 0.0f,
   1422             .maxLod = 0.0f,
   1423             .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
   1424             .unnormalizedCoordinates = VK_FALSE,
   1425         };
   1426 
   1427         VkImageViewCreateInfo view = {
   1428             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
   1429             .pNext = NULL,
   1430             .image = VK_NULL_HANDLE,
   1431             .viewType = VK_IMAGE_VIEW_TYPE_2D,
   1432             .format = tex_format,
   1433             .components =
   1434                 {
   1435                  VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
   1436                  VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
   1437                 },
   1438             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
   1439             .flags = 0,
   1440         };
   1441 
   1442         /* create sampler */
   1443         err = vkCreateSampler(demo->device, &sampler, NULL,
   1444                               &demo->textures[i].sampler);
   1445         assert(!err);
   1446 
   1447         /* create image view */
   1448         view.image = demo->textures[i].image;
   1449         err = vkCreateImageView(demo->device, &view, NULL,
   1450                                 &demo->textures[i].view);
   1451         assert(!err);
   1452     }
   1453 }
   1454 
   1455 void demo_prepare_cube_data_buffer(struct demo *demo) {
   1456     VkBufferCreateInfo buf_info;
   1457     VkMemoryRequirements mem_reqs;
   1458     uint8_t *pData;
   1459     int i;
   1460     mat4x4 MVP, VP;
   1461     VkResult U_ASSERT_ONLY err;
   1462     bool U_ASSERT_ONLY pass;
   1463     struct vktexcube_vs_uniform data;
   1464 
   1465     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
   1466     mat4x4_mul(MVP, VP, demo->model_matrix);
   1467     memcpy(data.mvp, MVP, sizeof(MVP));
   1468     //    dumpMatrix("MVP", MVP);
   1469 
   1470     for (i = 0; i < 12 * 3; i++) {
   1471         data.position[i][0] = g_vertex_buffer_data[i * 3];
   1472         data.position[i][1] = g_vertex_buffer_data[i * 3 + 1];
   1473         data.position[i][2] = g_vertex_buffer_data[i * 3 + 2];
   1474         data.position[i][3] = 1.0f;
   1475         data.attr[i][0] = g_uv_buffer_data[2 * i];
   1476         data.attr[i][1] = g_uv_buffer_data[2 * i + 1];
   1477         data.attr[i][2] = 0;
   1478         data.attr[i][3] = 0;
   1479     }
   1480 
   1481     memset(&buf_info, 0, sizeof(buf_info));
   1482     buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
   1483     buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
   1484     buf_info.size = sizeof(data);
   1485     err =
   1486         vkCreateBuffer(demo->device, &buf_info, NULL, &demo->uniform_data.buf);
   1487     assert(!err);
   1488 
   1489     vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf,
   1490                                   &mem_reqs);
   1491 
   1492     demo->uniform_data.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   1493     demo->uniform_data.mem_alloc.pNext = NULL;
   1494     demo->uniform_data.mem_alloc.allocationSize = mem_reqs.size;
   1495     demo->uniform_data.mem_alloc.memoryTypeIndex = 0;
   1496 
   1497     pass = memory_type_from_properties(
   1498         demo, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
   1499                                            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
   1500         &demo->uniform_data.mem_alloc.memoryTypeIndex);
   1501     assert(pass);
   1502 
   1503     err = vkAllocateMemory(demo->device, &demo->uniform_data.mem_alloc, NULL,
   1504                            &(demo->uniform_data.mem));
   1505     assert(!err);
   1506 
   1507     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
   1508                       demo->uniform_data.mem_alloc.allocationSize, 0,
   1509                       (void **)&pData);
   1510     assert(!err);
   1511 
   1512     memcpy(pData, &data, sizeof data);
   1513 
   1514     vkUnmapMemory(demo->device, demo->uniform_data.mem);
   1515 
   1516     err = vkBindBufferMemory(demo->device, demo->uniform_data.buf,
   1517                              demo->uniform_data.mem, 0);
   1518     assert(!err);
   1519 
   1520     demo->uniform_data.buffer_info.buffer = demo->uniform_data.buf;
   1521     demo->uniform_data.buffer_info.offset = 0;
   1522     demo->uniform_data.buffer_info.range = sizeof(data);
   1523 }
   1524 
   1525 static void demo_prepare_descriptor_layout(struct demo *demo) {
   1526     const VkDescriptorSetLayoutBinding layout_bindings[2] = {
   1527             [0] =
   1528                 {
   1529                  .binding = 0,
   1530                  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
   1531                  .descriptorCount = 1,
   1532                  .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
   1533                  .pImmutableSamplers = NULL,
   1534                 },
   1535             [1] =
   1536                 {
   1537                  .binding = 1,
   1538                  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
   1539                  .descriptorCount = DEMO_TEXTURE_COUNT,
   1540                  .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
   1541                  .pImmutableSamplers = NULL,
   1542                 },
   1543     };
   1544     const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
   1545         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
   1546         .pNext = NULL,
   1547         .bindingCount = 2,
   1548         .pBindings = layout_bindings,
   1549     };
   1550     VkResult U_ASSERT_ONLY err;
   1551 
   1552     err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL,
   1553                                       &demo->desc_layout);
   1554     assert(!err);
   1555 
   1556     const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
   1557         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
   1558         .pNext = NULL,
   1559         .setLayoutCount = 1,
   1560         .pSetLayouts = &demo->desc_layout,
   1561     };
   1562 
   1563     err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL,
   1564                                  &demo->pipeline_layout);
   1565     assert(!err);
   1566 }
   1567 
   1568 static void demo_prepare_render_pass(struct demo *demo) {
   1569     // The initial layout for the color and depth attachments will be LAYOUT_UNDEFINED
   1570     // because at the start of the renderpass, we don't care about their contents.
   1571     // At the start of the subpass, the color attachment's layout will be transitioned
   1572     // to LAYOUT_COLOR_ATTACHMENT_OPTIMAL and the depth stencil attachment's layout
   1573     // will be transitioned to LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL.  At the end of
   1574     // the renderpass, the color attachment's layout will be transitioned to
   1575     // LAYOUT_PRESENT_SRC_KHR to be ready to present.  This is all done as part of
   1576     // the renderpass, no barriers are necessary.
   1577     const VkAttachmentDescription attachments[2] = {
   1578             [0] =
   1579                 {
   1580                  .format = demo->format,
   1581                  .samples = VK_SAMPLE_COUNT_1_BIT,
   1582                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
   1583                  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
   1584                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
   1585                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1586                  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
   1587                  .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
   1588                 },
   1589             [1] =
   1590                 {
   1591                  .format = demo->depth.format,
   1592                  .samples = VK_SAMPLE_COUNT_1_BIT,
   1593                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
   1594                  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1595                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
   1596                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
   1597                  .initialLayout =
   1598                      VK_IMAGE_LAYOUT_UNDEFINED,
   1599                  .finalLayout =
   1600                      VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
   1601                 },
   1602     };
   1603     const VkAttachmentReference color_reference = {
   1604         .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
   1605     };
   1606     const VkAttachmentReference depth_reference = {
   1607         .attachment = 1,
   1608         .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
   1609     };
   1610     const VkSubpassDescription subpass = {
   1611         .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
   1612         .flags = 0,
   1613         .inputAttachmentCount = 0,
   1614         .pInputAttachments = NULL,
   1615         .colorAttachmentCount = 1,
   1616         .pColorAttachments = &color_reference,
   1617         .pResolveAttachments = NULL,
   1618         .pDepthStencilAttachment = &depth_reference,
   1619         .preserveAttachmentCount = 0,
   1620         .pPreserveAttachments = NULL,
   1621     };
   1622     const VkRenderPassCreateInfo rp_info = {
   1623         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
   1624         .pNext = NULL,
   1625         .attachmentCount = 2,
   1626         .pAttachments = attachments,
   1627         .subpassCount = 1,
   1628         .pSubpasses = &subpass,
   1629         .dependencyCount = 0,
   1630         .pDependencies = NULL,
   1631     };
   1632     VkResult U_ASSERT_ONLY err;
   1633 
   1634     err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
   1635     assert(!err);
   1636 }
   1637 
   1638 //TODO: Merge shader reading
   1639 #ifndef __ANDROID__
   1640 static VkShaderModule
   1641 demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) {
   1642     VkShaderModule module;
   1643     VkShaderModuleCreateInfo moduleCreateInfo;
   1644     VkResult U_ASSERT_ONLY err;
   1645 
   1646     moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   1647     moduleCreateInfo.pNext = NULL;
   1648 
   1649     moduleCreateInfo.codeSize = size;
   1650     moduleCreateInfo.pCode = code;
   1651     moduleCreateInfo.flags = 0;
   1652     err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
   1653     assert(!err);
   1654 
   1655     return module;
   1656 }
   1657 
   1658 char *demo_read_spv(const char *filename, size_t *psize) {
   1659     long int size;
   1660     size_t U_ASSERT_ONLY retval;
   1661     void *shader_code;
   1662 
   1663     FILE *fp = fopen(filename, "rb");
   1664     if (!fp)
   1665         return NULL;
   1666 
   1667     fseek(fp, 0L, SEEK_END);
   1668     size = ftell(fp);
   1669 
   1670     fseek(fp, 0L, SEEK_SET);
   1671 
   1672     shader_code = malloc(size);
   1673     retval = fread(shader_code, size, 1, fp);
   1674     assert(retval == 1);
   1675 
   1676     *psize = size;
   1677 
   1678     fclose(fp);
   1679     return shader_code;
   1680 }
   1681 #endif
   1682 
   1683 static VkShaderModule demo_prepare_vs(struct demo *demo) {
   1684 #ifdef __ANDROID__
   1685     VkShaderModuleCreateInfo sh_info = {};
   1686     sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   1687 
   1688 #include "cube.vert.h"
   1689     sh_info.codeSize = sizeof(cube_vert);
   1690     sh_info.pCode = cube_vert;
   1691     VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->vert_shader_module);
   1692     assert(!err);
   1693 #else
   1694     void *vertShaderCode;
   1695     size_t size;
   1696 
   1697     vertShaderCode = demo_read_spv("cube-vert.spv", &size);
   1698 
   1699     demo->vert_shader_module =
   1700         demo_prepare_shader_module(demo, vertShaderCode, size);
   1701 
   1702     free(vertShaderCode);
   1703 #endif
   1704 
   1705     return demo->vert_shader_module;
   1706 }
   1707 
   1708 static VkShaderModule demo_prepare_fs(struct demo *demo) {
   1709 #ifdef __ANDROID__
   1710     VkShaderModuleCreateInfo sh_info = {};
   1711     sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
   1712 
   1713 #include "cube.frag.h"
   1714     sh_info.codeSize = sizeof(cube_frag);
   1715     sh_info.pCode = cube_frag;
   1716     VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->frag_shader_module);
   1717     assert(!err);
   1718 #else
   1719     void *fragShaderCode;
   1720     size_t size;
   1721 
   1722     fragShaderCode = demo_read_spv("cube-frag.spv", &size);
   1723 
   1724     demo->frag_shader_module =
   1725         demo_prepare_shader_module(demo, fragShaderCode, size);
   1726 
   1727     free(fragShaderCode);
   1728 #endif
   1729 
   1730     return demo->frag_shader_module;
   1731 }
   1732 
   1733 static void demo_prepare_pipeline(struct demo *demo) {
   1734     VkGraphicsPipelineCreateInfo pipeline;
   1735     VkPipelineCacheCreateInfo pipelineCache;
   1736     VkPipelineVertexInputStateCreateInfo vi;
   1737     VkPipelineInputAssemblyStateCreateInfo ia;
   1738     VkPipelineRasterizationStateCreateInfo rs;
   1739     VkPipelineColorBlendStateCreateInfo cb;
   1740     VkPipelineDepthStencilStateCreateInfo ds;
   1741     VkPipelineViewportStateCreateInfo vp;
   1742     VkPipelineMultisampleStateCreateInfo ms;
   1743     VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
   1744     VkPipelineDynamicStateCreateInfo dynamicState;
   1745     VkResult U_ASSERT_ONLY err;
   1746 
   1747     memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
   1748     memset(&dynamicState, 0, sizeof dynamicState);
   1749     dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
   1750     dynamicState.pDynamicStates = dynamicStateEnables;
   1751 
   1752     memset(&pipeline, 0, sizeof(pipeline));
   1753     pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
   1754     pipeline.layout = demo->pipeline_layout;
   1755 
   1756     memset(&vi, 0, sizeof(vi));
   1757     vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
   1758 
   1759     memset(&ia, 0, sizeof(ia));
   1760     ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
   1761     ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
   1762 
   1763     memset(&rs, 0, sizeof(rs));
   1764     rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
   1765     rs.polygonMode = VK_POLYGON_MODE_FILL;
   1766     rs.cullMode = VK_CULL_MODE_BACK_BIT;
   1767     rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
   1768     rs.depthClampEnable = VK_FALSE;
   1769     rs.rasterizerDiscardEnable = VK_FALSE;
   1770     rs.depthBiasEnable = VK_FALSE;
   1771     rs.lineWidth = 1.0f;
   1772 
   1773     memset(&cb, 0, sizeof(cb));
   1774     cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
   1775     VkPipelineColorBlendAttachmentState att_state[1];
   1776     memset(att_state, 0, sizeof(att_state));
   1777     att_state[0].colorWriteMask = 0xf;
   1778     att_state[0].blendEnable = VK_FALSE;
   1779     cb.attachmentCount = 1;
   1780     cb.pAttachments = att_state;
   1781 
   1782     memset(&vp, 0, sizeof(vp));
   1783     vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
   1784     vp.viewportCount = 1;
   1785     dynamicStateEnables[dynamicState.dynamicStateCount++] =
   1786         VK_DYNAMIC_STATE_VIEWPORT;
   1787     vp.scissorCount = 1;
   1788     dynamicStateEnables[dynamicState.dynamicStateCount++] =
   1789         VK_DYNAMIC_STATE_SCISSOR;
   1790 
   1791     memset(&ds, 0, sizeof(ds));
   1792     ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
   1793     ds.depthTestEnable = VK_TRUE;
   1794     ds.depthWriteEnable = VK_TRUE;
   1795     ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
   1796     ds.depthBoundsTestEnable = VK_FALSE;
   1797     ds.back.failOp = VK_STENCIL_OP_KEEP;
   1798     ds.back.passOp = VK_STENCIL_OP_KEEP;
   1799     ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
   1800     ds.stencilTestEnable = VK_FALSE;
   1801     ds.front = ds.back;
   1802 
   1803     memset(&ms, 0, sizeof(ms));
   1804     ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
   1805     ms.pSampleMask = NULL;
   1806     ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
   1807 
   1808     // Two stages: vs and fs
   1809     pipeline.stageCount = 2;
   1810     VkPipelineShaderStageCreateInfo shaderStages[2];
   1811     memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
   1812 
   1813     shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   1814     shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
   1815     shaderStages[0].module = demo_prepare_vs(demo);
   1816     shaderStages[0].pName = "main";
   1817 
   1818     shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
   1819     shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
   1820     shaderStages[1].module = demo_prepare_fs(demo);
   1821     shaderStages[1].pName = "main";
   1822 
   1823     memset(&pipelineCache, 0, sizeof(pipelineCache));
   1824     pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
   1825 
   1826     err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL,
   1827                                 &demo->pipelineCache);
   1828     assert(!err);
   1829 
   1830     pipeline.pVertexInputState = &vi;
   1831     pipeline.pInputAssemblyState = &ia;
   1832     pipeline.pRasterizationState = &rs;
   1833     pipeline.pColorBlendState = &cb;
   1834     pipeline.pMultisampleState = &ms;
   1835     pipeline.pViewportState = &vp;
   1836     pipeline.pDepthStencilState = &ds;
   1837     pipeline.pStages = shaderStages;
   1838     pipeline.renderPass = demo->render_pass;
   1839     pipeline.pDynamicState = &dynamicState;
   1840 
   1841     pipeline.renderPass = demo->render_pass;
   1842 
   1843     err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1,
   1844                                     &pipeline, NULL, &demo->pipeline);
   1845     assert(!err);
   1846 
   1847     vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
   1848     vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
   1849 }
   1850 
   1851 static void demo_prepare_descriptor_pool(struct demo *demo) {
   1852     const VkDescriptorPoolSize type_counts[2] = {
   1853             [0] =
   1854                 {
   1855                  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
   1856                  .descriptorCount = 1,
   1857                 },
   1858             [1] =
   1859                 {
   1860                  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
   1861                  .descriptorCount = DEMO_TEXTURE_COUNT,
   1862                 },
   1863     };
   1864     const VkDescriptorPoolCreateInfo descriptor_pool = {
   1865         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
   1866         .pNext = NULL,
   1867         .maxSets = 1,
   1868         .poolSizeCount = 2,
   1869         .pPoolSizes = type_counts,
   1870     };
   1871     VkResult U_ASSERT_ONLY err;
   1872 
   1873     err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL,
   1874                                  &demo->desc_pool);
   1875     assert(!err);
   1876 }
   1877 
   1878 static void demo_prepare_descriptor_set(struct demo *demo) {
   1879     VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
   1880     VkWriteDescriptorSet writes[2];
   1881     VkResult U_ASSERT_ONLY err;
   1882     uint32_t i;
   1883 
   1884     VkDescriptorSetAllocateInfo alloc_info = {
   1885         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
   1886         .pNext = NULL,
   1887         .descriptorPool = demo->desc_pool,
   1888         .descriptorSetCount = 1,
   1889         .pSetLayouts = &demo->desc_layout};
   1890     err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
   1891     assert(!err);
   1892 
   1893     memset(&tex_descs, 0, sizeof(tex_descs));
   1894     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   1895         tex_descs[i].sampler = demo->textures[i].sampler;
   1896         tex_descs[i].imageView = demo->textures[i].view;
   1897         tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
   1898     }
   1899 
   1900     memset(&writes, 0, sizeof(writes));
   1901 
   1902     writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
   1903     writes[0].dstSet = demo->desc_set;
   1904     writes[0].descriptorCount = 1;
   1905     writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
   1906     writes[0].pBufferInfo = &demo->uniform_data.buffer_info;
   1907 
   1908     writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
   1909     writes[1].dstSet = demo->desc_set;
   1910     writes[1].dstBinding = 1;
   1911     writes[1].descriptorCount = DEMO_TEXTURE_COUNT;
   1912     writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
   1913     writes[1].pImageInfo = tex_descs;
   1914 
   1915     vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL);
   1916 }
   1917 
   1918 static void demo_prepare_framebuffers(struct demo *demo) {
   1919     VkImageView attachments[2];
   1920     attachments[1] = demo->depth.view;
   1921 
   1922     const VkFramebufferCreateInfo fb_info = {
   1923         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
   1924         .pNext = NULL,
   1925         .renderPass = demo->render_pass,
   1926         .attachmentCount = 2,
   1927         .pAttachments = attachments,
   1928         .width = demo->width,
   1929         .height = demo->height,
   1930         .layers = 1,
   1931     };
   1932     VkResult U_ASSERT_ONLY err;
   1933     uint32_t i;
   1934 
   1935     demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount *
   1936                                                  sizeof(VkFramebuffer));
   1937     assert(demo->framebuffers);
   1938 
   1939     for (i = 0; i < demo->swapchainImageCount; i++) {
   1940         attachments[0] = demo->buffers[i].view;
   1941         err = vkCreateFramebuffer(demo->device, &fb_info, NULL,
   1942                                   &demo->framebuffers[i]);
   1943         assert(!err);
   1944     }
   1945 }
   1946 
   1947 static void demo_prepare(struct demo *demo) {
   1948     VkResult U_ASSERT_ONLY err;
   1949 
   1950     const VkCommandPoolCreateInfo cmd_pool_info = {
   1951         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
   1952         .pNext = NULL,
   1953         .queueFamilyIndex = demo->graphics_queue_family_index,
   1954         .flags = 0,
   1955     };
   1956     err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
   1957                               &demo->cmd_pool);
   1958     assert(!err);
   1959 
   1960     const VkCommandBufferAllocateInfo cmd = {
   1961         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
   1962         .pNext = NULL,
   1963         .commandPool = demo->cmd_pool,
   1964         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
   1965         .commandBufferCount = 1,
   1966     };
   1967 
   1968     demo_prepare_buffers(demo);
   1969     demo_prepare_depth(demo);
   1970     demo_prepare_textures(demo);
   1971     demo_prepare_cube_data_buffer(demo);
   1972 
   1973     demo_prepare_descriptor_layout(demo);
   1974     demo_prepare_render_pass(demo);
   1975     demo_prepare_pipeline(demo);
   1976 
   1977     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
   1978         err =
   1979             vkAllocateCommandBuffers(demo->device, &cmd, &demo->buffers[i].cmd);
   1980         assert(!err);
   1981     }
   1982 
   1983     if (demo->separate_present_queue) {
   1984         const VkCommandPoolCreateInfo cmd_pool_info = {
   1985             .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
   1986             .pNext = NULL,
   1987             .queueFamilyIndex = demo->present_queue_family_index,
   1988             .flags = 0,
   1989         };
   1990         err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
   1991                                   &demo->present_cmd_pool);
   1992         assert(!err);
   1993         const VkCommandBufferAllocateInfo cmd = {
   1994             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
   1995             .pNext = NULL,
   1996             .commandPool = demo->present_cmd_pool,
   1997             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
   1998             .commandBufferCount = 1,
   1999         };
   2000         for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
   2001             err = vkAllocateCommandBuffers(
   2002                 demo->device, &cmd, &demo->buffers[i].graphics_to_present_cmd);
   2003             assert(!err);
   2004             demo_build_image_ownership_cmd(demo, i);
   2005         }
   2006     }
   2007 
   2008     demo_prepare_descriptor_pool(demo);
   2009     demo_prepare_descriptor_set(demo);
   2010 
   2011     demo_prepare_framebuffers(demo);
   2012 
   2013     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
   2014         demo->current_buffer = i;
   2015         demo_draw_build_cmd(demo, demo->buffers[i].cmd);
   2016     }
   2017 
   2018     /*
   2019      * Prepare functions above may generate pipeline commands
   2020      * that need to be flushed before beginning the render loop.
   2021      */
   2022     demo_flush_init_cmd(demo);
   2023 
   2024     demo->current_buffer = 0;
   2025     demo->prepared = true;
   2026 }
   2027 
   2028 static void demo_cleanup(struct demo *demo) {
   2029     uint32_t i;
   2030 
   2031     demo->prepared = false;
   2032     vkDeviceWaitIdle(demo->device);
   2033 
   2034     // Wait for fences from present operations
   2035     for (i = 0; i < FRAME_LAG; i++) {
   2036         vkWaitForFences(demo->device, 1, &demo->fences[i], VK_TRUE, UINT64_MAX);
   2037         vkDestroyFence(demo->device, demo->fences[i], NULL);
   2038         vkDestroySemaphore(demo->device, demo->image_acquired_semaphores[i], NULL);
   2039         vkDestroySemaphore(demo->device, demo->draw_complete_semaphores[i], NULL);
   2040         if (demo->separate_present_queue) {
   2041             vkDestroySemaphore(demo->device, demo->image_ownership_semaphores[i], NULL);
   2042         }
   2043     }
   2044 
   2045     for (i = 0; i < demo->swapchainImageCount; i++) {
   2046         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
   2047     }
   2048     free(demo->framebuffers);
   2049     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
   2050 
   2051     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
   2052     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
   2053     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
   2054     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
   2055     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
   2056 
   2057     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   2058         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
   2059         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
   2060         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
   2061         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
   2062     }
   2063     demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
   2064 
   2065     vkDestroyImageView(demo->device, demo->depth.view, NULL);
   2066     vkDestroyImage(demo->device, demo->depth.image, NULL);
   2067     vkFreeMemory(demo->device, demo->depth.mem, NULL);
   2068 
   2069     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
   2070     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
   2071 
   2072     for (i = 0; i < demo->swapchainImageCount; i++) {
   2073         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
   2074         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
   2075                              &demo->buffers[i].cmd);
   2076     }
   2077     free(demo->buffers);
   2078     free(demo->queue_props);
   2079     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
   2080 
   2081     if (demo->separate_present_queue) {
   2082         vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL);
   2083     }
   2084     vkDestroyDevice(demo->device, NULL);
   2085     if (demo->validate) {
   2086         demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
   2087     }
   2088     vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
   2089     vkDestroyInstance(demo->inst, NULL);
   2090 
   2091 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   2092     if (demo->use_xlib) {
   2093         XDestroyWindow(demo->display, demo->xlib_window);
   2094         XCloseDisplay(demo->display);
   2095     } else {
   2096         xcb_destroy_window(demo->connection, demo->xcb_window);
   2097         xcb_disconnect(demo->connection);
   2098     }
   2099     free(demo->atom_wm_delete_window);
   2100 #elif defined(VK_USE_PLATFORM_XCB_KHR)
   2101     xcb_destroy_window(demo->connection, demo->xcb_window);
   2102     xcb_disconnect(demo->connection);
   2103     free(demo->atom_wm_delete_window);
   2104 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   2105     wl_shell_surface_destroy(demo->shell_surface);
   2106     wl_surface_destroy(demo->window);
   2107     wl_shell_destroy(demo->shell);
   2108     wl_compositor_destroy(demo->compositor);
   2109     wl_registry_destroy(demo->registry);
   2110     wl_display_disconnect(demo->display);
   2111 #endif
   2112 }
   2113 
   2114 static void demo_resize(struct demo *demo) {
   2115     uint32_t i;
   2116 
   2117     // Don't react to resize until after first initialization.
   2118     if (!demo->prepared) {
   2119         return;
   2120     }
   2121     // In order to properly resize the window, we must re-create the swapchain
   2122     // AND redo the command buffers, etc.
   2123     //
   2124     // First, perform part of the demo_cleanup() function:
   2125     demo->prepared = false;
   2126     vkDeviceWaitIdle(demo->device);
   2127 
   2128     for (i = 0; i < demo->swapchainImageCount; i++) {
   2129         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
   2130     }
   2131     free(demo->framebuffers);
   2132     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
   2133 
   2134     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
   2135     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
   2136     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
   2137     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
   2138     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
   2139 
   2140     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
   2141         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
   2142         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
   2143         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
   2144         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
   2145     }
   2146 
   2147     vkDestroyImageView(demo->device, demo->depth.view, NULL);
   2148     vkDestroyImage(demo->device, demo->depth.image, NULL);
   2149     vkFreeMemory(demo->device, demo->depth.mem, NULL);
   2150 
   2151     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
   2152     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
   2153 
   2154     for (i = 0; i < demo->swapchainImageCount; i++) {
   2155         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
   2156         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
   2157                              &demo->buffers[i].cmd);
   2158     }
   2159     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
   2160     if (demo->separate_present_queue) {
   2161         vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL);
   2162     }
   2163     free(demo->buffers);
   2164 
   2165     // Second, re-perform the demo_prepare() function, which will re-create the
   2166     // swapchain:
   2167     demo_prepare(demo);
   2168 }
   2169 
   2170 // On MS-Windows, make this a global, so it's available to WndProc()
   2171 struct demo demo;
   2172 
   2173 #if defined(VK_USE_PLATFORM_WIN32_KHR)
   2174 static void demo_run(struct demo *demo) {
   2175     if (!demo->prepared)
   2176         return;
   2177 
   2178     demo_update_data_buffer(demo);
   2179     demo_draw(demo);
   2180     demo->curFrame++;
   2181     if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) {
   2182         PostQuitMessage(validation_error);
   2183     }
   2184 }
   2185 
   2186 // MS-Windows event handling function:
   2187 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
   2188     switch (uMsg) {
   2189     case WM_CLOSE:
   2190         PostQuitMessage(validation_error);
   2191         break;
   2192     case WM_PAINT:
   2193         // The validation callback calls MessageBox which can generate paint
   2194         // events - don't make more Vulkan calls if we got here from the
   2195         // callback
   2196         if (!in_callback) {
   2197             demo_run(&demo);
   2198         }
   2199         break;
   2200     case WM_GETMINMAXINFO:     // set window's minimum size
   2201         ((MINMAXINFO*)lParam)->ptMinTrackSize = demo.minsize;
   2202         return 0;
   2203     case WM_SIZE:
   2204         // Resize the application to the new window size, except when
   2205         // it was minimized. Vulkan doesn't support images or swapchains
   2206         // with width=0 and height=0.
   2207         if (wParam != SIZE_MINIMIZED) {
   2208             demo.width = lParam & 0xffff;
   2209             demo.height = (lParam & 0xffff0000) >> 16;
   2210             demo_resize(&demo);
   2211         }
   2212         break;
   2213     default:
   2214         break;
   2215     }
   2216     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
   2217 }
   2218 
   2219 static void demo_create_window(struct demo *demo) {
   2220     WNDCLASSEX win_class;
   2221 
   2222     // Initialize the window class structure:
   2223     win_class.cbSize = sizeof(WNDCLASSEX);
   2224     win_class.style = CS_HREDRAW | CS_VREDRAW;
   2225     win_class.lpfnWndProc = WndProc;
   2226     win_class.cbClsExtra = 0;
   2227     win_class.cbWndExtra = 0;
   2228     win_class.hInstance = demo->connection; // hInstance
   2229     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
   2230     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
   2231     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
   2232     win_class.lpszMenuName = NULL;
   2233     win_class.lpszClassName = demo->name;
   2234     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
   2235     // Register window class:
   2236     if (!RegisterClassEx(&win_class)) {
   2237         // It didn't work, so try to give a useful error:
   2238         printf("Unexpected error trying to start the application!\n");
   2239         fflush(stdout);
   2240         exit(1);
   2241     }
   2242     // Create window with the registered class:
   2243     RECT wr = {0, 0, demo->width, demo->height};
   2244     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
   2245     demo->window = CreateWindowEx(0,
   2246                                   demo->name,           // class name
   2247                                   demo->name,           // app name
   2248                                   WS_OVERLAPPEDWINDOW | // window style
   2249                                       WS_VISIBLE | WS_SYSMENU,
   2250                                   100, 100,           // x/y coords
   2251                                   wr.right - wr.left, // width
   2252                                   wr.bottom - wr.top, // height
   2253                                   NULL,               // handle to parent
   2254                                   NULL,               // handle to menu
   2255                                   demo->connection,   // hInstance
   2256                                   NULL);              // no extra parameters
   2257     if (!demo->window) {
   2258         // It didn't work, so try to give a useful error:
   2259         printf("Cannot create a window in which to draw!\n");
   2260         fflush(stdout);
   2261         exit(1);
   2262     }
   2263     // Window client area size must be at least 1 pixel high, to prevent crash.
   2264     demo->minsize.x = GetSystemMetrics(SM_CXMINTRACK);
   2265     demo->minsize.y = GetSystemMetrics(SM_CYMINTRACK)+1;
   2266 }
   2267 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
   2268 static void demo_create_xlib_window(struct demo *demo) {
   2269 
   2270     demo->display = XOpenDisplay(NULL);
   2271     long visualMask = VisualScreenMask;
   2272     int numberOfVisuals;
   2273     XVisualInfo vInfoTemplate={};
   2274     vInfoTemplate.screen = DefaultScreen(demo->display);
   2275     XVisualInfo *visualInfo = XGetVisualInfo(demo->display, visualMask,
   2276                                              &vInfoTemplate, &numberOfVisuals);
   2277 
   2278     Colormap colormap = XCreateColormap(
   2279                 demo->display, RootWindow(demo->display, vInfoTemplate.screen),
   2280                 visualInfo->visual, AllocNone);
   2281 
   2282     XSetWindowAttributes windowAttributes={};
   2283     windowAttributes.colormap = colormap;
   2284     windowAttributes.background_pixel = 0xFFFFFFFF;
   2285     windowAttributes.border_pixel = 0;
   2286     windowAttributes.event_mask =
   2287             KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
   2288 
   2289     demo->xlib_window = XCreateWindow(
   2290                 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 0, 0,
   2291                 demo->width, demo->height, 0, visualInfo->depth, InputOutput,
   2292                 visualInfo->visual,
   2293                 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes);
   2294 
   2295     XSelectInput(demo->display, demo->xlib_window, ExposureMask | KeyPressMask);
   2296     XMapWindow(demo->display, demo->xlib_window);
   2297     XFlush(demo->display);
   2298     demo->xlib_wm_delete_window =
   2299             XInternAtom(demo->display, "WM_DELETE_WINDOW", False);
   2300 }
   2301 static void demo_handle_xlib_event(struct demo *demo, const XEvent *event) {
   2302     switch(event->type) {
   2303     case ClientMessage:
   2304         if ((Atom)event->xclient.data.l[0] == demo->xlib_wm_delete_window)
   2305             demo->quit = true;
   2306         break;
   2307     case KeyPress:
   2308         switch (event->xkey.keycode) {
   2309         case 0x9: // Escape
   2310             demo->quit = true;
   2311             break;
   2312         case 0x71: // left arrow key
   2313             demo->spin_angle += demo->spin_increment;
   2314             break;
   2315         case 0x72: // right arrow key
   2316             demo->spin_angle -= demo->spin_increment;
   2317             break;
   2318         case 0x41:
   2319             demo->pause = !demo->pause;
   2320             break;
   2321         }
   2322         break;
   2323     case ConfigureNotify:
   2324         if ((demo->width != event->xconfigure.width) ||
   2325             (demo->height != event->xconfigure.height)) {
   2326             demo->width = event->xconfigure.width;
   2327             demo->height = event->xconfigure.height;
   2328             demo_resize(demo);
   2329         }
   2330         break;
   2331     default:
   2332         break;
   2333     }
   2334 
   2335 }
   2336 
   2337 static void demo_run_xlib(struct demo *demo) {
   2338 
   2339     while (!demo->quit) {
   2340         XEvent event;
   2341 
   2342         if (demo->pause) {
   2343             XNextEvent(demo->display, &event);
   2344             demo_handle_xlib_event(demo, &event);
   2345         } else {
   2346             while (XPending(demo->display) > 0) {
   2347                 XNextEvent(demo->display, &event);
   2348                 demo_handle_xlib_event(demo, &event);
   2349             }
   2350         }
   2351 
   2352         demo_update_data_buffer(demo);
   2353         demo_draw(demo);
   2354         demo->curFrame++;
   2355         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
   2356             demo->quit = true;
   2357     }
   2358 }
   2359 #endif // VK_USE_PLATFORM_XLIB_KHR
   2360 #ifdef VK_USE_PLATFORM_XCB_KHR
   2361 static void demo_handle_xcb_event(struct demo *demo,
   2362                               const xcb_generic_event_t *event) {
   2363     uint8_t event_code = event->response_type & 0x7f;
   2364     switch (event_code) {
   2365     case XCB_EXPOSE:
   2366         // TODO: Resize window
   2367         break;
   2368     case XCB_CLIENT_MESSAGE:
   2369         if ((*(xcb_client_message_event_t *)event).data.data32[0] ==
   2370             (*demo->atom_wm_delete_window).atom) {
   2371             demo->quit = true;
   2372         }
   2373         break;
   2374     case XCB_KEY_RELEASE: {
   2375         const xcb_key_release_event_t *key =
   2376             (const xcb_key_release_event_t *)event;
   2377 
   2378         switch (key->detail) {
   2379         case 0x9: // Escape
   2380             demo->quit = true;
   2381             break;
   2382         case 0x71: // left arrow key
   2383             demo->spin_angle += demo->spin_increment;
   2384             break;
   2385         case 0x72: // right arrow key
   2386             demo->spin_angle -= demo->spin_increment;
   2387             break;
   2388         case 0x41:
   2389             demo->pause = !demo->pause;
   2390             break;
   2391         }
   2392     } break;
   2393     case XCB_CONFIGURE_NOTIFY: {
   2394         const xcb_configure_notify_event_t *cfg =
   2395             (const xcb_configure_notify_event_t *)event;
   2396         if ((demo->width != cfg->width) || (demo->height != cfg->height)) {
   2397             demo->width = cfg->width;
   2398             demo->height = cfg->height;
   2399             demo_resize(demo);
   2400         }
   2401     } break;
   2402     default:
   2403         break;
   2404     }
   2405 }
   2406 
   2407 static void demo_run_xcb(struct demo *demo) {
   2408     xcb_flush(demo->connection);
   2409 
   2410     while (!demo->quit) {
   2411         xcb_generic_event_t *event;
   2412 
   2413         if (demo->pause) {
   2414             event = xcb_wait_for_event(demo->connection);
   2415         } else {
   2416             event = xcb_poll_for_event(demo->connection);
   2417             while(event) {
   2418                 demo_handle_xcb_event(demo, event);
   2419                 free(event);
   2420                 event = xcb_poll_for_event(demo->connection);
   2421             }
   2422         }
   2423 
   2424         demo_update_data_buffer(demo);
   2425         demo_draw(demo);
   2426         demo->curFrame++;
   2427         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
   2428             demo->quit = true;
   2429     }
   2430 }
   2431 
   2432 static void demo_create_xcb_window(struct demo *demo) {
   2433     uint32_t value_mask, value_list[32];
   2434 
   2435     demo->xcb_window = xcb_generate_id(demo->connection);
   2436 
   2437     value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
   2438     value_list[0] = demo->screen->black_pixel;
   2439     value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
   2440                     XCB_EVENT_MASK_STRUCTURE_NOTIFY;
   2441 
   2442     xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, demo->xcb_window,
   2443                       demo->screen->root, 0, 0, demo->width, demo->height, 0,
   2444                       XCB_WINDOW_CLASS_INPUT_OUTPUT, demo->screen->root_visual,
   2445                       value_mask, value_list);
   2446 
   2447     /* Magic code that will send notification when window is destroyed */
   2448     xcb_intern_atom_cookie_t cookie =
   2449         xcb_intern_atom(demo->connection, 1, 12, "WM_PROTOCOLS");
   2450     xcb_intern_atom_reply_t *reply =
   2451         xcb_intern_atom_reply(demo->connection, cookie, 0);
   2452 
   2453     xcb_intern_atom_cookie_t cookie2 =
   2454         xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
   2455     demo->atom_wm_delete_window =
   2456         xcb_intern_atom_reply(demo->connection, cookie2, 0);
   2457 
   2458     xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, demo->xcb_window,
   2459                         (*reply).atom, 4, 32, 1,
   2460                         &(*demo->atom_wm_delete_window).atom);
   2461     free(reply);
   2462 
   2463     xcb_map_window(demo->connection, demo->xcb_window);
   2464 
   2465     // Force the x/y coordinates to 100,100 results are identical in consecutive
   2466     // runs
   2467     const uint32_t coords[] = {100, 100};
   2468     xcb_configure_window(demo->connection, demo->xcb_window,
   2469                          XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
   2470 }
   2471 // VK_USE_PLATFORM_XCB_KHR
   2472 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   2473 static void demo_run(struct demo *demo) {
   2474     while (!demo->quit) {
   2475         demo_update_data_buffer(demo);
   2476         demo_draw(demo);
   2477         demo->curFrame++;
   2478         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
   2479             demo->quit = true;
   2480     }
   2481 }
   2482 
   2483 static void handle_ping(void *data UNUSED,
   2484                         struct wl_shell_surface *shell_surface,
   2485                         uint32_t serial) {
   2486     wl_shell_surface_pong(shell_surface, serial);
   2487 }
   2488 
   2489 static void handle_configure(void *data UNUSED,
   2490                              struct wl_shell_surface *shell_surface UNUSED,
   2491                              uint32_t edges UNUSED, int32_t width UNUSED,
   2492                              int32_t height UNUSED) {}
   2493 
   2494 static void handle_popup_done(void *data UNUSED,
   2495                               struct wl_shell_surface *shell_surface UNUSED) {}
   2496 
   2497 static const struct wl_shell_surface_listener shell_surface_listener = {
   2498     handle_ping, handle_configure, handle_popup_done};
   2499 
   2500 static void demo_create_window(struct demo *demo) {
   2501     demo->window = wl_compositor_create_surface(demo->compositor);
   2502     if (!demo->window) {
   2503         printf("Can not create wayland_surface from compositor!\n");
   2504         fflush(stdout);
   2505         exit(1);
   2506     }
   2507 
   2508     demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window);
   2509     if (!demo->shell_surface) {
   2510         printf("Can not get shell_surface from wayland_surface!\n");
   2511         fflush(stdout);
   2512         exit(1);
   2513     }
   2514     wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener,
   2515                                   demo);
   2516     wl_shell_surface_set_toplevel(demo->shell_surface);
   2517     wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
   2518 }
   2519 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
   2520 static void demo_run(struct demo *demo) {
   2521     if (!demo->prepared)
   2522         return;
   2523 
   2524     demo_update_data_buffer(demo);
   2525     demo_draw(demo);
   2526     demo->curFrame++;
   2527 }
   2528 #endif
   2529 
   2530 /*
   2531  * Return 1 (true) if all layer names specified in check_names
   2532  * can be found in given layer properties.
   2533  */
   2534 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
   2535                                   uint32_t layer_count,
   2536                                   VkLayerProperties *layers) {
   2537     for (uint32_t i = 0; i < check_count; i++) {
   2538         VkBool32 found = 0;
   2539         for (uint32_t j = 0; j < layer_count; j++) {
   2540             if (!strcmp(check_names[i], layers[j].layerName)) {
   2541                 found = 1;
   2542                 break;
   2543             }
   2544         }
   2545         if (!found) {
   2546             fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
   2547             return 0;
   2548         }
   2549     }
   2550     return 1;
   2551 }
   2552 
   2553 static void demo_init_vk(struct demo *demo) {
   2554     VkResult err;
   2555     uint32_t instance_extension_count = 0;
   2556     uint32_t instance_layer_count = 0;
   2557     uint32_t validation_layer_count = 0;
   2558     char **instance_validation_layers = NULL;
   2559     demo->enabled_extension_count = 0;
   2560     demo->enabled_layer_count = 0;
   2561 
   2562     char *instance_validation_layers_alt1[] = {
   2563         "VK_LAYER_LUNARG_standard_validation"
   2564     };
   2565 
   2566     char *instance_validation_layers_alt2[] = {
   2567         "VK_LAYER_GOOGLE_threading",       "VK_LAYER_LUNARG_parameter_validation",
   2568         "VK_LAYER_LUNARG_object_tracker",  "VK_LAYER_LUNARG_image",
   2569         "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain",
   2570         "VK_LAYER_GOOGLE_unique_objects"
   2571     };
   2572 
   2573     /* Look for validation layers */
   2574     VkBool32 validation_found = 0;
   2575     if (demo->validate) {
   2576 
   2577         err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
   2578         assert(!err);
   2579 
   2580         instance_validation_layers = instance_validation_layers_alt1;
   2581         if (instance_layer_count > 0) {
   2582             VkLayerProperties *instance_layers =
   2583                     malloc(sizeof (VkLayerProperties) * instance_layer_count);
   2584             err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
   2585                     instance_layers);
   2586             assert(!err);
   2587 
   2588 
   2589             validation_found = demo_check_layers(
   2590                     ARRAY_SIZE(instance_validation_layers_alt1),
   2591                     instance_validation_layers, instance_layer_count,
   2592                     instance_layers);
   2593             if (validation_found) {
   2594                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
   2595                 demo->enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation";
   2596                 validation_layer_count = 1;
   2597             } else {
   2598                 // use alternative set of validation layers
   2599                 instance_validation_layers = instance_validation_layers_alt2;
   2600                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
   2601                 validation_found = demo_check_layers(
   2602                     ARRAY_SIZE(instance_validation_layers_alt2),
   2603                     instance_validation_layers, instance_layer_count,
   2604                     instance_layers);
   2605                 validation_layer_count =
   2606                     ARRAY_SIZE(instance_validation_layers_alt2);
   2607                 for (uint32_t i = 0; i < validation_layer_count; i++) {
   2608                     demo->enabled_layers[i] = instance_validation_layers[i];
   2609                 }
   2610             }
   2611             free(instance_layers);
   2612         }
   2613 
   2614         if (!validation_found) {
   2615             ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
   2616                     "required validation layer.\n\n"
   2617                     "Please look at the Getting Started guide for additional "
   2618                     "information.\n",
   2619                     "vkCreateInstance Failure");
   2620         }
   2621     }
   2622 
   2623     /* Look for instance extensions */
   2624     VkBool32 surfaceExtFound = 0;
   2625     VkBool32 platformSurfaceExtFound = 0;
   2626 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   2627     VkBool32 xlibSurfaceExtFound = 0;
   2628 #endif
   2629     memset(demo->extension_names, 0, sizeof(demo->extension_names));
   2630 
   2631     err = vkEnumerateInstanceExtensionProperties(
   2632         NULL, &instance_extension_count, NULL);
   2633     assert(!err);
   2634 
   2635     if (instance_extension_count > 0) {
   2636         VkExtensionProperties *instance_extensions =
   2637             malloc(sizeof(VkExtensionProperties) * instance_extension_count);
   2638         err = vkEnumerateInstanceExtensionProperties(
   2639             NULL, &instance_extension_count, instance_extensions);
   2640         assert(!err);
   2641         for (uint32_t i = 0; i < instance_extension_count; i++) {
   2642             if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
   2643                         instance_extensions[i].extensionName)) {
   2644                 surfaceExtFound = 1;
   2645                 demo->extension_names[demo->enabled_extension_count++] =
   2646                     VK_KHR_SURFACE_EXTENSION_NAME;
   2647             }
   2648 #if defined(VK_USE_PLATFORM_WIN32_KHR)
   2649             if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
   2650                         instance_extensions[i].extensionName)) {
   2651                 platformSurfaceExtFound = 1;
   2652                 demo->extension_names[demo->enabled_extension_count++] =
   2653                     VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
   2654             }
   2655 #endif
   2656 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   2657             if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
   2658                         instance_extensions[i].extensionName)) {
   2659                 platformSurfaceExtFound = 1;
   2660                 xlibSurfaceExtFound = 1;
   2661                 demo->extension_names[demo->enabled_extension_count++] =
   2662                     VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
   2663             }
   2664 #endif
   2665 #if defined(VK_USE_PLATFORM_XCB_KHR)
   2666             if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
   2667                         instance_extensions[i].extensionName)) {
   2668                 platformSurfaceExtFound = 1;
   2669                 demo->extension_names[demo->enabled_extension_count++] =
   2670                     VK_KHR_XCB_SURFACE_EXTENSION_NAME;
   2671             }
   2672 #endif
   2673 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
   2674             if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
   2675                         instance_extensions[i].extensionName)) {
   2676                 platformSurfaceExtFound = 1;
   2677                 demo->extension_names[demo->enabled_extension_count++] =
   2678                     VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
   2679             }
   2680 #endif
   2681 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
   2682             if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
   2683                         instance_extensions[i].extensionName)) {
   2684                 platformSurfaceExtFound = 1;
   2685                 demo->extension_names[demo->enabled_extension_count++] =
   2686                     VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
   2687             }
   2688 #endif
   2689             if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
   2690                         instance_extensions[i].extensionName)) {
   2691                 if (demo->validate) {
   2692                     demo->extension_names[demo->enabled_extension_count++] =
   2693                         VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
   2694                 }
   2695             }
   2696             assert(demo->enabled_extension_count < 64);
   2697         }
   2698 
   2699         free(instance_extensions);
   2700     }
   2701 
   2702     if (!surfaceExtFound) {
   2703         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2704                  "the " VK_KHR_SURFACE_EXTENSION_NAME
   2705                  " extension.\n\nDo you have a compatible "
   2706                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2707                  "look at the Getting Started guide for additional "
   2708                  "information.\n",
   2709                  "vkCreateInstance Failure");
   2710     }
   2711     if (!platformSurfaceExtFound) {
   2712 #if defined(VK_USE_PLATFORM_WIN32_KHR)
   2713         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2714                  "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
   2715                  " extension.\n\nDo you have a compatible "
   2716                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2717                  "look at the Getting Started guide for additional "
   2718                  "information.\n",
   2719                  "vkCreateInstance Failure");
   2720 #elif defined(VK_USE_PLATFORM_XCB_KHR)
   2721         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2722                  "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME
   2723                  " extension.\n\nDo you have a compatible "
   2724                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2725                  "look at the Getting Started guide for additional "
   2726                  "information.\n",
   2727                  "vkCreateInstance Failure");
   2728 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   2729         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2730                  "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
   2731                  " extension.\n\nDo you have a compatible "
   2732                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2733                  "look at the Getting Started guide for additional "
   2734                  "information.\n",
   2735                  "vkCreateInstance Failure");
   2736 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
   2737         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2738                  "the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
   2739                  " extension.\n\nDo you have a compatible "
   2740                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2741                  "look at the Getting Started guide for additional "
   2742                  "information.\n",
   2743                  "vkCreateInstance Failure");
   2744 #endif
   2745     }
   2746 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   2747     if (demo->use_xlib && !xlibSurfaceExtFound) {
   2748         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
   2749                  "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME
   2750                  " extension.\n\nDo you have a compatible "
   2751                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2752                  "look at the Getting Started guide for additional "
   2753                  "information.\n",
   2754                  "vkCreateInstance Failure");
   2755     }
   2756 #endif
   2757     const VkApplicationInfo app = {
   2758         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
   2759         .pNext = NULL,
   2760         .pApplicationName = APP_SHORT_NAME,
   2761         .applicationVersion = 0,
   2762         .pEngineName = APP_SHORT_NAME,
   2763         .engineVersion = 0,
   2764         .apiVersion = VK_API_VERSION_1_0,
   2765     };
   2766     VkInstanceCreateInfo inst_info = {
   2767         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
   2768         .pNext = NULL,
   2769         .pApplicationInfo = &app,
   2770         .enabledLayerCount = demo->enabled_layer_count,
   2771         .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
   2772         .enabledExtensionCount = demo->enabled_extension_count,
   2773         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
   2774     };
   2775 
   2776     /*
   2777      * This is info for a temp callback to use during CreateInstance.
   2778      * After the instance is created, we use the instance-based
   2779      * function to register the final callback.
   2780      */
   2781     VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
   2782     if (demo->validate) {
   2783         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
   2784         dbgCreateInfo.pNext = NULL;
   2785         dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
   2786         dbgCreateInfo.pUserData = demo;
   2787         dbgCreateInfo.flags =
   2788             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
   2789         inst_info.pNext = &dbgCreateInfo;
   2790     }
   2791 
   2792     uint32_t gpu_count;
   2793 
   2794     err = vkCreateInstance(&inst_info, NULL, &demo->inst);
   2795     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
   2796         ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
   2797                  "(ICD).\n\nPlease look at the Getting Started guide for "
   2798                  "additional information.\n",
   2799                  "vkCreateInstance Failure");
   2800     } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
   2801         ERR_EXIT("Cannot find a specified extension library"
   2802                  ".\nMake sure your layers path is set appropriately.\n",
   2803                  "vkCreateInstance Failure");
   2804     } else if (err) {
   2805         ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
   2806                  "installable client driver (ICD) installed?\nPlease look at "
   2807                  "the Getting Started guide for additional information.\n",
   2808                  "vkCreateInstance Failure");
   2809     }
   2810 
   2811     /* Make initial call to query gpu_count, then second call for gpu info*/
   2812     err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
   2813     assert(!err && gpu_count > 0);
   2814 
   2815     if (gpu_count > 0) {
   2816         VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
   2817         err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
   2818         assert(!err);
   2819         /* For cube demo we just grab the first physical device */
   2820         demo->gpu = physical_devices[0];
   2821         free(physical_devices);
   2822     } else {
   2823         ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
   2824                  "Do you have a compatible Vulkan installable client driver (ICD) "
   2825                  "installed?\nPlease look at the Getting Started guide for "
   2826                  "additional information.\n",
   2827                  "vkEnumeratePhysicalDevices Failure");
   2828     }
   2829 
   2830     /* Look for device extensions */
   2831     uint32_t device_extension_count = 0;
   2832     VkBool32 swapchainExtFound = 0;
   2833     demo->enabled_extension_count = 0;
   2834     memset(demo->extension_names, 0, sizeof(demo->extension_names));
   2835 
   2836     err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
   2837                                                &device_extension_count, NULL);
   2838     assert(!err);
   2839 
   2840     if (device_extension_count > 0) {
   2841         VkExtensionProperties *device_extensions =
   2842             malloc(sizeof(VkExtensionProperties) * device_extension_count);
   2843         err = vkEnumerateDeviceExtensionProperties(
   2844             demo->gpu, NULL, &device_extension_count, device_extensions);
   2845         assert(!err);
   2846 
   2847         for (uint32_t i = 0; i < device_extension_count; i++) {
   2848             if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
   2849                         device_extensions[i].extensionName)) {
   2850                 swapchainExtFound = 1;
   2851                 demo->extension_names[demo->enabled_extension_count++] =
   2852                     VK_KHR_SWAPCHAIN_EXTENSION_NAME;
   2853             }
   2854             assert(demo->enabled_extension_count < 64);
   2855         }
   2856 
   2857         free(device_extensions);
   2858     }
   2859 
   2860     if (!swapchainExtFound) {
   2861         ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
   2862                  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
   2863                  " extension.\n\nDo you have a compatible "
   2864                  "Vulkan installable client driver (ICD) installed?\nPlease "
   2865                  "look at the Getting Started guide for additional "
   2866                  "information.\n",
   2867                  "vkCreateInstance Failure");
   2868     }
   2869 
   2870     if (demo->validate) {
   2871         demo->CreateDebugReportCallback =
   2872             (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
   2873                 demo->inst, "vkCreateDebugReportCallbackEXT");
   2874         demo->DestroyDebugReportCallback =
   2875             (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
   2876                 demo->inst, "vkDestroyDebugReportCallbackEXT");
   2877         if (!demo->CreateDebugReportCallback) {
   2878             ERR_EXIT(
   2879                 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
   2880                 "vkGetProcAddr Failure");
   2881         }
   2882         if (!demo->DestroyDebugReportCallback) {
   2883             ERR_EXIT(
   2884                 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
   2885                 "vkGetProcAddr Failure");
   2886         }
   2887         demo->DebugReportMessage =
   2888             (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
   2889                 demo->inst, "vkDebugReportMessageEXT");
   2890         if (!demo->DebugReportMessage) {
   2891             ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
   2892                      "vkGetProcAddr Failure");
   2893         }
   2894 
   2895         VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
   2896         PFN_vkDebugReportCallbackEXT callback;
   2897         callback = demo->use_break ? BreakCallback : dbgFunc;
   2898         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
   2899         dbgCreateInfo.pNext = NULL;
   2900         dbgCreateInfo.pfnCallback = callback;
   2901         dbgCreateInfo.pUserData = demo;
   2902         dbgCreateInfo.flags =
   2903             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
   2904         err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
   2905                                               &demo->msg_callback);
   2906         switch (err) {
   2907         case VK_SUCCESS:
   2908             break;
   2909         case VK_ERROR_OUT_OF_HOST_MEMORY:
   2910             ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
   2911                      "CreateDebugReportCallback Failure");
   2912             break;
   2913         default:
   2914             ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
   2915                      "CreateDebugReportCallback Failure");
   2916             break;
   2917         }
   2918     }
   2919     vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
   2920 
   2921     /* Call with NULL data to get count */
   2922     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu,
   2923                                              &demo->queue_family_count, NULL);
   2924     assert(demo->queue_family_count >= 1);
   2925 
   2926     demo->queue_props = (VkQueueFamilyProperties *)malloc(
   2927         demo->queue_family_count * sizeof(VkQueueFamilyProperties));
   2928     vkGetPhysicalDeviceQueueFamilyProperties(
   2929         demo->gpu, &demo->queue_family_count, demo->queue_props);
   2930 
   2931     // Query fine-grained feature support for this device.
   2932     //  If app has specific feature requirements it should check supported
   2933     //  features based on this query
   2934     VkPhysicalDeviceFeatures physDevFeatures;
   2935     vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures);
   2936 
   2937     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
   2938     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
   2939     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
   2940     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
   2941     GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
   2942 }
   2943 
   2944 static void demo_create_device(struct demo *demo) {
   2945     VkResult U_ASSERT_ONLY err;
   2946     float queue_priorities[1] = {0.0};
   2947     VkDeviceQueueCreateInfo queues[2];
   2948     queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
   2949     queues[0].pNext = NULL;
   2950     queues[0].queueFamilyIndex = demo->graphics_queue_family_index;
   2951     queues[0].queueCount = 1;
   2952     queues[0].pQueuePriorities = queue_priorities;
   2953     queues[0].flags = 0;
   2954 
   2955     VkDeviceCreateInfo device = {
   2956         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
   2957         .pNext = NULL,
   2958         .queueCreateInfoCount = 1,
   2959         .pQueueCreateInfos = queues,
   2960         .enabledLayerCount = 0,
   2961         .ppEnabledLayerNames = NULL,
   2962         .enabledExtensionCount = demo->enabled_extension_count,
   2963         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
   2964         .pEnabledFeatures =
   2965             NULL, // If specific features are required, pass them in here
   2966     };
   2967     if (demo->separate_present_queue) {
   2968         queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
   2969         queues[1].pNext = NULL;
   2970         queues[1].queueFamilyIndex = demo->present_queue_family_index;
   2971         queues[1].queueCount = 1;
   2972         queues[1].pQueuePriorities = queue_priorities;
   2973         queues[1].flags = 0;
   2974         device.queueCreateInfoCount = 2;
   2975     }
   2976     err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
   2977     assert(!err);
   2978 }
   2979 
   2980 static void demo_init_vk_swapchain(struct demo *demo) {
   2981     VkResult U_ASSERT_ONLY err;
   2982     uint32_t i;
   2983 
   2984 // Create a WSI surface for the window:
   2985 #if defined(VK_USE_PLATFORM_WIN32_KHR)
   2986     VkWin32SurfaceCreateInfoKHR createInfo;
   2987     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
   2988     createInfo.pNext = NULL;
   2989     createInfo.flags = 0;
   2990     createInfo.hinstance = demo->connection;
   2991     createInfo.hwnd = demo->window;
   2992 
   2993     err =
   2994         vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
   2995 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
   2996     VkWaylandSurfaceCreateInfoKHR createInfo;
   2997     createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
   2998     createInfo.pNext = NULL;
   2999     createInfo.flags = 0;
   3000     createInfo.display = demo->display;
   3001     createInfo.surface = demo->window;
   3002 
   3003     err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL,
   3004                                     &demo->surface);
   3005 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
   3006     VkAndroidSurfaceCreateInfoKHR createInfo;
   3007     createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
   3008     createInfo.pNext = NULL;
   3009     createInfo.flags = 0;
   3010     createInfo.window = (ANativeWindow*)(demo->window);
   3011 
   3012     err = vkCreateAndroidSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
   3013 #endif
   3014     if (demo->use_xlib) {
   3015 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   3016         VkXlibSurfaceCreateInfoKHR createInfo;
   3017         createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
   3018         createInfo.pNext = NULL;
   3019         createInfo.flags = 0;
   3020         createInfo.dpy = demo->display;
   3021         createInfo.window = demo->xlib_window;
   3022 
   3023         err = vkCreateXlibSurfaceKHR(demo->inst, &createInfo, NULL,
   3024                                      &demo->surface);
   3025 #endif
   3026     }
   3027     else {
   3028 #if defined(VK_USE_PLATFORM_XCB_KHR)
   3029         VkXcbSurfaceCreateInfoKHR createInfo;
   3030         createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
   3031         createInfo.pNext = NULL;
   3032         createInfo.flags = 0;
   3033         createInfo.connection = demo->connection;
   3034         createInfo.window = demo->xcb_window;
   3035 
   3036         err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
   3037 #endif
   3038     }
   3039     assert(!err);
   3040 
   3041     // Iterate over each queue to learn whether it supports presenting:
   3042     VkBool32 *supportsPresent =
   3043         (VkBool32 *)malloc(demo->queue_family_count * sizeof(VkBool32));
   3044     for (i = 0; i < demo->queue_family_count; i++) {
   3045         demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
   3046                                                    &supportsPresent[i]);
   3047     }
   3048 
   3049     // Search for a graphics and a present queue in the array of queue
   3050     // families, try to find one that supports both
   3051     uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
   3052     uint32_t presentQueueFamilyIndex = UINT32_MAX;
   3053     for (i = 0; i < demo->queue_family_count; i++) {
   3054         if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
   3055             if (graphicsQueueFamilyIndex == UINT32_MAX) {
   3056                 graphicsQueueFamilyIndex = i;
   3057             }
   3058 
   3059             if (supportsPresent[i] == VK_TRUE) {
   3060                 graphicsQueueFamilyIndex = i;
   3061                 presentQueueFamilyIndex = i;
   3062                 break;
   3063             }
   3064         }
   3065     }
   3066 
   3067     if (presentQueueFamilyIndex == UINT32_MAX) {
   3068         // If didn't find a queue that supports both graphics and present, then
   3069         // find a separate present queue.
   3070         for (i = 0; i < demo->queue_family_count; ++i) {
   3071             if (supportsPresent[i] == VK_TRUE) {
   3072                 presentQueueFamilyIndex = i;
   3073                 break;
   3074             }
   3075         }
   3076     }
   3077 
   3078     // Generate error if could not find both a graphics and a present queue
   3079     if (graphicsQueueFamilyIndex == UINT32_MAX ||
   3080         presentQueueFamilyIndex == UINT32_MAX) {
   3081         ERR_EXIT("Could not find both graphics and present queues\n",
   3082                  "Swapchain Initialization Failure");
   3083     }
   3084 
   3085     demo->graphics_queue_family_index = graphicsQueueFamilyIndex;
   3086     demo->present_queue_family_index = presentQueueFamilyIndex;
   3087     demo->separate_present_queue =
   3088         (demo->graphics_queue_family_index != demo->present_queue_family_index);
   3089     free(supportsPresent);
   3090 
   3091     demo_create_device(demo);
   3092 
   3093     GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR);
   3094     GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR);
   3095     GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR);
   3096     GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR);
   3097     GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR);
   3098 
   3099     vkGetDeviceQueue(demo->device, demo->graphics_queue_family_index, 0,
   3100                      &demo->graphics_queue);
   3101 
   3102     if (!demo->separate_present_queue) {
   3103         demo->present_queue = demo->graphics_queue;
   3104     } else {
   3105         vkGetDeviceQueue(demo->device, demo->present_queue_family_index, 0,
   3106                          &demo->present_queue);
   3107     }
   3108 
   3109     // Get the list of VkFormat's that are supported:
   3110     uint32_t formatCount;
   3111     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
   3112                                                      &formatCount, NULL);
   3113     assert(!err);
   3114     VkSurfaceFormatKHR *surfFormats =
   3115         (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
   3116     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
   3117                                                      &formatCount, surfFormats);
   3118     assert(!err);
   3119     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
   3120     // the surface has no preferred format.  Otherwise, at least one
   3121     // supported format will be returned.
   3122     if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
   3123         demo->format = VK_FORMAT_B8G8R8A8_UNORM;
   3124     } else {
   3125         assert(formatCount >= 1);
   3126         demo->format = surfFormats[0].format;
   3127     }
   3128     demo->color_space = surfFormats[0].colorSpace;
   3129 
   3130     demo->quit = false;
   3131     demo->curFrame = 0;
   3132 
   3133     // Create semaphores to synchronize acquiring presentable buffers before
   3134     // rendering and waiting for drawing to be complete before presenting
   3135     VkSemaphoreCreateInfo semaphoreCreateInfo = {
   3136         .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
   3137         .pNext = NULL,
   3138         .flags = 0,
   3139     };
   3140 
   3141     // Create fences that we can use to throttle if we get too far
   3142     // ahead of the image presents
   3143     VkFenceCreateInfo fence_ci = {
   3144         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
   3145         .pNext = NULL,
   3146         .flags = VK_FENCE_CREATE_SIGNALED_BIT
   3147     };
   3148     for (uint32_t i = 0; i < FRAME_LAG; i++) {
   3149         vkCreateFence(demo->device, &fence_ci, NULL, &demo->fences[i]);
   3150         err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
   3151                                 &demo->image_acquired_semaphores[i]);
   3152         assert(!err);
   3153 
   3154         err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
   3155                                 &demo->draw_complete_semaphores[i]);
   3156         assert(!err);
   3157 
   3158         if (demo->separate_present_queue) {
   3159             err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
   3160                                     &demo->image_ownership_semaphores[i]);
   3161             assert(!err);
   3162         }
   3163     }
   3164     demo->frame_index = 0;
   3165 
   3166     // Get Memory information and properties
   3167     vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
   3168 }
   3169 
   3170 #if defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
   3171 static void registry_handle_global(void *data, struct wl_registry *registry,
   3172                                    uint32_t name, const char *interface,
   3173                                    uint32_t version UNUSED) {
   3174     struct demo *demo = data;
   3175     if (strcmp(interface, "wl_compositor") == 0) {
   3176         demo->compositor =
   3177             wl_registry_bind(registry, name, &wl_compositor_interface, 3);
   3178         /* Todo: When xdg_shell protocol has stablized, we should move wl_shell
   3179          * tp xdg_shell */
   3180     } else if (strcmp(interface, "wl_shell") == 0) {
   3181         demo->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
   3182     }
   3183 }
   3184 
   3185 static void registry_handle_global_remove(void *data UNUSED,
   3186                                           struct wl_registry *registry UNUSED,
   3187                                           uint32_t name UNUSED) {}
   3188 
   3189 static const struct wl_registry_listener registry_listener = {
   3190     registry_handle_global, registry_handle_global_remove};
   3191 #endif
   3192 
   3193 static void demo_init_connection(struct demo *demo) {
   3194 #if defined(VK_USE_PLATFORM_XCB_KHR)
   3195     const xcb_setup_t *setup;
   3196     xcb_screen_iterator_t iter;
   3197     int scr;
   3198 
   3199     demo->connection = xcb_connect(NULL, &scr);
   3200     if (xcb_connection_has_error(demo->connection) > 0) {
   3201         printf("Cannot find a compatible Vulkan installable client driver "
   3202                "(ICD).\nExiting ...\n");
   3203         fflush(stdout);
   3204         exit(1);
   3205     }
   3206 
   3207     setup = xcb_get_setup(demo->connection);
   3208     iter = xcb_setup_roots_iterator(setup);
   3209     while (scr-- > 0)
   3210         xcb_screen_next(&iter);
   3211 
   3212     demo->screen = iter.data;
   3213 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   3214     demo->display = wl_display_connect(NULL);
   3215 
   3216     if (demo->display == NULL) {
   3217         printf("Cannot find a compatible Vulkan installable client driver "
   3218                "(ICD).\nExiting ...\n");
   3219         fflush(stdout);
   3220         exit(1);
   3221     }
   3222 
   3223     demo->registry = wl_display_get_registry(demo->display);
   3224     wl_registry_add_listener(demo->registry, &registry_listener, demo);
   3225     wl_display_dispatch(demo->display);
   3226 #endif
   3227 }
   3228 
   3229 static void demo_init(struct demo *demo, int argc, char **argv) {
   3230     vec3 eye = {0.0f, 3.0f, 5.0f};
   3231     vec3 origin = {0, 0, 0};
   3232     vec3 up = {0.0f, 1.0f, 0.0};
   3233 
   3234     memset(demo, 0, sizeof(*demo));
   3235     demo->frameCount = INT32_MAX;
   3236 
   3237     for (int i = 1; i < argc; i++) {
   3238         if (strcmp(argv[i], "--use_staging") == 0) {
   3239             demo->use_staging_buffer = true;
   3240             continue;
   3241         }
   3242         if (strcmp(argv[i], "--break") == 0) {
   3243             demo->use_break = true;
   3244             continue;
   3245         }
   3246         if (strcmp(argv[i], "--validate") == 0) {
   3247             demo->validate = true;
   3248             continue;
   3249         }
   3250 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   3251         if (strcmp(argv[i], "--xlib") == 0) {
   3252             demo->use_xlib = true;
   3253             continue;
   3254         }
   3255 #endif
   3256         if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
   3257             i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
   3258             demo->frameCount >= 0) {
   3259             i++;
   3260             continue;
   3261         }
   3262         if (strcmp(argv[i], "--suppress_popups") == 0) {
   3263             demo->suppress_popups = true;
   3264             continue;
   3265         }
   3266 
   3267 #if defined(ANDROID)
   3268         ERR_EXIT("Usage: cube [--validate]\n", "Usage");
   3269 #else
   3270         fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] "
   3271 #if defined(VK_USE_PLATFORM_XLIB_KHR)
   3272                         "[--xlib] "
   3273 #endif
   3274                         "[--c <framecount>] [--suppress_popups]\n",
   3275                 APP_SHORT_NAME);
   3276         fflush(stderr);
   3277         exit(1);
   3278 #endif
   3279     }
   3280 
   3281     if (!demo->use_xlib)
   3282         demo_init_connection(demo);
   3283 
   3284     demo_init_vk(demo);
   3285 
   3286     demo->width = 500;
   3287     demo->height = 500;
   3288 
   3289     demo->spin_angle = 4.0f;
   3290     demo->spin_increment = 0.2f;
   3291     demo->pause = false;
   3292 
   3293     mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f),
   3294                        1.0f, 0.1f, 100.0f);
   3295     mat4x4_look_at(demo->view_matrix, eye, origin, up);
   3296     mat4x4_identity(demo->model_matrix);
   3297 
   3298     demo->projection_matrix[1][1]*=-1;  //Flip projection matrix from GL to Vulkan orientation.
   3299 }
   3300 
   3301 #if defined(VK_USE_PLATFORM_WIN32_KHR)
   3302 // Include header required for parsing the command line options.
   3303 #include <shellapi.h>
   3304 
   3305 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine,
   3306                    int nCmdShow) {
   3307     MSG msg;   // message
   3308     bool done; // flag saying when app is complete
   3309     int argc;
   3310     char **argv;
   3311 
   3312     // Use the CommandLine functions to get the command line arguments.
   3313     // Unfortunately, Microsoft outputs
   3314     // this information as wide characters for Unicode, and we simply want the
   3315     // Ascii version to be compatible
   3316     // with the non-Windows side.  So, we have to convert the information to
   3317     // Ascii character strings.
   3318     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
   3319     if (NULL == commandLineArgs) {
   3320         argc = 0;
   3321     }
   3322 
   3323     if (argc > 0) {
   3324         argv = (char **)malloc(sizeof(char *) * argc);
   3325         if (argv == NULL) {
   3326             argc = 0;
   3327         } else {
   3328             for (int iii = 0; iii < argc; iii++) {
   3329                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
   3330                 size_t numConverted = 0;
   3331 
   3332                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
   3333                 if (argv[iii] != NULL) {
   3334                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
   3335                                commandLineArgs[iii], wideCharLen + 1);
   3336                 }
   3337             }
   3338         }
   3339     } else {
   3340         argv = NULL;
   3341     }
   3342 
   3343     demo_init(&demo, argc, argv);
   3344 
   3345     // Free up the items we had to allocate for the command line arguments.
   3346     if (argc > 0 && argv != NULL) {
   3347         for (int iii = 0; iii < argc; iii++) {
   3348             if (argv[iii] != NULL) {
   3349                 free(argv[iii]);
   3350             }
   3351         }
   3352         free(argv);
   3353     }
   3354 
   3355     demo.connection = hInstance;
   3356     strncpy(demo.name, "cube", APP_NAME_STR_LEN);
   3357     demo_create_window(&demo);
   3358     demo_init_vk_swapchain(&demo);
   3359 
   3360     demo_prepare(&demo);
   3361 
   3362     done = false; // initialize loop condition variable
   3363 
   3364     // main message loop
   3365     while (!done) {
   3366         PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
   3367         if (msg.message == WM_QUIT) // check for a quit message
   3368         {
   3369             done = true; // if found, quit app
   3370         } else {
   3371             /* Translate and dispatch to event queue*/
   3372             TranslateMessage(&msg);
   3373             DispatchMessage(&msg);
   3374         }
   3375         RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
   3376     }
   3377 
   3378     demo_cleanup(&demo);
   3379 
   3380     return (int)msg.wParam;
   3381 }
   3382 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
   3383 #include <android/log.h>
   3384 #include <android_native_app_glue.h>
   3385 #include "android_util.h"
   3386 
   3387 static bool initialized = false;
   3388 static bool active = false;
   3389 struct demo demo;
   3390 
   3391 static int32_t processInput(struct android_app* app, AInputEvent* event) {
   3392     return 0;
   3393 }
   3394 
   3395 static void processCommand(struct android_app* app, int32_t cmd) {
   3396     switch(cmd) {
   3397         case APP_CMD_INIT_WINDOW: {
   3398             if (app->window) {
   3399                 // We're getting a new window.  If the app is starting up, we
   3400                 // need to initialize.  If the app has already been
   3401                 // initialized, that means that we lost our previous window,
   3402                 // which means that we have a lot of work to do.  At a minimum,
   3403                 // we need to destroy the swapchain and surface associated with
   3404                 // the old window, and create a new surface and swapchain.
   3405                 // However, since there are a lot of other objects/state that
   3406                 // is tied to the swapchain, it's easiest to simply cleanup and
   3407                 // start over (i.e. use a brute-force approach of re-starting
   3408                 // the app)
   3409                 if (demo.prepared) {
   3410                     demo_cleanup(&demo);
   3411                 }
   3412 
   3413                 // Parse Intents into argc, argv
   3414                 // Use the following key to send arguments, i.e.
   3415                 // --es args "--validate"
   3416                 const char key[] = "args";
   3417                 char* appTag = (char*) APP_SHORT_NAME;
   3418                 int argc = 0;
   3419                 char** argv = get_args(app, key, appTag, &argc);
   3420 
   3421                 __android_log_print(ANDROID_LOG_INFO, appTag, "argc = %i", argc);
   3422                 for (int i = 0; i < argc; i++)
   3423                     __android_log_print(ANDROID_LOG_INFO, appTag, "argv[%i] = %s", i, argv[i]);
   3424 
   3425                 demo_init(&demo, argc, argv);
   3426 
   3427                 // Free the argv malloc'd by get_args
   3428                 for (int i = 0; i < argc; i++)
   3429                     free(argv[i]);
   3430 
   3431                 demo.window = (void*)app->window;
   3432                 demo_init_vk_swapchain(&demo);
   3433                 demo_prepare(&demo);
   3434                 initialized = true;
   3435             }
   3436             break;
   3437         }
   3438         case APP_CMD_GAINED_FOCUS: {
   3439             active = true;
   3440             break;
   3441         }
   3442         case APP_CMD_LOST_FOCUS: {
   3443             active = false;
   3444             break;
   3445         }
   3446     }
   3447 }
   3448 
   3449 void android_main(struct android_app *app)
   3450 {
   3451     app_dummy();
   3452 
   3453 #ifdef ANDROID
   3454     int vulkanSupport = InitVulkan();
   3455     if (vulkanSupport == 0)
   3456         return;
   3457 #endif
   3458 
   3459     demo.prepared = false;
   3460 
   3461     app->onAppCmd = processCommand;
   3462     app->onInputEvent = processInput;
   3463 
   3464     while(1) {
   3465         int events;
   3466         struct android_poll_source* source;
   3467         while (ALooper_pollAll(active ? 0 : -1, NULL, &events, (void**)&source) >= 0) {
   3468             if (source) {
   3469                 source->process(app, source);
   3470             }
   3471 
   3472             if (app->destroyRequested != 0) {
   3473                 demo_cleanup(&demo);
   3474                 return;
   3475             }
   3476         }
   3477         if (initialized && active) {
   3478             demo_run(&demo);
   3479         }
   3480     }
   3481 
   3482 }
   3483 #else
   3484 int main(int argc, char **argv) {
   3485     struct demo demo;
   3486 
   3487     demo_init(&demo, argc, argv);
   3488 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
   3489     if (demo.use_xlib)
   3490         demo_create_xlib_window(&demo);
   3491     else
   3492         demo_create_xcb_window(&demo);
   3493 #elif defined(VK_USE_PLATFORM_XCB_KHR)
   3494     demo_create_xcb_window(&demo);
   3495 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
   3496     demo_create_xlib_window(&demo);
   3497 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   3498     demo_create_window(&demo);
   3499 #endif
   3500 
   3501     demo_init_vk_swapchain(&demo);
   3502 
   3503     demo_prepare(&demo);
   3504 
   3505 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
   3506     if (demo.use_xlib)
   3507         demo_run_xlib(&demo);
   3508     else
   3509         demo_run_xcb(&demo);
   3510 #elif defined(VK_USE_PLATFORM_XCB_KHR)
   3511     demo_run_xcb(&demo);
   3512 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
   3513     demo_run_xlib(&demo);
   3514 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
   3515     demo_run(&demo);
   3516 #endif
   3517 
   3518     demo_cleanup(&demo);
   3519 
   3520     return validation_error;
   3521 }
   3522 #endif
   3523