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