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