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