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