cube.c revision 95b8bb3810e626be6e997a4a40e5f6cfc24ca7b0
1/*
2 * Vulkan
3 *
4 * Copyright (C) 2014-2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
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
31#ifdef _WIN32
32#pragma comment(linker, "/subsystem:windows")
33#include <windows.h>
34#define APP_NAME_STR_LEN 80
35#else  // _WIN32
36#include <xcb/xcb.h>
37#endif // _WIN32
38
39#include <vulkan.h>
40#include <vk_ext_khr_swapchain.h>
41#include <vk_ext_khr_device_swapchain.h>
42#include "vk_debug_report_lunarg.h"
43
44#include "icd-spv.h"
45
46#include "vk_sdk_platform.h"
47#include "linmath.h"
48#include <png.h>
49
50#define DEMO_BUFFER_COUNT 2
51#define DEMO_TEXTURE_COUNT 1
52#define APP_SHORT_NAME "cube"
53#define APP_LONG_NAME "The Vulkan Cube Demo Program"
54
55#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
56
57#if defined(NDEBUG) && defined(__GNUC__)
58#define U_ASSERT_ONLY __attribute__((unused))
59#else
60#define U_ASSERT_ONLY
61#endif
62
63#ifdef _WIN32
64#define ERR_EXIT(err_msg, err_class)                    \
65    do {                                                \
66        MessageBox(NULL, err_msg, err_class, MB_OK);    \
67        exit(1);                                        \
68   } while (0)
69
70#else  // _WIN32
71
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 // _WIN32
79
80#define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                        \
81{                                                                       \
82    demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
83    if (demo->fp##entrypoint == NULL) {                                 \
84        ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint,  \
85                 "vkGetInstanceProcAddr Failure");                      \
86    }                                                                   \
87}
88
89#define GET_DEVICE_PROC_ADDR(dev, entrypoint)                           \
90{                                                                       \
91    demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint);   \
92    if (demo->fp##entrypoint == NULL) {                                 \
93        ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint,    \
94                 "vkGetDeviceProcAddr Failure");                        \
95    }                                                                   \
96}
97
98/*
99 * structure to track all objects related to a texture.
100 */
101struct texture_object {
102    VkSampler sampler;
103
104    VkImage image;
105    VkImageLayout imageLayout;
106
107    VkDeviceMemory mem;
108    VkImageView view;
109    int32_t tex_width, tex_height;
110};
111
112static char *tex_files[] = {
113    "lunarg-logo-256x256-solid.png"
114};
115
116struct vkcube_vs_uniform {
117    // Must start with MVP
118    float       mvp[4][4];
119    float       position[12*3][4];
120    float       color[12*3][4];
121};
122
123struct vktexcube_vs_uniform {
124    // Must start with MVP
125    float       mvp[4][4];
126    float       position[12*3][4];
127    float       attr[12*3][4];
128};
129
130//--------------------------------------------------------------------------------------
131// Mesh and VertexFormat Data
132//--------------------------------------------------------------------------------------
133struct Vertex
134{
135    float     posX, posY, posZ, posW;    // Position data
136    float     r, g, b, a;                // Color
137};
138
139struct VertexPosTex
140{
141    float     posX, posY, posZ, posW;    // Position data
142    float     u, v, s, t;                // Texcoord
143};
144
145#define XYZ1(_x_, _y_, _z_)         (_x_), (_y_), (_z_), 1.f
146#define UV(_u_, _v_)                (_u_), (_v_), 0.f, 1.f
147
148static const float g_vertex_buffer_data[] = {
149    -1.0f,-1.0f,-1.0f,  // -X side
150    -1.0f,-1.0f, 1.0f,
151    -1.0f, 1.0f, 1.0f,
152    -1.0f, 1.0f, 1.0f,
153    -1.0f, 1.0f,-1.0f,
154    -1.0f,-1.0f,-1.0f,
155
156    -1.0f,-1.0f,-1.0f,  // -Z side
157     1.0f, 1.0f,-1.0f,
158     1.0f,-1.0f,-1.0f,
159    -1.0f,-1.0f,-1.0f,
160    -1.0f, 1.0f,-1.0f,
161     1.0f, 1.0f,-1.0f,
162
163    -1.0f,-1.0f,-1.0f,  // -Y side
164     1.0f,-1.0f,-1.0f,
165     1.0f,-1.0f, 1.0f,
166    -1.0f,-1.0f,-1.0f,
167     1.0f,-1.0f, 1.0f,
168    -1.0f,-1.0f, 1.0f,
169
170    -1.0f, 1.0f,-1.0f,  // +Y side
171    -1.0f, 1.0f, 1.0f,
172     1.0f, 1.0f, 1.0f,
173    -1.0f, 1.0f,-1.0f,
174     1.0f, 1.0f, 1.0f,
175     1.0f, 1.0f,-1.0f,
176
177     1.0f, 1.0f,-1.0f,  // +X side
178     1.0f, 1.0f, 1.0f,
179     1.0f,-1.0f, 1.0f,
180     1.0f,-1.0f, 1.0f,
181     1.0f,-1.0f,-1.0f,
182     1.0f, 1.0f,-1.0f,
183
184    -1.0f, 1.0f, 1.0f,  // +Z side
185    -1.0f,-1.0f, 1.0f,
186     1.0f, 1.0f, 1.0f,
187    -1.0f,-1.0f, 1.0f,
188     1.0f,-1.0f, 1.0f,
189     1.0f, 1.0f, 1.0f,
190};
191
192static const float g_uv_buffer_data[] = {
193    0.0f, 0.0f,  // -X side
194    1.0f, 0.0f,
195    1.0f, 1.0f,
196    1.0f, 1.0f,
197    0.0f, 1.0f,
198    0.0f, 0.0f,
199
200    1.0f, 0.0f,  // -Z side
201    0.0f, 1.0f,
202    0.0f, 0.0f,
203    1.0f, 0.0f,
204    1.0f, 1.0f,
205    0.0f, 1.0f,
206
207    1.0f, 1.0f,  // -Y side
208    1.0f, 0.0f,
209    0.0f, 0.0f,
210    1.0f, 1.0f,
211    0.0f, 0.0f,
212    0.0f, 1.0f,
213
214    1.0f, 1.0f,  // +Y side
215    0.0f, 1.0f,
216    0.0f, 0.0f,
217    1.0f, 1.0f,
218    0.0f, 0.0f,
219    1.0f, 0.0f,
220
221    1.0f, 1.0f,  // +X side
222    0.0f, 1.0f,
223    0.0f, 0.0f,
224    0.0f, 0.0f,
225    1.0f, 0.0f,
226    1.0f, 1.0f,
227
228    0.0f, 1.0f,  // +Z side
229    0.0f, 0.0f,
230    1.0f, 1.0f,
231    0.0f, 0.0f,
232    1.0f, 0.0f,
233    1.0f, 1.0f,
234};
235
236void dumpMatrix(const char *note, mat4x4 MVP)
237{
238    int i;
239
240    printf("%s: \n", note);
241    for (i=0; i<4; i++) {
242        printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]);
243    }
244    printf("\n");
245    fflush(stdout);
246}
247
248void dumpVec4(const char *note, vec4 vector)
249{
250    printf("%s: \n", note);
251        printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
252    printf("\n");
253    fflush(stdout);
254}
255
256VkBool32 dbgFunc(
257    VkFlags                             msgFlags,
258    VkDbgObjectType                     objType,
259    uint64_t                            srcObject,
260    size_t                              location,
261    int32_t                             msgCode,
262    const char*                         pLayerPrefix,
263    const char*                         pMsg,
264    void*                               pUserData)
265{
266    char *message = (char *) malloc(strlen(pMsg)+100);
267
268    assert (message);
269
270    if (msgFlags & VK_DBG_REPORT_ERROR_BIT) {
271        sprintf(message,"ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
272    } else if (msgFlags & VK_DBG_REPORT_WARN_BIT) {
273        // We know that we're submitting queues without fences, ignore this warning
274        if (strstr(pMsg, "vkQueueSubmit parameter, VkFence fence, is null pointer")){
275            return false;
276        }
277        sprintf(message,"WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
278    } else {
279        return false;
280    }
281
282#ifdef _WIN32
283    MessageBox(NULL, message, "Alert", MB_OK);
284#else
285    printf("%s\n",message);
286    fflush(stdout);
287#endif
288    free(message);
289
290    /*
291     * false indicates that layer should not bail-out of an
292     * API call that had validation failures. This may mean that the
293     * app dies inside the driver due to invalid parameter(s).
294     * That's what would happen without validation layers, so we'll
295     * keep that behavior here.
296     */
297    return false;
298}
299
300typedef struct _SwapchainBuffers {
301    VkImage image;
302    VkCmdBuffer cmd;
303    VkImageView view;
304} SwapchainBuffers;
305
306struct demo {
307#ifdef _WIN32
308#define APP_NAME_STR_LEN 80
309    HINSTANCE connection;        // hInstance - Windows Instance
310    char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
311    HWND        window;          // hWnd - window handle
312#else  // _WIN32
313    xcb_connection_t *connection;
314    xcb_screen_t *screen;
315    xcb_window_t window;
316    xcb_intern_atom_reply_t *atom_wm_delete_window;
317    VkPlatformHandleXcbKHR platform_handle_xcb;
318#endif // _WIN32
319    bool prepared;
320    bool use_staging_buffer;
321    bool use_glsl;
322
323    VkInstance inst;
324    VkPhysicalDevice gpu;
325    VkDevice device;
326    VkQueue queue;
327    uint32_t graphics_queue_node_index;
328    VkPhysicalDeviceProperties gpu_props;
329    VkQueueFamilyProperties *queue_props;
330    VkPhysicalDeviceMemoryProperties memory_properties;
331
332    VkFramebuffer framebuffer;
333    int width, height;
334    VkFormat format;
335    VkColorSpaceKHR color_space;
336
337    PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
338    PFN_vkGetSurfacePropertiesKHR fpGetSurfacePropertiesKHR;
339    PFN_vkGetSurfaceFormatsKHR fpGetSurfaceFormatsKHR;
340    PFN_vkGetSurfacePresentModesKHR fpGetSurfacePresentModesKHR;
341    PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
342    PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
343    PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
344    PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
345    PFN_vkQueuePresentKHR fpQueuePresentKHR;
346    VkSurfaceDescriptionWindowKHR surface_description;
347    uint32_t swapchainImageCount;
348    VkSwapchainKHR swap_chain;
349    SwapchainBuffers *buffers;
350
351    VkCmdPool cmd_pool;
352
353    struct {
354        VkFormat format;
355
356        VkImage image;
357        VkDeviceMemory mem;
358        VkImageView view;
359    } depth;
360
361    struct texture_object textures[DEMO_TEXTURE_COUNT];
362
363    struct {
364        VkBuffer buf;
365        VkDeviceMemory mem;
366        VkDescriptorInfo desc;
367    } uniform_data;
368
369    VkCmdBuffer cmd;  // Buffer for initialization commands
370    VkPipelineLayout pipeline_layout;
371    VkDescriptorSetLayout desc_layout;
372    VkPipelineCache pipelineCache;
373    VkRenderPass render_pass;
374    VkPipeline pipeline;
375
376    VkDynamicViewportState dynamic_viewport;
377    VkDynamicLineWidthState dynamic_line_width;
378    VkDynamicDepthBiasState dynamic_depth_bias;
379    VkDynamicBlendState dynamic_blend;
380    VkDynamicDepthBoundsState dynamic_depth_bounds;
381    VkDynamicStencilState dynamic_stencil;
382
383    mat4x4 projection_matrix;
384    mat4x4 view_matrix;
385    mat4x4 model_matrix;
386
387    float spin_angle;
388    float spin_increment;
389    bool pause;
390
391    VkShaderModule vert_shader_module;
392    VkShaderModule frag_shader_module;
393
394    VkDescriptorPool desc_pool;
395    VkDescriptorSet desc_set;
396
397    VkFramebuffer framebuffers[DEMO_BUFFER_COUNT];
398
399    bool quit;
400    int32_t curFrame;
401    int32_t frameCount;
402    bool validate;
403    bool use_break;
404    PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback;
405    PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback;
406    PFN_vkDbgMsgCallback dbgBreakCallback;
407    VkDbgMsgCallback msg_callback;
408
409    uint32_t current_buffer;
410    uint32_t queue_count;
411};
412
413static VkResult memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags properties, uint32_t *typeIndex)
414{
415     // Search memtypes to find first index with those properties
416     for (uint32_t i = 0; i < 32; i++) {
417         if ((typeBits & 1) == 1) {
418             // Type is available, does it match user properties?
419             if ((demo->memory_properties.memoryTypes[i].propertyFlags & properties) == properties) {
420                 *typeIndex = i;
421                 return VK_SUCCESS;
422             }
423         }
424         typeBits >>= 1;
425     }
426     // No memory types matched, return failure
427     return VK_UNSUPPORTED;
428}
429
430static void demo_flush_init_cmd(struct demo *demo)
431{
432    VkResult U_ASSERT_ONLY err;
433
434    if (demo->cmd == VK_NULL_HANDLE)
435        return;
436
437    err = vkEndCommandBuffer(demo->cmd);
438    assert(!err);
439
440    const VkCmdBuffer cmd_bufs[] = { demo->cmd };
441    VkFence nullFence = { VK_NULL_HANDLE };
442
443    err = vkQueueSubmit(demo->queue, 1, cmd_bufs, nullFence);
444    assert(!err);
445
446    err = vkQueueWaitIdle(demo->queue);
447    assert(!err);
448
449    vkDestroyCommandBuffer(demo->device, demo->cmd);
450    demo->cmd = VK_NULL_HANDLE;
451}
452
453static void demo_set_image_layout(
454        struct demo *demo,
455        VkImage image,
456        VkImageAspectFlags aspectMask,
457        VkImageLayout old_image_layout,
458        VkImageLayout new_image_layout)
459{
460    VkResult U_ASSERT_ONLY err;
461
462    if (demo->cmd == VK_NULL_HANDLE) {
463        const VkCmdBufferCreateInfo cmd = {
464            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
465            .pNext = NULL,
466            .cmdPool = demo->cmd_pool,
467            .level = VK_CMD_BUFFER_LEVEL_PRIMARY,
468            .flags = 0,
469        };
470
471        err = vkCreateCommandBuffer(demo->device, &cmd, &demo->cmd);
472        assert(!err);
473
474        VkCmdBufferBeginInfo cmd_buf_info = {
475            .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
476            .pNext = NULL,
477            .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT |
478                VK_CMD_BUFFER_OPTIMIZE_ONE_TIME_SUBMIT_BIT,
479            .renderPass = { VK_NULL_HANDLE },
480            .subpass = 0,
481            .framebuffer = { VK_NULL_HANDLE },
482        };
483        err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
484    }
485
486    VkImageMemoryBarrier image_memory_barrier = {
487        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
488        .pNext = NULL,
489        .outputMask = 0,
490        .inputMask = 0,
491        .oldLayout = old_image_layout,
492        .newLayout = new_image_layout,
493        .image = image,
494        .subresourceRange = { aspectMask, 0, 1, 0, 0 }
495    };
496
497    if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL) {
498        /* Make sure anything that was copying from this image has completed */
499        image_memory_barrier.inputMask = VK_MEMORY_INPUT_TRANSFER_BIT;
500    }
501
502    if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
503        /* Make sure any Copy or CPU writes to image are flushed */
504        image_memory_barrier.outputMask = VK_MEMORY_OUTPUT_HOST_WRITE_BIT | VK_MEMORY_OUTPUT_TRANSFER_BIT;
505    }
506
507    VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
508
509    VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
510    VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
511
512    vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, false, 1, (const void * const*)&pmemory_barrier);
513}
514
515static void demo_draw_build_cmd(struct demo *demo, VkCmdBuffer cmd_buf)
516{
517    const VkCmdBufferBeginInfo cmd_buf_info = {
518        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_BEGIN_INFO,
519        .pNext = NULL,
520        .flags = VK_CMD_BUFFER_OPTIMIZE_SMALL_BATCH_BIT,
521        .renderPass = { VK_NULL_HANDLE },
522        .subpass = 0,
523        .framebuffer = { VK_NULL_HANDLE },
524    };
525    const VkClearValue clear_values[2] = {
526        [0] = { .color.float32 = { 0.2f, 0.2f, 0.2f, 0.2f } },
527        [1] = { .depthStencil = { 1.0f, 0 } },
528    };
529    const VkRenderPassBeginInfo rp_begin = {
530        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
531        .pNext = NULL,
532        .renderPass = demo->render_pass,
533        .framebuffer = demo->framebuffers[demo->current_buffer],
534        .renderArea.offset.x = 0,
535        .renderArea.offset.y = 0,
536        .renderArea.extent.width = demo->width,
537        .renderArea.extent.height = demo->height,
538        .clearValueCount = 2,
539        .pClearValues = clear_values,
540    };
541    VkResult U_ASSERT_ONLY err;
542
543    err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
544    assert(!err);
545
546    vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_RENDER_PASS_CONTENTS_INLINE);
547
548    vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
549                                  demo->pipeline);
550    vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout,
551            0, 1, &demo->desc_set, 0, NULL);
552
553    vkCmdBindDynamicViewportState(cmd_buf, demo->dynamic_viewport);
554    vkCmdBindDynamicLineWidthState(cmd_buf,  demo->dynamic_line_width);
555    vkCmdBindDynamicDepthBiasState(cmd_buf,  demo->dynamic_depth_bias);
556    vkCmdBindDynamicBlendState(cmd_buf, demo->dynamic_blend);
557    vkCmdBindDynamicDepthBoundsState(cmd_buf, demo->dynamic_depth_bounds);
558    vkCmdBindDynamicStencilState(cmd_buf, demo->dynamic_stencil);
559
560    vkCmdDraw(cmd_buf, 0, 12 * 3, 0, 1);
561    vkCmdEndRenderPass(cmd_buf);
562
563    err = vkEndCommandBuffer(cmd_buf);
564    assert(!err);
565}
566
567
568void demo_update_data_buffer(struct demo *demo)
569{
570    mat4x4 MVP, Model, VP;
571    int matrixSize = sizeof(MVP);
572    uint8_t *pData;
573    VkResult U_ASSERT_ONLY err;
574
575    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
576
577    // Rotate 22.5 degrees around the Y axis
578    mat4x4_dup(Model, demo->model_matrix);
579    mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f, (float)degreesToRadians(demo->spin_angle));
580    mat4x4_mul(MVP, VP, demo->model_matrix);
581
582    err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 0, 0, (void **) &pData);
583    assert(!err);
584
585    memcpy(pData, (const void*) &MVP[0][0], matrixSize);
586
587    vkUnmapMemory(demo->device, demo->uniform_data.mem);
588}
589
590static void demo_draw(struct demo *demo)
591{
592    VkResult U_ASSERT_ONLY err;
593    VkSemaphore presentCompleteSemaphore;
594    VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
595        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
596        .pNext = NULL,
597        .flags = VK_FENCE_CREATE_SIGNALED_BIT,
598    };
599    VkFence nullFence = { VK_NULL_HANDLE };
600
601    err = vkCreateSemaphore(demo->device,
602                            &presentCompleteSemaphoreCreateInfo,
603                            &presentCompleteSemaphore);
604    assert(!err);
605
606    // Get the index of the next available swapchain image:
607    err = demo->fpAcquireNextImageKHR(demo->device, demo->swap_chain,
608                                      UINT64_MAX,
609                                      presentCompleteSemaphore,
610                                      &demo->current_buffer);
611    // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
612    // return codes
613    assert(!err);
614
615    // Wait for the present complete semaphore to be signaled to ensure
616    // that the image won't be rendered to until the presentation
617    // engine has fully released ownership to the application, and it is
618    // okay to render to the image.
619    vkQueueWaitSemaphore(demo->queue, presentCompleteSemaphore);
620
621// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SOURCE_KHR
622    err = vkQueueSubmit(demo->queue, 1, &demo->buffers[demo->current_buffer].cmd,
623            nullFence);
624    assert(!err);
625
626    VkPresentInfoKHR present = {
627        .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
628        .pNext = NULL,
629        .swapchainCount = 1,
630        .swapchains = &demo->swap_chain,
631        .imageIndices = &demo->current_buffer,
632    };
633
634// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
635    err = demo->fpQueuePresentKHR(demo->queue, &present);
636    // TODO: Deal with the VK_SUBOPTIMAL_KHR and VK_ERROR_OUT_OF_DATE_KHR
637    // return codes
638    assert(!err);
639
640    err = vkQueueWaitIdle(demo->queue);
641    assert(err == VK_SUCCESS);
642
643    vkDestroySemaphore(demo->device, presentCompleteSemaphore);
644}
645
646static void demo_prepare_buffers(struct demo *demo)
647{
648    VkResult U_ASSERT_ONLY err;
649
650    // Check the surface properties and formats
651    VkSurfacePropertiesKHR surfProperties;
652    err = demo->fpGetSurfacePropertiesKHR(demo->device,
653        (const VkSurfaceDescriptionKHR *)&demo->surface_description,
654        &surfProperties);
655    assert(!err);
656
657    uint32_t presentModeCount;
658    err = demo->fpGetSurfacePresentModesKHR(demo->device,
659        (const VkSurfaceDescriptionKHR *)&demo->surface_description,
660        &presentModeCount, NULL);
661    assert(!err);
662    VkPresentModeKHR *presentModes =
663        (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
664    assert(presentModes);
665    err = demo->fpGetSurfacePresentModesKHR(demo->device,
666        (const VkSurfaceDescriptionKHR *)&demo->surface_description,
667        &presentModeCount, presentModes);
668    assert(!err);
669
670    VkExtent2D swapchainExtent;
671    // width and height are either both -1, or both not -1.
672    if (surfProperties.currentExtent.width == -1)
673    {
674        // If the surface size is undefined, the size is set to
675        // the size of the images requested.
676        swapchainExtent.width = demo->width;
677        swapchainExtent.height = demo->height;
678    }
679    else
680    {
681        // If the surface size is defined, the swap chain size must match
682        swapchainExtent = surfProperties.currentExtent;
683    }
684
685    // If mailbox mode is available, use it, as is the lowest-latency non-
686    // tearing mode.  If not, try IMMEDIATE which will usually be available,
687    // and is fastest (though it tears).  If not, fall back to FIFO which is
688    // always available.
689    VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
690    for (size_t i = 0; i < presentModeCount; i++) {
691        if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
692            swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
693            break;
694        }
695        if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) &&
696            (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)) {
697            swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
698        }
699    }
700
701#define WORK_AROUND_CODE
702#ifdef WORK_AROUND_CODE
703    // After the proper code was created, other parts of this demo were
704    // modified to only support DEMO_BUFFER_COUNT number of command buffers,
705    // images, etc.  Live with that for now.
706    // TODO: Rework this demo code to live with the number of buffers returned
707    // by vkCreateSwapchainKHR().
708    uint32_t desiredNumberOfSwapchainImages = DEMO_BUFFER_COUNT;
709#else  // WORK_AROUND_CODE
710    // Determine the number of VkImage's to use in the swap chain (we desire to
711    // own only 1 image at a time, besides the images being displayed and
712    // queued for display):
713    uint32_t desiredNumberOfSwapchainImages = surfProperties.minImageCount + 1;
714    if ((surfProperties.maxImageCount > 0) &&
715        (desiredNumberOfSwapchainImages > surfProperties.maxImageCount))
716    {
717        // Application must settle for fewer images than desired:
718        desiredNumberOfSwapchainImages = surfProperties.maxImageCount;
719    }
720#endif // WORK_AROUND_CODE
721
722    VkSurfaceTransformFlagBitsKHR preTransform;
723    if (surfProperties.supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) {
724        preTransform = VK_SURFACE_TRANSFORM_NONE_KHR;
725    } else {
726        preTransform = surfProperties.currentTransform;
727    }
728
729    const VkSwapchainCreateInfoKHR swap_chain = {
730        .sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_KHR,
731        .pNext = NULL,
732        .pSurfaceDescription = (const VkSurfaceDescriptionKHR *)&demo->surface_description,
733        .minImageCount = desiredNumberOfSwapchainImages,
734        .imageFormat = demo->format,
735        .imageColorSpace = demo->color_space,
736        .imageExtent = {
737            .width = swapchainExtent.width,
738            .height = swapchainExtent.height,
739        },
740        .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
741        .preTransform = preTransform,
742        .imageArraySize = 1,
743        .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
744        .queueFamilyCount = 0,
745        .pQueueFamilyIndices = NULL,
746        .presentMode = swapchainPresentMode,
747        .oldSwapchain.handle = 0,
748        .clipped = true,
749    };
750    uint32_t i;
751
752    err = demo->fpCreateSwapchainKHR(demo->device, &swap_chain, &demo->swap_chain);
753    assert(!err);
754
755    err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain,
756                                        &demo->swapchainImageCount, NULL);
757    assert(!err);
758
759    VkImage* swapchainImages =
760        (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage));
761    assert(swapchainImages);
762    err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swap_chain,
763                                        &demo->swapchainImageCount,
764                                        swapchainImages);
765    assert(!err);
766#ifdef WORK_AROUND_CODE
767    // After the proper code was created, other parts of this demo were
768    // modified to only support DEMO_BUFFER_COUNT number of command buffers,
769    // images, etc.  Live with that for now.
770    // TODO: Rework this demo code to live with the number of buffers returned
771    // by vkCreateSwapchainKHR().
772    demo->swapchainImageCount = DEMO_BUFFER_COUNT;
773#endif // WORK_AROUND_CODE
774
775    demo->buffers = (SwapchainBuffers*)malloc(sizeof(SwapchainBuffers)*demo->swapchainImageCount);
776    assert(demo->buffers);
777
778    for (i = 0; i < demo->swapchainImageCount; i++) {
779        VkImageViewCreateInfo color_image_view = {
780            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
781            .pNext = NULL,
782            .format = demo->format,
783            .channels = {
784                .r = VK_CHANNEL_SWIZZLE_R,
785                .g = VK_CHANNEL_SWIZZLE_G,
786                .b = VK_CHANNEL_SWIZZLE_B,
787                .a = VK_CHANNEL_SWIZZLE_A,
788            },
789            .subresourceRange = {
790                .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
791                .baseMipLevel = 0,
792                .mipLevels = 1,
793                .baseArrayLayer = 0,
794                .arraySize = 1
795            },
796            .viewType = VK_IMAGE_VIEW_TYPE_2D,
797            .flags = 0,
798        };
799
800        demo->buffers[i].image = swapchainImages[i];
801
802        demo_set_image_layout(demo, demo->buffers[i].image,
803                               VK_IMAGE_ASPECT_COLOR,
804                               VK_IMAGE_LAYOUT_UNDEFINED,
805                               VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
806
807        color_image_view.image = demo->buffers[i].image;
808
809        err = vkCreateImageView(demo->device,
810                &color_image_view, &demo->buffers[i].view);
811        assert(!err);
812    }
813}
814
815static void demo_prepare_depth(struct demo *demo)
816{
817    const VkFormat depth_format = VK_FORMAT_D16_UNORM;
818    const VkImageCreateInfo image = {
819        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
820        .pNext = NULL,
821        .imageType = VK_IMAGE_TYPE_2D,
822        .format = depth_format,
823        .extent = { demo->width, demo->height, 1 },
824        .mipLevels = 1,
825        .arraySize = 1,
826        .samples = 1,
827        .tiling = VK_IMAGE_TILING_OPTIMAL,
828        .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
829        .flags = 0,
830    };
831    VkMemoryAllocInfo mem_alloc = {
832        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
833        .pNext = NULL,
834        .allocationSize = 0,
835        .memoryTypeIndex = 0,
836    };
837    VkImageViewCreateInfo view = {
838        .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
839        .pNext = NULL,
840        .image.handle = VK_NULL_HANDLE,
841        .format = depth_format,
842        .subresourceRange = {
843            .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
844            .baseMipLevel = 0,
845            .mipLevels = 1,
846            .baseArrayLayer = 0,
847            .arraySize = 1
848        },
849        .flags = 0,
850        .viewType = VK_IMAGE_VIEW_TYPE_2D,
851    };
852
853    VkMemoryRequirements mem_reqs;
854    VkResult U_ASSERT_ONLY err;
855
856    demo->depth.format = depth_format;
857
858    /* create image */
859    err = vkCreateImage(demo->device, &image,
860            &demo->depth.image);
861    assert(!err);
862
863    err = vkGetImageMemoryRequirements(demo->device,
864                    demo->depth.image, &mem_reqs);
865
866    mem_alloc.allocationSize = mem_reqs.size;
867    err = memory_type_from_properties(demo,
868                                      mem_reqs.memoryTypeBits,
869                                      VK_MEMORY_PROPERTY_DEVICE_ONLY,
870                                      &mem_alloc.memoryTypeIndex);
871    assert(!err);
872
873    /* allocate memory */
874    err = vkAllocMemory(demo->device, &mem_alloc, &demo->depth.mem);
875    assert(!err);
876
877    /* bind memory */
878    err = vkBindImageMemory(demo->device, demo->depth.image,
879            demo->depth.mem, 0);
880    assert(!err);
881
882    demo_set_image_layout(demo, demo->depth.image,
883                           VK_IMAGE_ASPECT_DEPTH_BIT,
884                           VK_IMAGE_LAYOUT_UNDEFINED,
885                           VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
886
887    /* create image view */
888    view.image = demo->depth.image;
889    err = vkCreateImageView(demo->device, &view, &demo->depth.view);
890    assert(!err);
891}
892
893/** loadTexture
894 *     loads a png file into an memory object, using cstdio , libpng.
895 *
896 *        \param demo : Needed to access VK calls
897 *     \param filename : the png file to be loaded
898 *     \param width : width of png, to be updated as a side effect of this function
899 *     \param height : height of png, to be updated as a side effect of this function
900 *
901 *     \return bool : an opengl texture id.  true if successful?,
902 *                     should be validated by the client of this function.
903 *
904 * Source: http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures
905 * Modified to copy image to memory
906 *
907 */
908bool loadTexture(const char *filename, uint8_t *rgba_data,
909                 VkSubresourceLayout *layout,
910                 int32_t *width, int32_t *height)
911{
912  //header for testing if it is a png
913  png_byte header[8];
914  int is_png, bit_depth, color_type, rowbytes;
915  size_t retval;
916  png_uint_32 i, twidth, theight;
917  png_structp  png_ptr;
918  png_infop info_ptr, end_info;
919  png_byte *image_data;
920  png_bytep *row_pointers;
921
922  //open file as binary
923  FILE *fp = fopen(filename, "rb");
924  if (!fp) {
925    return false;
926  }
927
928  //read the header
929  retval = fread(header, 1, 8, fp);
930  if (retval != 8) {
931      fclose(fp);
932      return false;
933  }
934
935  //test if png
936  is_png = !png_sig_cmp(header, 0, 8);
937  if (!is_png) {
938    fclose(fp);
939    return false;
940  }
941
942  //create png struct
943  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
944      NULL, NULL);
945  if (!png_ptr) {
946    fclose(fp);
947    return (false);
948  }
949
950  //create png info struct
951  info_ptr = png_create_info_struct(png_ptr);
952  if (!info_ptr) {
953    png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
954    fclose(fp);
955    return (false);
956  }
957
958  //create png info struct
959  end_info = png_create_info_struct(png_ptr);
960  if (!end_info) {
961    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
962    fclose(fp);
963    return (false);
964  }
965
966  //png error stuff, not sure libpng man suggests this.
967  if (setjmp(png_jmpbuf(png_ptr))) {
968    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
969    fclose(fp);
970    return (false);
971  }
972
973  //init png reading
974  png_init_io(png_ptr, fp);
975
976  //let libpng know you already read the first 8 bytes
977  png_set_sig_bytes(png_ptr, 8);
978
979  // read all the info up to the image data
980  png_read_info(png_ptr, info_ptr);
981
982  // get info about png
983  png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
984      NULL, NULL, NULL);
985
986  //update width and height based on png info
987  *width = twidth;
988  *height = theight;
989
990  // Require that incoming texture be 8bits per color component
991  // and 4 components (RGBA).
992  if (png_get_bit_depth(png_ptr, info_ptr) != 8 ||
993      png_get_channels(png_ptr, info_ptr) != 4) {
994      return false;
995  }
996
997  if (rgba_data == NULL) {
998      // If data pointer is null, we just want the width & height
999      // clean up memory and close stuff
1000      png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1001      fclose(fp);
1002
1003      return true;
1004  }
1005
1006  // Update the png info struct.
1007  png_read_update_info(png_ptr, info_ptr);
1008
1009  // Row size in bytes.
1010  rowbytes = png_get_rowbytes(png_ptr, info_ptr);
1011
1012  // Allocate the image_data as a big block, to be given to opengl
1013  image_data = (png_byte *)malloc(rowbytes * theight * sizeof(png_byte));
1014  if (!image_data) {
1015    //clean up memory and close stuff
1016    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1017    fclose(fp);
1018    return false;
1019  }
1020
1021  // row_pointers is for pointing to image_data for reading the png with libpng
1022  row_pointers = (png_bytep *)malloc(theight * sizeof(png_bytep));
1023  if (!row_pointers) {
1024    //clean up memory and close stuff
1025    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1026    // delete[] image_data;
1027    fclose(fp);
1028    return false;
1029  }
1030  // set the individual row_pointers to point at the correct offsets of image_data
1031  for (i = 0; i < theight; ++i)
1032    row_pointers[theight - 1 - i] = rgba_data + i * layout->rowPitch;
1033
1034  // read the png into image_data through row_pointers
1035  png_read_image(png_ptr, row_pointers);
1036
1037  // clean up memory and close stuff
1038  png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
1039  free(row_pointers);
1040  free(image_data);
1041  fclose(fp);
1042
1043  return true;
1044}
1045
1046static void demo_prepare_texture_image(struct demo *demo,
1047                                       const char *filename,
1048                                       struct texture_object *tex_obj,
1049                                       VkImageTiling tiling,
1050                                       VkImageUsageFlags usage,
1051                                       VkFlags mem_props)
1052{
1053    const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
1054    int32_t tex_width;
1055    int32_t tex_height;
1056    VkResult U_ASSERT_ONLY err;
1057
1058    if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height))
1059    {
1060        printf("Failed to load textures\n");
1061        fflush(stdout);
1062        exit(1);
1063    }
1064
1065    tex_obj->tex_width = tex_width;
1066    tex_obj->tex_height = tex_height;
1067
1068    const VkImageCreateInfo image_create_info = {
1069        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1070        .pNext = NULL,
1071        .imageType = VK_IMAGE_TYPE_2D,
1072        .format = tex_format,
1073        .extent = { tex_width, tex_height, 1 },
1074        .mipLevels = 1,
1075        .arraySize = 1,
1076        .samples = 1,
1077        .tiling = tiling,
1078        .usage = usage,
1079        .flags = 0,
1080    };
1081    VkMemoryAllocInfo mem_alloc = {
1082        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
1083        .pNext = NULL,
1084        .allocationSize = 0,
1085        .memoryTypeIndex = 0,
1086    };
1087
1088    VkMemoryRequirements mem_reqs;
1089
1090    err = vkCreateImage(demo->device, &image_create_info,
1091            &tex_obj->image);
1092    assert(!err);
1093
1094    err = vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
1095    assert(!err);
1096
1097    mem_alloc.allocationSize = mem_reqs.size;
1098
1099    err = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, mem_props, &mem_alloc.memoryTypeIndex);
1100    assert(!err);
1101
1102    /* allocate memory */
1103    err = vkAllocMemory(demo->device, &mem_alloc,
1104                &(tex_obj->mem));
1105    assert(!err);
1106
1107    /* bind memory */
1108    err = vkBindImageMemory(demo->device, tex_obj->image,
1109            tex_obj->mem, 0);
1110    assert(!err);
1111
1112    if (mem_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1113        const VkImageSubresource subres = {
1114            .aspect = VK_IMAGE_ASPECT_COLOR,
1115            .mipLevel = 0,
1116            .arrayLayer = 0,
1117        };
1118        VkSubresourceLayout layout;
1119        void *data;
1120
1121        err = vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, &layout);
1122        assert(!err);
1123
1124        err = vkMapMemory(demo->device, tex_obj->mem, 0, 0, 0, &data);
1125        assert(!err);
1126
1127        if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) {
1128            fprintf(stderr, "Error loading texture: %s\n", filename);
1129        }
1130
1131        vkUnmapMemory(demo->device, tex_obj->mem);
1132    }
1133
1134    tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1135    demo_set_image_layout(demo, tex_obj->image,
1136                           VK_IMAGE_ASPECT_COLOR,
1137                           VK_IMAGE_LAYOUT_UNDEFINED,
1138                           tex_obj->imageLayout);
1139    /* setting the image layout does not reference the actual memory so no need to add a mem ref */
1140}
1141
1142static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_objs)
1143{
1144    /* clean up staging resources */
1145    vkFreeMemory(demo->device, tex_objs->mem);
1146    vkDestroyImage(demo->device, tex_objs->image);
1147}
1148
1149static void demo_prepare_textures(struct demo *demo)
1150{
1151    const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
1152    VkFormatProperties props;
1153    VkResult U_ASSERT_ONLY err;
1154    uint32_t i;
1155
1156    err = vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
1157    assert(!err);
1158
1159    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1160
1161        if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) {
1162            /* Device can texture using linear textures */
1163            demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i],
1164                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1165        } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
1166            /* Must use staging buffer to copy linear texture to optimized */
1167            struct texture_object staging_texture;
1168
1169            memset(&staging_texture, 0, sizeof(staging_texture));
1170            demo_prepare_texture_image(demo, tex_files[i], &staging_texture,
1171                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1172
1173            demo_prepare_texture_image(demo, tex_files[i], &demo->textures[i],
1174                                       VK_IMAGE_TILING_OPTIMAL,
1175                                       (VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
1176                                       VK_MEMORY_PROPERTY_DEVICE_ONLY);
1177
1178            demo_set_image_layout(demo, staging_texture.image,
1179                                   VK_IMAGE_ASPECT_COLOR,
1180                                   staging_texture.imageLayout,
1181                                   VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL);
1182
1183            demo_set_image_layout(demo, demo->textures[i].image,
1184                                   VK_IMAGE_ASPECT_COLOR,
1185                                   demo->textures[i].imageLayout,
1186                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL);
1187
1188            VkImageCopy copy_region = {
1189                .srcSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
1190                .srcOffset = { 0, 0, 0 },
1191                .destSubresource = { VK_IMAGE_ASPECT_COLOR, 0, 0 },
1192                .destOffset = { 0, 0, 0 },
1193                .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 },
1194            };
1195            vkCmdCopyImage(demo->cmd,
1196                            staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SOURCE_OPTIMAL,
1197                            demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
1198                            1, &copy_region);
1199
1200            demo_set_image_layout(demo, demo->textures[i].image,
1201                                   VK_IMAGE_ASPECT_COLOR,
1202                                   VK_IMAGE_LAYOUT_TRANSFER_DESTINATION_OPTIMAL,
1203                                   demo->textures[i].imageLayout);
1204
1205            demo_flush_init_cmd(demo);
1206
1207            demo_destroy_texture_image(demo, &staging_texture);
1208        } else {
1209            /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */
1210            assert(!"No support for R8G8B8A8_UNORM as texture image format");
1211        }
1212
1213        const VkSamplerCreateInfo sampler = {
1214            .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1215            .pNext = NULL,
1216            .magFilter = VK_TEX_FILTER_NEAREST,
1217            .minFilter = VK_TEX_FILTER_NEAREST,
1218            .mipMode = VK_TEX_MIPMAP_MODE_BASE,
1219            .addressModeU = VK_TEX_ADDRESS_MODE_CLAMP,
1220            .addressModeV = VK_TEX_ADDRESS_MODE_CLAMP,
1221            .addressModeW = VK_TEX_ADDRESS_MODE_CLAMP,
1222            .mipLodBias = 0.0f,
1223            .maxAnisotropy = 1,
1224            .compareOp = VK_COMPARE_OP_NEVER,
1225            .minLod = 0.0f,
1226            .maxLod = 0.0f,
1227            .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1228            .unnormalizedCoordinates = VK_FALSE,
1229        };
1230
1231        VkImageViewCreateInfo view = {
1232            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1233            .pNext = NULL,
1234            .image.handle = VK_NULL_HANDLE,
1235            .viewType = VK_IMAGE_VIEW_TYPE_2D,
1236            .format = tex_format,
1237            .channels = { VK_CHANNEL_SWIZZLE_R,
1238                          VK_CHANNEL_SWIZZLE_G,
1239                          VK_CHANNEL_SWIZZLE_B,
1240                          VK_CHANNEL_SWIZZLE_A, },
1241            .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 },
1242            .flags = 0,
1243        };
1244
1245        /* create sampler */
1246        err = vkCreateSampler(demo->device, &sampler,
1247                &demo->textures[i].sampler);
1248        assert(!err);
1249
1250        /* create image view */
1251        view.image = demo->textures[i].image;
1252        err = vkCreateImageView(demo->device, &view,
1253                &demo->textures[i].view);
1254        assert(!err);
1255    }
1256}
1257
1258void demo_prepare_cube_data_buffer(struct demo *demo)
1259{
1260    VkBufferCreateInfo buf_info;
1261    VkMemoryAllocInfo alloc_info = {
1262        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOC_INFO,
1263        .pNext = NULL,
1264        .allocationSize = 0,
1265        .memoryTypeIndex = 0,
1266    };
1267    VkMemoryRequirements mem_reqs;
1268    uint8_t *pData;
1269    int i;
1270    mat4x4 MVP, VP;
1271    VkResult U_ASSERT_ONLY err;
1272    struct vktexcube_vs_uniform data;
1273
1274    mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
1275    mat4x4_mul(MVP, VP, demo->model_matrix);
1276    memcpy(data.mvp, MVP, sizeof(MVP));
1277//    dumpMatrix("MVP", MVP);
1278
1279    for (i=0; i<12*3; i++) {
1280        data.position[i][0] = g_vertex_buffer_data[i*3];
1281        data.position[i][1] = g_vertex_buffer_data[i*3+1];
1282        data.position[i][2] = g_vertex_buffer_data[i*3+2];
1283        data.position[i][3] = 1.0f;
1284        data.attr[i][0] = g_uv_buffer_data[2*i];
1285        data.attr[i][1] = g_uv_buffer_data[2*i + 1];
1286        data.attr[i][2] = 0;
1287        data.attr[i][3] = 0;
1288    }
1289
1290    memset(&buf_info, 0, sizeof(buf_info));
1291    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1292    buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
1293    buf_info.size = sizeof(data);
1294    err = vkCreateBuffer(demo->device, &buf_info, &demo->uniform_data.buf);
1295    assert(!err);
1296
1297    err = vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf, &mem_reqs);
1298    assert(!err);
1299
1300    alloc_info.allocationSize = mem_reqs.size;
1301    err = memory_type_from_properties(demo,
1302                                      mem_reqs.memoryTypeBits,
1303                                      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
1304                                      &alloc_info.memoryTypeIndex);
1305    assert(!err);
1306
1307    err = vkAllocMemory(demo->device, &alloc_info, &(demo->uniform_data.mem));
1308    assert(!err);
1309
1310    err = vkMapMemory(demo->device, demo->uniform_data.mem, 0, 0, 0, (void **) &pData);
1311    assert(!err);
1312
1313    memcpy(pData, &data, sizeof data);
1314
1315    vkUnmapMemory(demo->device, demo->uniform_data.mem);
1316
1317    err = vkBindBufferMemory(demo->device,
1318            demo->uniform_data.buf,
1319            demo->uniform_data.mem, 0);
1320    assert(!err);
1321
1322    demo->uniform_data.desc.bufferInfo.buffer = demo->uniform_data.buf;
1323    demo->uniform_data.desc.bufferInfo.offset = 0;
1324    demo->uniform_data.desc.bufferInfo.range = sizeof(data);
1325}
1326
1327static void demo_prepare_descriptor_layout(struct demo *demo)
1328{
1329    const VkDescriptorSetLayoutBinding layout_bindings[2] = {
1330        [0] = {
1331            .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1332            .arraySize = 1,
1333            .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
1334            .pImmutableSamplers = NULL,
1335        },
1336        [1] = {
1337            .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1338            .arraySize = DEMO_TEXTURE_COUNT,
1339            .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1340            .pImmutableSamplers = NULL,
1341        },
1342    };
1343    const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
1344        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1345        .pNext = NULL,
1346        .count = 2,
1347        .pBinding = layout_bindings,
1348    };
1349    VkResult U_ASSERT_ONLY err;
1350
1351    err = vkCreateDescriptorSetLayout(demo->device,
1352            &descriptor_layout, &demo->desc_layout);
1353    assert(!err);
1354
1355    const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
1356        .sType              = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1357        .pNext              = NULL,
1358        .descriptorSetCount = 1,
1359        .pSetLayouts        = &demo->desc_layout,
1360    };
1361
1362    err = vkCreatePipelineLayout(demo->device,
1363                                 &pPipelineLayoutCreateInfo,
1364                                 &demo->pipeline_layout);
1365    assert(!err);
1366}
1367
1368static void demo_prepare_render_pass(struct demo *demo)
1369{
1370    const VkAttachmentDescription attachments[2] = {
1371        [0] = {
1372            .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,
1373            .pNext = NULL,
1374            .format = demo->format,
1375            .samples = 1,
1376            .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1377            .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1378            .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1379            .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1380            .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1381            .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1382        },
1383        [1] = {
1384            .sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION,
1385            .pNext = NULL,
1386            .format = demo->depth.format,
1387            .samples = 1,
1388            .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1389            .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1390            .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1391            .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1392            .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1393            .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1394        },
1395    };
1396    const VkAttachmentReference color_reference = {
1397        .attachment = 0,
1398        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1399    };
1400    const VkSubpassDescription subpass = {
1401        .sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION,
1402        .pNext = NULL,
1403        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1404        .flags = 0,
1405        .inputCount = 0,
1406        .pInputAttachments = NULL,
1407        .colorCount = 1,
1408        .pColorAttachments = &color_reference,
1409        .pResolveAttachments = NULL,
1410        .depthStencilAttachment = {
1411            .attachment = 1,
1412            .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1413        },
1414        .preserveCount = 0,
1415        .pPreserveAttachments = NULL,
1416    };
1417    const VkRenderPassCreateInfo rp_info = {
1418        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1419        .pNext = NULL,
1420        .attachmentCount = 2,
1421        .pAttachments = attachments,
1422        .subpassCount = 1,
1423        .pSubpasses = &subpass,
1424        .dependencyCount = 0,
1425        .pDependencies = NULL,
1426    };
1427    VkResult U_ASSERT_ONLY err;
1428
1429    err = vkCreateRenderPass(demo->device, &rp_info, &demo->render_pass);
1430    assert(!err);
1431}
1432
1433static VkShader demo_prepare_shader(struct demo* demo,
1434                                      VkShaderStage stage,
1435                                      VkShaderModule* pShaderModule,
1436                                      const void* code,
1437                                      size_t size)
1438{
1439    VkShaderModuleCreateInfo moduleCreateInfo;
1440    VkShaderCreateInfo shaderCreateInfo;
1441    VkShader shader;
1442    VkResult err;
1443
1444
1445    moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1446    moduleCreateInfo.pNext = NULL;
1447
1448    shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO;
1449    shaderCreateInfo.pNext = NULL;
1450    shaderCreateInfo.pName = "main";
1451
1452    if (!demo->use_glsl) {
1453        moduleCreateInfo.codeSize = size;
1454        moduleCreateInfo.pCode = code;
1455        moduleCreateInfo.flags = 0;
1456        err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule);
1457        if (err) {
1458            free((void *) moduleCreateInfo.pCode);
1459        }
1460
1461        shaderCreateInfo.flags = 0;
1462        shaderCreateInfo.module = *pShaderModule;
1463        shaderCreateInfo.pName = "main";
1464        shaderCreateInfo.stage = stage;
1465        err = vkCreateShader(demo->device, &shaderCreateInfo, &shader);
1466    } else {
1467        // Create fake SPV structure to feed GLSL
1468        // to the driver "under the covers"
1469        moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
1470        moduleCreateInfo.pCode = malloc(moduleCreateInfo.codeSize);
1471        moduleCreateInfo.flags = 0;
1472
1473        /* try version 0 first: VkShaderStage followed by GLSL */
1474        ((uint32_t *) moduleCreateInfo.pCode)[0] = ICD_SPV_MAGIC;
1475        ((uint32_t *) moduleCreateInfo.pCode)[1] = 0;
1476        ((uint32_t *) moduleCreateInfo.pCode)[2] = stage;
1477        memcpy(((uint32_t *) moduleCreateInfo.pCode + 3), code, size + 1);
1478
1479        err = vkCreateShaderModule(demo->device, &moduleCreateInfo, pShaderModule);
1480        if (err) {
1481            free((void *) moduleCreateInfo.pCode);
1482        }
1483
1484        shaderCreateInfo.flags = 0;
1485        shaderCreateInfo.module = *pShaderModule;
1486        shaderCreateInfo.pName = "main";
1487        shaderCreateInfo.stage = stage;
1488        err = vkCreateShader(demo->device, &shaderCreateInfo, &shader);
1489    }
1490    return shader;
1491}
1492
1493char *demo_read_spv(const char *filename, size_t *psize)
1494{
1495    long int size;
1496    size_t U_ASSERT_ONLY retval;
1497    void *shader_code;
1498
1499    FILE *fp = fopen(filename, "rb");
1500    if (!fp) return NULL;
1501
1502    fseek(fp, 0L, SEEK_END);
1503    size = ftell(fp);
1504
1505    fseek(fp, 0L, SEEK_SET);
1506
1507    shader_code = malloc(size);
1508    retval = fread(shader_code, size, 1, fp);
1509    assert(retval == 1);
1510
1511    *psize = size;
1512
1513    return shader_code;
1514}
1515
1516static VkShader demo_prepare_vs(struct demo *demo)
1517{
1518    if (!demo->use_glsl) {
1519        void *vertShaderCode;
1520        size_t size;
1521
1522        vertShaderCode = demo_read_spv("cube-vert.spv", &size);
1523
1524        return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, &demo->vert_shader_module,
1525                                   vertShaderCode, size);
1526    } else {
1527        static const char *vertShaderText =
1528                "#version 140\n"
1529                "#extension GL_ARB_separate_shader_objects : enable\n"
1530                "#extension GL_ARB_shading_language_420pack : enable\n"
1531                "\n"
1532                "layout(binding = 0) uniform buf {\n"
1533                "        mat4 MVP;\n"
1534                "        vec4 position[12*3];\n"
1535                "        vec4 attr[12*3];\n"
1536                "} ubuf;\n"
1537                "\n"
1538                "layout (location = 0) out vec4 texcoord;\n"
1539                "\n"
1540                "void main() \n"
1541                "{\n"
1542                "   texcoord = ubuf.attr[gl_VertexID];\n"
1543                "   gl_Position = ubuf.MVP * ubuf.position[gl_VertexID];\n"
1544                "\n"
1545                "   // GL->VK conventions\n"
1546                "   gl_Position.y = -gl_Position.y;\n"
1547                "   gl_Position.z = (gl_Position.z + gl_Position.w) / 2.0;\n"
1548                "}\n";
1549
1550        return demo_prepare_shader(demo, VK_SHADER_STAGE_VERTEX, &demo->vert_shader_module,
1551                                   (const void *) vertShaderText,
1552                                   strlen(vertShaderText));
1553    }
1554}
1555
1556static VkShader demo_prepare_fs(struct demo *demo)
1557{
1558    if (!demo->use_glsl) {
1559        void *fragShaderCode;
1560        size_t size;
1561
1562        fragShaderCode = demo_read_spv("cube-frag.spv", &size);
1563
1564        return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, &demo->frag_shader_module,
1565                                   fragShaderCode, size);
1566    } else {
1567        static const char *fragShaderText =
1568                "#version 140\n"
1569                "#extension GL_ARB_separate_shader_objects : enable\n"
1570                "#extension GL_ARB_shading_language_420pack : enable\n"
1571                "layout (binding = 1) uniform sampler2D tex;\n"
1572                "\n"
1573                "layout (location = 0) in vec4 texcoord;\n"
1574                "layout (location = 0) out vec4 uFragColor;\n"
1575                "void main() {\n"
1576                "   uFragColor = texture(tex, texcoord.xy);\n"
1577                "}\n";
1578
1579        return demo_prepare_shader(demo, VK_SHADER_STAGE_FRAGMENT, &demo->frag_shader_module,
1580                                   (const void *) fragShaderText,
1581                                   strlen(fragShaderText));
1582    }
1583}
1584
1585static void demo_prepare_pipeline(struct demo *demo)
1586{
1587    VkGraphicsPipelineCreateInfo pipeline;
1588    VkPipelineCacheCreateInfo pipelineCache;
1589    VkPipelineInputAssemblyStateCreateInfo ia;
1590    VkPipelineRasterStateCreateInfo        rs;
1591    VkPipelineColorBlendStateCreateInfo    cb;
1592    VkPipelineDepthStencilStateCreateInfo  ds;
1593    VkPipelineViewportStateCreateInfo      vp;
1594    VkPipelineMultisampleStateCreateInfo   ms;
1595    VkResult U_ASSERT_ONLY err;
1596
1597    memset(&pipeline, 0, sizeof(pipeline));
1598    pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1599    pipeline.layout = demo->pipeline_layout;
1600
1601    memset(&ia, 0, sizeof(ia));
1602    ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1603    ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1604
1605    memset(&rs, 0, sizeof(rs));
1606    rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTER_STATE_CREATE_INFO;
1607    rs.fillMode = VK_FILL_MODE_SOLID;
1608    rs.cullMode = VK_CULL_MODE_BACK;
1609    rs.frontFace = VK_FRONT_FACE_CCW;
1610    rs.depthClipEnable = VK_TRUE;
1611    rs.rasterizerDiscardEnable = VK_FALSE;
1612    rs.depthBiasEnable = VK_FALSE;
1613
1614    memset(&cb, 0, sizeof(cb));
1615    cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1616    VkPipelineColorBlendAttachmentState att_state[1];
1617    memset(att_state, 0, sizeof(att_state));
1618    att_state[0].channelWriteMask = 0xf;
1619    att_state[0].blendEnable = VK_FALSE;
1620    cb.attachmentCount = 1;
1621    cb.pAttachments = att_state;
1622
1623    memset(&vp, 0, sizeof(vp));
1624    vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1625    vp.viewportCount = 1;
1626
1627    memset(&ds, 0, sizeof(ds));
1628    ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1629    ds.depthTestEnable = VK_TRUE;
1630    ds.depthWriteEnable = VK_TRUE;
1631    ds.depthCompareOp = VK_COMPARE_OP_LESS_EQUAL;
1632    ds.depthBoundsTestEnable = VK_FALSE;
1633    ds.back.stencilFailOp = VK_STENCIL_OP_KEEP;
1634    ds.back.stencilPassOp = VK_STENCIL_OP_KEEP;
1635    ds.back.stencilCompareOp = VK_COMPARE_OP_ALWAYS;
1636    ds.stencilTestEnable = VK_FALSE;
1637    ds.front = ds.back;
1638
1639    memset(&ms, 0, sizeof(ms));
1640    ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1641    ms.pSampleMask = NULL;
1642    ms.rasterSamples = 1;
1643
1644    // Two stages: vs and fs
1645    pipeline.stageCount = 2;
1646    VkPipelineShaderStageCreateInfo shaderStages[2];
1647    memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
1648
1649    shaderStages[0].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1650    shaderStages[0].stage  = VK_SHADER_STAGE_VERTEX;
1651    shaderStages[0].shader = demo_prepare_vs(demo);
1652
1653    shaderStages[1].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1654    shaderStages[1].stage  = VK_SHADER_STAGE_FRAGMENT;
1655    shaderStages[1].shader = demo_prepare_fs(demo);
1656
1657    memset(&pipelineCache, 0, sizeof(pipelineCache));
1658    pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
1659
1660    err = vkCreatePipelineCache(demo->device, &pipelineCache, &demo->pipelineCache);
1661    assert(!err);
1662
1663    pipeline.pVertexInputState   = NULL;
1664    pipeline.pInputAssemblyState = &ia;
1665    pipeline.pRasterState        = &rs;
1666    pipeline.pColorBlendState    = &cb;
1667    pipeline.pMultisampleState   = &ms;
1668    pipeline.pViewportState      = &vp;
1669    pipeline.pDepthStencilState  = &ds;
1670    pipeline.pStages             = shaderStages;
1671    pipeline.renderPass          = demo->render_pass;
1672
1673    pipeline.renderPass = demo->render_pass;
1674
1675    err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1, &pipeline, &demo->pipeline);
1676    assert(!err);
1677
1678    for (uint32_t i = 0; i < pipeline.stageCount; i++) {
1679        vkDestroyShader(demo->device, shaderStages[i].shader);
1680    }
1681    vkDestroyShaderModule(demo->device, demo->frag_shader_module);
1682    vkDestroyShaderModule(demo->device, demo->vert_shader_module);
1683}
1684
1685static void demo_prepare_dynamic_states(struct demo *demo)
1686{
1687    VkDynamicViewportStateCreateInfo viewport_create;
1688    VkDynamicLineWidthStateCreateInfo line_width;
1689    VkDynamicDepthBiasStateCreateInfo depth_bias;
1690    VkDynamicBlendStateCreateInfo blend;
1691    VkDynamicDepthBoundsStateCreateInfo depth_bounds;
1692    VkDynamicStencilStateCreateInfo stencil;
1693    VkResult U_ASSERT_ONLY err;
1694
1695    memset(&viewport_create, 0, sizeof(viewport_create));
1696    viewport_create.sType = VK_STRUCTURE_TYPE_DYNAMIC_VIEWPORT_STATE_CREATE_INFO;
1697    viewport_create.viewportAndScissorCount = 1;
1698    VkViewport viewport;
1699    memset(&viewport, 0, sizeof(viewport));
1700    viewport.height = (float) demo->height;
1701    viewport.width = (float) demo->width;
1702    viewport.minDepth = (float) 0.0f;
1703    viewport.maxDepth = (float) 1.0f;
1704    viewport_create.pViewports = &viewport;
1705    VkRect2D scissor;
1706    memset(&scissor, 0, sizeof(scissor));
1707    scissor.extent.width = demo->width;
1708    scissor.extent.height = demo->height;
1709    scissor.offset.x = 0;
1710    scissor.offset.y = 0;
1711    viewport_create.pScissors = &scissor;
1712
1713    memset(&line_width, 0, sizeof(line_width));
1714    line_width.sType = VK_STRUCTURE_TYPE_DYNAMIC_LINE_WIDTH_STATE_CREATE_INFO;
1715    line_width.lineWidth = 1.0;
1716
1717    memset(&depth_bias, 0, sizeof(depth_bias));
1718    depth_bias.sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_BIAS_STATE_CREATE_INFO;
1719    depth_bias.depthBias = 0.0f;
1720    depth_bias.depthBiasClamp = 0.0f;
1721    depth_bias.slopeScaledDepthBias = 0.0f;
1722
1723    memset(&blend, 0, sizeof(blend));
1724    blend.sType = VK_STRUCTURE_TYPE_DYNAMIC_BLEND_STATE_CREATE_INFO;
1725    blend.blendConst[0] = 1.0f;
1726    blend.blendConst[1] = 1.0f;
1727    blend.blendConst[2] = 1.0f;
1728    blend.blendConst[3] = 1.0f;
1729
1730    memset(&depth_bounds, 0, sizeof(depth_bounds));
1731    depth_bounds.sType = VK_STRUCTURE_TYPE_DYNAMIC_DEPTH_BOUNDS_STATE_CREATE_INFO;
1732    depth_bounds.minDepthBounds = 0.0f;
1733    depth_bounds.maxDepthBounds = 1.0f;
1734
1735    memset(&stencil, 0, sizeof(stencil));
1736    stencil.sType = VK_STRUCTURE_TYPE_DYNAMIC_STENCIL_STATE_CREATE_INFO;
1737    stencil.stencilReference = 0;
1738    stencil.stencilCompareMask = 0xff;
1739    stencil.stencilWriteMask = 0xff;
1740
1741    err = vkCreateDynamicViewportState(demo->device, &viewport_create, &demo->dynamic_viewport);
1742    assert(!err);
1743
1744    err = vkCreateDynamicLineWidthState(demo->device, &line_width, &demo->dynamic_line_width);
1745    assert(!err);
1746
1747    err = vkCreateDynamicDepthBiasState(demo->device, &depth_bias, &demo->dynamic_depth_bias);
1748    assert(!err);
1749
1750    err = vkCreateDynamicBlendState(demo->device,
1751            &blend, &demo->dynamic_blend);
1752    assert(!err);
1753
1754    err = vkCreateDynamicDepthBoundsState(demo->device,
1755            &depth_bounds, &demo->dynamic_depth_bounds);
1756    assert(!err);
1757
1758    err = vkCreateDynamicStencilState(demo->device,
1759            &stencil, &stencil, &demo->dynamic_stencil);
1760    assert(!err);
1761}
1762
1763static void demo_prepare_descriptor_pool(struct demo *demo)
1764{
1765    const VkDescriptorTypeCount type_counts[2] = {
1766        [0] = {
1767            .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1768            .count = 1,
1769        },
1770        [1] = {
1771            .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1772            .count = DEMO_TEXTURE_COUNT,
1773        },
1774    };
1775    const VkDescriptorPoolCreateInfo descriptor_pool = {
1776        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1777        .pNext = NULL,
1778        .count = 2,
1779        .pTypeCount = type_counts,
1780    };
1781    VkResult U_ASSERT_ONLY err;
1782
1783    err = vkCreateDescriptorPool(demo->device,
1784            VK_DESCRIPTOR_POOL_USAGE_ONE_SHOT, 1,
1785            &descriptor_pool, &demo->desc_pool);
1786    assert(!err);
1787}
1788
1789static void demo_prepare_descriptor_set(struct demo *demo)
1790{
1791    VkDescriptorInfo tex_descs[DEMO_TEXTURE_COUNT];
1792    VkWriteDescriptorSet writes[2];
1793    VkResult U_ASSERT_ONLY err;
1794    uint32_t i;
1795
1796    err = vkAllocDescriptorSets(demo->device, demo->desc_pool,
1797            VK_DESCRIPTOR_SET_USAGE_STATIC,
1798            1, &demo->desc_layout,
1799            &demo->desc_set);
1800    assert(!err);
1801
1802    memset(&tex_descs, 0, sizeof(tex_descs));
1803    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1804        tex_descs[i].sampler = demo->textures[i].sampler;
1805        tex_descs[i].imageView = demo->textures[i].view;
1806        tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1807    }
1808
1809    memset(&writes, 0, sizeof(writes));
1810
1811    writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1812    writes[0].destSet = demo->desc_set;
1813    writes[0].count = 1;
1814    writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1815    writes[0].pDescriptors = &demo->uniform_data.desc;
1816
1817    writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1818    writes[1].destSet = demo->desc_set;
1819    writes[1].destBinding = 1;
1820    writes[1].count = DEMO_TEXTURE_COUNT;
1821    writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1822    writes[1].pDescriptors = tex_descs;
1823
1824    vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL);
1825}
1826
1827static void demo_prepare_framebuffers(struct demo *demo)
1828{
1829    VkImageView attachments[2];
1830    attachments[1] = demo->depth.view;
1831
1832    const VkFramebufferCreateInfo fb_info = {
1833         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1834         .pNext = NULL,
1835         .renderPass = demo->render_pass,
1836         .attachmentCount = 2,
1837         .pAttachments = attachments,
1838         .width  = demo->width,
1839         .height = demo->height,
1840         .layers = 1,
1841    };
1842    VkResult U_ASSERT_ONLY err;
1843    uint32_t i;
1844
1845    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
1846        attachments[0] = demo->buffers[i].view;
1847        err = vkCreateFramebuffer(demo->device, &fb_info, &demo->framebuffers[i]);
1848        assert(!err);
1849    }
1850}
1851
1852static void demo_prepare(struct demo *demo)
1853{
1854    VkResult U_ASSERT_ONLY err;
1855
1856    const VkCmdPoolCreateInfo cmd_pool_info = {
1857        .sType = VK_STRUCTURE_TYPE_CMD_POOL_CREATE_INFO,
1858        .pNext = NULL,
1859        .queueFamilyIndex = demo->graphics_queue_node_index,
1860        .flags = 0,
1861    };
1862    err = vkCreateCommandPool(demo->device, &cmd_pool_info, &demo->cmd_pool);
1863    assert(!err);
1864
1865    const VkCmdBufferCreateInfo cmd = {
1866        .sType = VK_STRUCTURE_TYPE_CMD_BUFFER_CREATE_INFO,
1867        .pNext = NULL,
1868        .cmdPool = demo->cmd_pool,
1869        .level = VK_CMD_BUFFER_LEVEL_PRIMARY,
1870        .flags = 0,
1871    };
1872
1873    demo_prepare_buffers(demo);
1874    demo_prepare_depth(demo);
1875    demo_prepare_textures(demo);
1876    demo_prepare_cube_data_buffer(demo);
1877
1878    demo_prepare_descriptor_layout(demo);
1879    demo_prepare_render_pass(demo);
1880    demo_prepare_pipeline(demo);
1881    demo_prepare_dynamic_states(demo);
1882
1883    for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
1884        err = vkCreateCommandBuffer(demo->device, &cmd, &demo->buffers[i].cmd);
1885        assert(!err);
1886    }
1887
1888    demo_prepare_descriptor_pool(demo);
1889    demo_prepare_descriptor_set(demo);
1890
1891    demo_prepare_framebuffers(demo);
1892
1893    for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
1894        demo->current_buffer = i;
1895        demo_draw_build_cmd(demo, demo->buffers[i].cmd);
1896    }
1897
1898    /*
1899     * Prepare functions above may generate pipeline commands
1900     * that need to be flushed before beginning the render loop.
1901     */
1902    demo_flush_init_cmd(demo);
1903
1904    demo->current_buffer = 0;
1905	demo->prepared = true;
1906}
1907
1908static void demo_cleanup(struct demo *demo)
1909{
1910    uint32_t i;
1911
1912    demo->prepared = false;
1913
1914    for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
1915        vkDestroyFramebuffer(demo->device, demo->framebuffers[i]);
1916    }
1917    vkFreeDescriptorSets(demo->device, demo->desc_pool, 1, &demo->desc_set);
1918    vkDestroyDescriptorPool(demo->device, demo->desc_pool);
1919
1920    vkDestroyDynamicViewportState(demo->device, demo->dynamic_viewport);
1921    vkDestroyDynamicLineWidthState(demo->device, demo->dynamic_line_width);
1922    vkDestroyDynamicDepthBiasState(demo->device, demo->dynamic_depth_bias);
1923    vkDestroyDynamicBlendState(demo->device, demo->dynamic_blend);
1924    vkDestroyDynamicDepthBoundsState(demo->device, demo->dynamic_depth_bounds);
1925    vkDestroyDynamicStencilState(demo->device, demo->dynamic_stencil);
1926
1927    vkDestroyPipeline(demo->device, demo->pipeline);
1928    vkDestroyPipelineCache(demo->device, demo->pipelineCache);
1929    vkDestroyRenderPass(demo->device, demo->render_pass);
1930    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout);
1931    vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout);
1932
1933    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1934        vkDestroyImageView(demo->device, demo->textures[i].view);
1935        vkDestroyImage(demo->device, demo->textures[i].image);
1936        vkFreeMemory(demo->device, demo->textures[i].mem);
1937        vkDestroySampler(demo->device, demo->textures[i].sampler);
1938    }
1939    demo->fpDestroySwapchainKHR(demo->device, demo->swap_chain);
1940
1941    vkDestroyImageView(demo->device, demo->depth.view);
1942    vkDestroyImage(demo->device, demo->depth.image);
1943    vkFreeMemory(demo->device, demo->depth.mem);
1944
1945    vkDestroyBuffer(demo->device, demo->uniform_data.buf);
1946    vkFreeMemory(demo->device, demo->uniform_data.mem);
1947
1948    for (i = 0; i < demo->swapchainImageCount; i++) {
1949        vkDestroyImageView(demo->device, demo->buffers[i].view);
1950        vkDestroyCommandBuffer(demo->device, demo->buffers[i].cmd);
1951    }
1952    free(demo->buffers);
1953
1954    vkDestroyCommandPool(demo->device, demo->cmd_pool);
1955    vkDestroyDevice(demo->device);
1956    if (demo->validate) {
1957        demo->dbgDestroyMsgCallback(demo->inst, demo->msg_callback);
1958    }
1959    vkDestroyInstance(demo->inst);
1960
1961#ifndef _WIN32
1962    xcb_destroy_window(demo->connection, demo->window);
1963    xcb_disconnect(demo->connection);
1964#endif // _WIN32
1965}
1966
1967// On MS-Windows, make this a global, so it's available to WndProc()
1968struct demo demo;
1969
1970#ifdef _WIN32
1971static void demo_run(struct demo *demo)
1972{
1973    if (!demo->prepared)
1974        return;
1975    // Wait for work to finish before updating MVP.
1976    vkDeviceWaitIdle(demo->device);
1977    demo_update_data_buffer(demo);
1978
1979    demo_draw(demo);
1980
1981    // Wait for work to finish before updating MVP.
1982    vkDeviceWaitIdle(demo->device);
1983
1984    demo->curFrame++;
1985
1986    if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount)
1987    {
1988        demo->quit=true;
1989        demo_cleanup(demo);
1990        ExitProcess(0);
1991    }
1992
1993}
1994
1995// MS-Windows event handling function:
1996LRESULT CALLBACK WndProc(HWND hWnd,
1997                         UINT uMsg,
1998                         WPARAM wParam,
1999                         LPARAM lParam)
2000{
2001    switch(uMsg)
2002    {
2003    case WM_CLOSE:
2004        PostQuitMessage(0);
2005        break;
2006    case WM_PAINT:
2007        demo_run(&demo);
2008        return 0;
2009    default:
2010        break;
2011    }
2012    return (DefWindowProc(hWnd, uMsg, wParam, lParam));
2013}
2014
2015static void demo_create_window(struct demo *demo)
2016{
2017    WNDCLASSEX  win_class;
2018
2019    // Initialize the window class structure:
2020    win_class.cbSize = sizeof(WNDCLASSEX);
2021    win_class.style = CS_HREDRAW | CS_VREDRAW;
2022    win_class.lpfnWndProc = WndProc;
2023    win_class.cbClsExtra = 0;
2024    win_class.cbWndExtra = 0;
2025    win_class.hInstance = demo->connection; // hInstance
2026    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
2027    win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
2028    win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
2029    win_class.lpszMenuName = NULL;
2030    win_class.lpszClassName = demo->name;
2031    win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
2032    // Register window class:
2033    if (!RegisterClassEx(&win_class)) {
2034        // It didn't work, so try to give a useful error:
2035        printf("Unexpected error trying to start the application!\n");
2036        fflush(stdout);
2037        exit(1);
2038    }
2039    // Create window with the registered class:
2040    RECT wr = { 0, 0, demo->width, demo->height };
2041    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
2042    demo->window = CreateWindowEx(0,
2043                                  demo->name,           // class name
2044                                  demo->name,           // app name
2045                                  WS_OVERLAPPEDWINDOW | // window style
2046                                  WS_VISIBLE |
2047                                  WS_SYSMENU,
2048                                  100,100,              // x/y coords
2049                                  wr.right-wr.left,     // width
2050                                  wr.bottom-wr.top,     // height
2051                                  NULL,                 // handle to parent
2052                                  NULL,                 // handle to menu
2053                                  demo->connection,     // hInstance
2054                                  NULL);                // no extra parameters
2055    if (!demo->window) {
2056        // It didn't work, so try to give a useful error:
2057        printf("Cannot create a window in which to draw!\n");
2058        fflush(stdout);
2059        exit(1);
2060    }
2061}
2062#else  // _WIN32
2063static void demo_handle_event(struct demo *demo,
2064                              const xcb_generic_event_t *event)
2065{
2066    uint8_t event_code = event->response_type & 0x7f;
2067    switch (event_code) {
2068    case XCB_EXPOSE:
2069        // TODO: Resize window
2070        break;
2071    case XCB_CLIENT_MESSAGE:
2072        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
2073           (*demo->atom_wm_delete_window).atom) {
2074            demo->quit = true;
2075        }
2076        break;
2077    case XCB_KEY_RELEASE:
2078        {
2079            const xcb_key_release_event_t *key =
2080                (const xcb_key_release_event_t *) event;
2081
2082            switch (key->detail) {
2083            case 0x9:           // Escape
2084                demo->quit = true;
2085                break;
2086            case 0x71:          // left arrow key
2087                demo->spin_angle += demo->spin_increment;
2088                break;
2089            case 0x72:          // right arrow key
2090                demo->spin_angle -= demo->spin_increment;
2091                break;
2092            case 0x41:
2093                demo->pause = !demo->pause;
2094                break;
2095            }
2096        }
2097        break;
2098    default:
2099        break;
2100    }
2101}
2102
2103static void demo_run(struct demo *demo)
2104{
2105    xcb_flush(demo->connection);
2106
2107    while (!demo->quit) {
2108        xcb_generic_event_t *event;
2109
2110        if (demo->pause) {
2111            event = xcb_wait_for_event(demo->connection);
2112        } else {
2113            event = xcb_poll_for_event(demo->connection);
2114        }
2115        if (event) {
2116            demo_handle_event(demo, event);
2117            free(event);
2118        }
2119
2120        // Wait for work to finish before updating MVP.
2121        vkDeviceWaitIdle(demo->device);
2122        demo_update_data_buffer(demo);
2123
2124        demo_draw(demo);
2125
2126        // Wait for work to finish before updating MVP.
2127        vkDeviceWaitIdle(demo->device);
2128        demo->curFrame++;
2129        if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount)
2130            demo->quit = true;
2131
2132    }
2133}
2134
2135static void demo_create_window(struct demo *demo)
2136{
2137    uint32_t value_mask, value_list[32];
2138
2139    demo->window = xcb_generate_id(demo->connection);
2140
2141    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
2142    value_list[0] = demo->screen->black_pixel;
2143    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
2144                    XCB_EVENT_MASK_EXPOSURE;
2145
2146    xcb_create_window(demo->connection,
2147            XCB_COPY_FROM_PARENT,
2148            demo->window, demo->screen->root,
2149            0, 0, demo->width, demo->height, 0,
2150            XCB_WINDOW_CLASS_INPUT_OUTPUT,
2151            demo->screen->root_visual,
2152            value_mask, value_list);
2153
2154    /* Magic code that will send notification when window is destroyed */
2155    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
2156                                                      "WM_PROTOCOLS");
2157    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
2158
2159    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
2160    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
2161
2162    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
2163                        demo->window, (*reply).atom, 4, 32, 1,
2164                        &(*demo->atom_wm_delete_window).atom);
2165    free(reply);
2166
2167    xcb_map_window(demo->connection, demo->window);
2168
2169    // Force the x/y coordinates to 100,100 results are identical in consecutive runs
2170    const uint32_t coords[] = {100,  100};
2171    xcb_configure_window(demo->connection, demo->window,
2172                         XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
2173}
2174#endif // _WIN32
2175
2176/*
2177 * Return 1 (true) if all layer names specified in check_names
2178 * can be found in given layer properties.
2179 */
2180static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
2181                              uint32_t layer_count, VkLayerProperties *layers)
2182{
2183    for (uint32_t i = 0; i < check_count; i++) {
2184        VkBool32 found = 0;
2185        for (uint32_t j = 0; j < layer_count; j++) {
2186            if (!strcmp(check_names[i], layers[j].layerName)) {
2187                found = 1;
2188            }
2189        }
2190        if (!found) {
2191            fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
2192            return 0;
2193        }
2194    }
2195    return 1;
2196}
2197
2198static void demo_init_vk(struct demo *demo)
2199{
2200    VkResult err;
2201    char *extension_names[64];
2202    VkExtensionProperties *instance_extensions;
2203    VkPhysicalDevice *physical_devices;
2204    VkLayerProperties *instance_layers;
2205    VkLayerProperties *device_layers;
2206    uint32_t instance_extension_count = 0;
2207    uint32_t instance_layer_count = 0;
2208    uint32_t enabled_extension_count = 0;
2209    uint32_t enabled_layer_count = 0;
2210
2211    char *instance_validation_layers[] = {
2212        "Threading",
2213        "MemTracker",
2214        "ObjectTracker",
2215        "DrawState",
2216        "ParamChecker",
2217        "ShaderChecker",
2218    };
2219
2220    char *device_validation_layers[] = {
2221        "Threading",
2222        "MemTracker",
2223        "ObjectTracker",
2224        "DrawState",
2225        "ParamChecker",
2226        "ShaderChecker",
2227    };
2228
2229    /* Look for validation layers */
2230    VkBool32 validation_found = 0;
2231    err = vkGetGlobalLayerProperties(&instance_layer_count, NULL);
2232    assert(!err);
2233
2234    instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count);
2235    err = vkGetGlobalLayerProperties(&instance_layer_count, instance_layers);
2236    assert(!err);
2237
2238    if (demo->validate) {
2239        validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers,
2240                                             instance_layer_count, instance_layers);
2241        if (!validation_found) {
2242            ERR_EXIT("vkGetGlobalLayerProperties failed to find"
2243                     "required validation layer.\n\n"
2244                     "Please look at the Getting Started guide for additional "
2245                     "information.\n",
2246                     "vkCreateInstance Failure");
2247        }
2248        enabled_layer_count = ARRAY_SIZE(instance_validation_layers);
2249    }
2250
2251    err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, NULL);
2252    assert(!err);
2253
2254    VkBool32 WSIextFound = 0;
2255    memset(extension_names, 0, sizeof(extension_names));
2256    instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count);
2257    err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, instance_extensions);
2258    assert(!err);
2259    for (uint32_t i = 0; i < instance_extension_count; i++) {
2260        if (!strcmp("VK_EXT_KHR_swapchain", instance_extensions[i].extName)) {
2261            WSIextFound = 1;
2262            extension_names[enabled_extension_count++] = "VK_EXT_KHR_swapchain";
2263        }
2264        if (!strcmp(VK_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) {
2265            if (demo->validate) {
2266                extension_names[enabled_extension_count++] = VK_DEBUG_REPORT_EXTENSION_NAME;
2267            }
2268        }
2269        assert(enabled_extension_count < 64);
2270    }
2271    if (!WSIextFound) {
2272        ERR_EXIT("vkGetGlobalExtensionProperties failed to find the "
2273                 "\"VK_EXT_KHR_swapchain\" extension.\n\nDo you have a compatible "
2274                 "Vulkan installable client driver (ICD) installed?\nPlease "
2275                 "look at the Getting Started guide for additional "
2276                 "information.\n",
2277                 "vkCreateInstance Failure");
2278    }
2279    const VkApplicationInfo app = {
2280        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
2281        .pNext = NULL,
2282        .pAppName = APP_SHORT_NAME,
2283        .appVersion = 0,
2284        .pEngineName = APP_SHORT_NAME,
2285        .engineVersion = 0,
2286        .apiVersion = VK_API_VERSION,
2287    };
2288    VkInstanceCreateInfo inst_info = {
2289        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
2290        .pNext = NULL,
2291        .pAppInfo = &app,
2292        .pAllocCb = NULL,
2293        .layerCount = enabled_layer_count,
2294        .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? instance_validation_layers : NULL),
2295        .extensionCount = enabled_extension_count,
2296        .ppEnabledExtensionNames = (const char *const*) extension_names,
2297    };
2298    const VkDeviceQueueCreateInfo queue = {
2299        .queueFamilyIndex = 0,
2300        .queueCount = 1,
2301    };
2302
2303    uint32_t gpu_count;
2304
2305    err = vkCreateInstance(&inst_info, &demo->inst);
2306    if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
2307        ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
2308                 "(ICD).\n\nPlease look at the Getting Started guide for "
2309                 "additional information.\n",
2310                 "vkCreateInstance Failure");
2311    } else if (err == VK_ERROR_INVALID_EXTENSION) {
2312        ERR_EXIT("Cannot find a specified extension library"
2313                 ".\nMake sure your layers path is set appropriately\n",
2314                 "vkCreateInstance Failure");
2315    } else if (err) {
2316        ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
2317                 "installable client driver (ICD) installed?\nPlease look at "
2318                 "the Getting Started guide for additional information.\n",
2319                 "vkCreateInstance Failure");
2320    }
2321
2322    free(instance_layers);
2323    free(instance_extensions);
2324
2325    /* Make initial call to query gpu_count, then second call for gpu info*/
2326    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2327    assert(!err && gpu_count > 0);
2328    physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
2329    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
2330    assert(!err);
2331    /* For cube demo we just grab the first physical device */
2332    demo->gpu = physical_devices[0];
2333    free(physical_devices);
2334
2335    /* Look for validation layers */
2336    validation_found = 0;
2337    enabled_layer_count = 0;
2338    uint32_t device_layer_count = 0;
2339    err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2340    assert(!err);
2341
2342    device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count);
2343    err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers);
2344    assert(!err);
2345
2346    if (demo->validate) {
2347        validation_found = demo_check_layers(ARRAY_SIZE(device_validation_layers), device_validation_layers,
2348                                             device_layer_count, device_layers);
2349        if (!validation_found) {
2350            ERR_EXIT("vkGetPhysicalDeviceLayerProperties failed to find"
2351                     "a required validation layer.\n\n"
2352                     "Please look at the Getting Started guide for additional "
2353                     "information.\n",
2354                     "vkCreateDevice Failure");
2355        }
2356        enabled_layer_count = ARRAY_SIZE(device_validation_layers);
2357    }
2358
2359    uint32_t device_extension_count = 0;
2360    VkExtensionProperties *device_extensions = NULL;
2361    err = vkGetPhysicalDeviceExtensionProperties(
2362              demo->gpu, NULL, &device_extension_count, NULL);
2363    assert(!err);
2364
2365    WSIextFound = 0;
2366    enabled_extension_count = 0;
2367    memset(extension_names, 0, sizeof(extension_names));
2368    device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count);
2369    err = vkGetPhysicalDeviceExtensionProperties(
2370              demo->gpu, NULL, &device_extension_count, device_extensions);
2371    assert(!err);
2372
2373    for (uint32_t i = 0; i < device_extension_count; i++) {
2374        if (!strcmp("VK_EXT_KHR_device_swapchain", device_extensions[i].extName)) {
2375            WSIextFound = 1;
2376            extension_names[enabled_extension_count++] = "VK_EXT_KHR_device_swapchain";
2377        }
2378        assert(enabled_extension_count < 64);
2379    }
2380    if (!WSIextFound) {
2381        ERR_EXIT("vkGetPhysicalDeviceExtensionProperties failed to find the "
2382                 "\"VK_EXT_KHR_device_swapchain\" extension.\n\nDo you have a compatible "
2383                 "Vulkan installable client driver (ICD) installed?\nPlease "
2384                 "look at the Getting Started guide for additional "
2385                 "information.\n",
2386                 "vkCreateInstance Failure");
2387    }
2388
2389    VkDeviceCreateInfo device = {
2390        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2391        .pNext = NULL,
2392        .queueRecordCount = 1,
2393        .pRequestedQueues = &queue,
2394        .layerCount = enabled_layer_count,
2395        .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? device_validation_layers : NULL),
2396        .extensionCount = enabled_extension_count,
2397        .ppEnabledExtensionNames = (const char *const*) extension_names,
2398    };
2399
2400    if (demo->validate) {
2401        demo->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgCreateMsgCallback");
2402        demo->dbgDestroyMsgCallback = (PFN_vkDbgDestroyMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgDestroyMsgCallback");
2403        if (!demo->dbgCreateMsgCallback) {
2404            ERR_EXIT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\n",
2405                     "vkGetProcAddr Failure");
2406        }
2407        if (!demo->dbgDestroyMsgCallback) {
2408            ERR_EXIT("GetProcAddr: Unable to find vkDbgDestroyMsgCallback\n",
2409                     "vkGetProcAddr Failure");
2410        }
2411        demo->dbgBreakCallback = (PFN_vkDbgMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgBreakCallback");
2412        if (!demo->dbgBreakCallback) {
2413            ERR_EXIT("GetProcAddr: Unable to find vkDbgBreakCallback\n",
2414                     "vkGetProcAddr Failure");
2415        }
2416
2417        PFN_vkDbgMsgCallback callback;
2418
2419        if (!demo->use_break) {
2420            callback = dbgFunc;
2421        } else {
2422            callback = demo->dbgBreakCallback;
2423        }
2424        err = demo->dbgCreateMsgCallback(
2425                  demo->inst,
2426                  VK_DBG_REPORT_ERROR_BIT | VK_DBG_REPORT_WARN_BIT,
2427                  callback, NULL,
2428                  &demo->msg_callback);
2429        switch (err) {
2430        case VK_SUCCESS:
2431            break;
2432        case VK_ERROR_OUT_OF_HOST_MEMORY:
2433            ERR_EXIT("dbgCreateMsgCallback: out of host memory\n",
2434                     "dbgCreateMsgCallback Failure");
2435            break;
2436        default:
2437            ERR_EXIT("dbgCreateMsgCallback: unknown failure\n",
2438                     "dbgCreateMsgCallback Failure");
2439            break;
2440        }
2441    }
2442
2443    err = vkCreateDevice(demo->gpu, &device, &demo->device);
2444    assert(!err);
2445
2446    free(device_layers);
2447
2448    GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2449    GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePropertiesKHR);
2450    GET_DEVICE_PROC_ADDR(demo->device, GetSurfaceFormatsKHR);
2451    GET_DEVICE_PROC_ADDR(demo->device, GetSurfacePresentModesKHR);
2452    GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR);
2453    GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR);
2454    GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR);
2455    GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR);
2456    GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR);
2457    GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR);
2458
2459    err = vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2460    assert(!err);
2461
2462    /* Call with NULL data to get count */
2463    err = vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, NULL);
2464    assert(!err);
2465    assert(demo->queue_count >= 1);
2466
2467    demo->queue_props = (VkQueueFamilyProperties *) malloc(demo->queue_count * sizeof(VkQueueFamilyProperties));
2468    err = vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, demo->queue_props);
2469    assert(!err);
2470    assert(demo->queue_count >= 1);
2471}
2472
2473static void demo_init_vk_wsi(struct demo *demo)
2474{
2475    VkResult err;
2476    uint32_t i;
2477
2478    // Construct the WSI surface description:
2479    demo->surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_KHR;
2480    demo->surface_description.pNext = NULL;
2481#ifdef _WIN32
2482    demo->surface_description.platform = VK_PLATFORM_WIN32_KHR;
2483    demo->surface_description.pPlatformHandle = demo->connection;
2484    demo->surface_description.pPlatformWindow = demo->window;
2485#else  // _WIN32
2486    demo->platform_handle_xcb.connection = demo->connection;
2487    demo->platform_handle_xcb.root = demo->screen->root;
2488    demo->surface_description.platform = VK_PLATFORM_XCB_KHR;
2489    demo->surface_description.pPlatformHandle = &demo->platform_handle_xcb;
2490    demo->surface_description.pPlatformWindow = &demo->window;
2491#endif // _WIN32
2492
2493    // Iterate over each queue to learn whether it supports presenting to WSI:
2494    VkBool32* supportsPresent = (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2495    for (i = 0; i < demo->queue_count; i++) {
2496        demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i,
2497                                                   (VkSurfaceDescriptionKHR *) &demo->surface_description,
2498                                                   &supportsPresent[i]);
2499    }
2500
2501    // Search for a graphics and a present queue in the array of queue
2502    // families, try to find one that supports both
2503    uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2504    uint32_t presentQueueNodeIndex  = UINT32_MAX;
2505    for (i = 0; i < demo->queue_count; i++) {
2506        if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2507            if (graphicsQueueNodeIndex == UINT32_MAX) {
2508                graphicsQueueNodeIndex = i;
2509            }
2510
2511            if (supportsPresent[i] == VK_TRUE) {
2512                graphicsQueueNodeIndex = i;
2513                presentQueueNodeIndex = i;
2514                break;
2515            }
2516        }
2517    }
2518    if (presentQueueNodeIndex == UINT32_MAX) {
2519        // If didn't find a queue that supports both graphics and present, then
2520        // find a separate present queue.
2521        for (uint32_t i = 0; i < demo->queue_count; ++i) {
2522            if (supportsPresent[i] == VK_TRUE) {
2523                presentQueueNodeIndex = i;
2524                break;
2525            }
2526        }
2527    }
2528    free(supportsPresent);
2529
2530    // Generate error if could not find both a graphics and a present queue
2531    if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
2532        ERR_EXIT("Could not find a graphics and a present queue\n",
2533                 "WSI Initialization Failure");
2534    }
2535
2536    // TODO: Add support for separate queues, including presentation,
2537    //       synchronization, and appropriate tracking for QueueSubmit
2538    // While it is possible for an application to use a separate graphics and a
2539    // present queues, this demo program assumes it is only using one:
2540    if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2541        ERR_EXIT("Could not find a common graphics and a present queue\n",
2542                 "WSI Initialization Failure");
2543    }
2544
2545    demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2546
2547    err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
2548            0, &demo->queue);
2549    assert(!err);
2550
2551    // Get the list of VkFormat's that are supported:
2552    uint32_t formatCount;
2553    err = demo->fpGetSurfaceFormatsKHR(demo->device,
2554                                    (VkSurfaceDescriptionKHR *) &demo->surface_description,
2555                                    &formatCount, NULL);
2556    assert(!err);
2557    VkSurfaceFormatKHR *surfFormats =
2558        (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2559    err = demo->fpGetSurfaceFormatsKHR(demo->device,
2560                                    (VkSurfaceDescriptionKHR *) &demo->surface_description,
2561                                    &formatCount, surfFormats);
2562    assert(!err);
2563    // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2564    // the surface has no preferred format.  Otherwise, at least one
2565    // supported format will be returned.
2566    if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
2567    {
2568        demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2569    }
2570    else
2571    {
2572        assert(formatCount >= 1);
2573        demo->format = surfFormats[0].format;
2574    }
2575    demo->color_space = surfFormats[0].colorSpace;
2576
2577    demo->quit = false;
2578    demo->curFrame = 0;
2579
2580    // Get Memory information and properties
2581    err = vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2582    assert(!err);
2583}
2584
2585static void demo_init_connection(struct demo *demo)
2586{
2587#ifndef _WIN32
2588    const xcb_setup_t *setup;
2589    xcb_screen_iterator_t iter;
2590    int scr;
2591
2592    demo->connection = xcb_connect(NULL, &scr);
2593    if (demo->connection == NULL) {
2594        printf("Cannot find a compatible Vulkan installable client driver "
2595               "(ICD).\nExiting ...\n");
2596        fflush(stdout);
2597        exit(1);
2598    }
2599
2600    setup = xcb_get_setup(demo->connection);
2601    iter = xcb_setup_roots_iterator(setup);
2602    while (scr-- > 0)
2603        xcb_screen_next(&iter);
2604
2605    demo->screen = iter.data;
2606#endif // _WIN32
2607}
2608
2609static void demo_init(struct demo *demo, int argc, char **argv)
2610{
2611    vec3 eye = {0.0f, 3.0f, 5.0f};
2612    vec3 origin = {0, 0, 0};
2613    vec3 up = {0.0f, 1.0f, 0.0};
2614
2615    memset(demo, 0, sizeof(*demo));
2616    demo->frameCount = INT_MAX;
2617
2618    for (int i = 1; i < argc; i++) {
2619        if (strcmp(argv[i], "--use_staging") == 0) {
2620            demo->use_staging_buffer = true;
2621            continue;
2622        }
2623        if (strcmp(argv[i], "--use_glsl") == 0) {
2624            demo->use_glsl = true;
2625            continue;
2626        }
2627        if (strcmp(argv[i], "--break") == 0) {
2628            demo->use_break = true;
2629            continue;
2630        }
2631        if (strcmp(argv[i], "--validate") == 0) {
2632            demo->validate = true;
2633            continue;
2634        }
2635        if (strcmp(argv[i], "--c") == 0 &&
2636            demo->frameCount == INT_MAX &&
2637            i < argc-1 &&
2638            sscanf(argv[i+1],"%d", &demo->frameCount) == 1 &&
2639            demo->frameCount >= 0)
2640        {
2641            i++;
2642            continue;
2643        }
2644
2645        fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] [--c <framecount>]\n", APP_SHORT_NAME);
2646        fflush(stderr);
2647        exit(1);
2648    }
2649
2650    demo_init_connection(demo);
2651    demo_init_vk(demo);
2652
2653    demo->width = 500;
2654    demo->height = 500;
2655
2656    demo->spin_angle = 0.01f;
2657    demo->spin_increment = 0.01f;
2658    demo->pause = false;
2659
2660    mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f), 1.0f, 0.1f, 100.0f);
2661    mat4x4_look_at(demo->view_matrix, eye, origin, up);
2662    mat4x4_identity(demo->model_matrix);
2663}
2664
2665
2666#ifdef _WIN32
2667extern int __getmainargs(
2668        int * _Argc,
2669        char *** _Argv,
2670        char *** _Env,
2671        int _DoWildCard,
2672        int * new_mode);
2673
2674int WINAPI WinMain(HINSTANCE hInstance,
2675                   HINSTANCE hPrevInstance,
2676                   LPSTR pCmdLine,
2677                   int nCmdShow)
2678{
2679    MSG msg;         // message
2680    bool done;        // flag saying when app is complete
2681    int argc;
2682    char** argv;
2683    char** env;
2684    int new_mode = 0;
2685
2686    __getmainargs(&argc,&argv,&env,0,&new_mode);
2687
2688    demo_init(&demo, argc, argv);
2689    demo.connection = hInstance;
2690    strncpy(demo.name, "cube", APP_NAME_STR_LEN);
2691    demo_create_window(&demo);
2692    demo_init_vk_wsi(&demo);
2693
2694    demo_prepare(&demo);
2695
2696    done = false; //initialize loop condition variable
2697    /* main message loop*/
2698    while(!done)
2699    {
2700        PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2701        if (msg.message == WM_QUIT) //check for a quit message
2702        {
2703            done = true; //if found, quit app
2704        }
2705        else
2706        {
2707            /* Translate and dispatch to event queue*/
2708            TranslateMessage(&msg);
2709            DispatchMessage(&msg);
2710        }
2711    }
2712
2713    demo_cleanup(&demo);
2714
2715    return (int) msg.wParam;
2716}
2717#else  // _WIN32
2718int main(int argc, char **argv)
2719{
2720    struct demo demo;
2721
2722    demo_init(&demo, argc, argv);
2723    demo_create_window(&demo);
2724    demo_init_vk_wsi(&demo);
2725
2726    demo_prepare(&demo);
2727    demo_run(&demo);
2728
2729    demo_cleanup(&demo);
2730
2731    return 0;
2732}
2733#endif // _WIN32
2734