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