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