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