tri.c revision 3e1c844db968370c97d42b721306126c30b3242b
1bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs/*
2bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs *
3bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs * Copyright (C) 2015 Valve Corporation
4b2fc6234973414f8881b534719380ea6a9f5c03dVinson Lee *
55a0915870c7e994d20334042b7647db749e79224Ben Skeggs * Permission is hereby granted, free of charge, to any person obtaining a
66d1cdec3ba151168bfc3aef222fba6265dfb41fbChristoph Bumiller * copy of this software and associated documentation files (the "Software"),
75a0915870c7e994d20334042b7647db749e79224Ben Skeggs * to deal in the Software without restriction, including without limitation
8b2fc6234973414f8881b534719380ea6a9f5c03dVinson Lee * the rights to use, copy, modify, merge, publish, distribute, sublicense,
990dcd6c89ab4afa55ca19d572a1a695cf55cb1b2Marcin Slusarz * and/or sell copies of the Software, and to permit persons to whom the
1090dcd6c89ab4afa55ca19d572a1a695cf55cb1b2Marcin Slusarz * Software is furnished to do so, subject to the following conditions:
115c1c4f8593073c0bad9bada9234657dda1b25ff0Ben Skeggs *
125c1c4f8593073c0bad9bada9234657dda1b25ff0Ben Skeggs * The above copyright notice and this permission notice shall be included
13bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs * in all copies or substantial portions of the Software.
14bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs *
15bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
166d1cdec3ba151168bfc3aef222fba6265dfb41fbChristoph Bumiller * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
176d1cdec3ba151168bfc3aef222fba6265dfb41fbChristoph Bumiller * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
186d1cdec3ba151168bfc3aef222fba6265dfb41fbChristoph Bumiller * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1942d9f2bb7bc21ff8c1a3fc4b4ceb4d294bccaabeLuca Barbieri * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * DEALINGS IN THE SOFTWARE.
221befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller *
231befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * Author: Chia-I Wu <olvaffe@gmail.com>
241befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * Author: Cody Northrop <cody@lunarg.com>
251befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
261befacc7647f51344f5cfbfa86b62e53625a436fChristoph Bumiller * Author: Ian Elliott <ian@LunarG.com>
275a0915870c7e994d20334042b7647db749e79224Ben Skeggs * Author: Jon Ashburn <jon@lunarg.com>
28e44089b2f79aa2dcaacf348911433d1e21235c0cChristoph Bumiller * Author: Piers Daniell <pdaniell@nvidia.com>
29e44089b2f79aa2dcaacf348911433d1e21235c0cChristoph Bumiller */
305a0915870c7e994d20334042b7647db749e79224Ben Skeggs/*
315a0915870c7e994d20334042b7647db749e79224Ben Skeggs * Draw a textured triangle with depth testing.  This is written against Intel
325a0915870c7e994d20334042b7647db749e79224Ben Skeggs * ICD.  It does not do state transition nor object memory binding like it
335a0915870c7e994d20334042b7647db749e79224Ben Skeggs * should.  It also does no error checking.
345a0915870c7e994d20334042b7647db749e79224Ben Skeggs */
355a0915870c7e994d20334042b7647db749e79224Ben Skeggs
369849f366cbfd781ebeca725058029b70c96836f9Marcin Slusarz#include <stdio.h>
375a0915870c7e994d20334042b7647db749e79224Ben Skeggs#include <stdlib.h>
385a0915870c7e994d20334042b7647db749e79224Ben Skeggs#include <string.h>
39cd24fcedecfc41d77047fb827a88db528ed292caBen Skeggs#include <stdbool.h>
40cd24fcedecfc41d77047fb827a88db528ed292caBen Skeggs#include <assert.h>
41cd24fcedecfc41d77047fb827a88db528ed292caBen Skeggs
429ed65301e044711de0db51b4986085fca170d764Christoph Bumiller#ifdef _WIN32
439ed65301e044711de0db51b4986085fca170d764Christoph Bumiller#pragma comment(linker, "/subsystem:windows")
44bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#define APP_NAME_STR_LEN 80
45bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#endif // _WIN32
46e02c1e215eabd14d0f58415e3a8179b995109696Vinson Lee
47bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#include <vulkan/vulkan.h>
48bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs
49bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#include "vulkan/vk_lunarg_debug_report.h"
50bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs
51bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs
52287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define DEMO_TEXTURE_COUNT 1
53287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define VERTEX_BUFFER_BIND_ID 0
54287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define APP_SHORT_NAME "tri"
55287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define APP_LONG_NAME "The Vulkan Triangle Demo Program"
56287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell
57287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
58287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell
59287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#if defined(NDEBUG) && defined(__GNUC__)
60287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#define U_ASSERT_ONLY __attribute__((unused))
61287c94ea4987033f9c99a2f91c5750c9083504caKeith Whitwell#else
62bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#define U_ASSERT_ONLY
63bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#endif
64bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs
65bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs#ifdef _WIN32
66ea316c5e060cbd92b34e0d794c0707d4ca79e6e8Christoph Bumiller#define ERR_EXIT(err_msg, err_class)                    \
6702f32454487f2caba00931590254260d871ae795Ben Skeggs    do {                                                \
68bc466be695913cd504cefddd857ac1cefda87a04Ben Skeggs        MessageBox(NULL, err_msg, err_class, MB_OK);    \
69        exit(1);                                        \
70   } while (0)
71#else  // _WIN32
72
73#define ERR_EXIT(err_msg, err_class)                    \
74    do {                                                \
75        printf(err_msg);                                \
76        fflush(stdout);                                 \
77        exit(1);                                        \
78   } while (0)
79#endif // _WIN32
80
81#define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                        \
82{                                                                       \
83    demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
84    if (demo->fp##entrypoint == NULL) {                                 \
85        ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint,  \
86                 "vkGetInstanceProcAddr Failure");                      \
87    }                                                                   \
88}
89
90#define GET_DEVICE_PROC_ADDR(dev, entrypoint)                           \
91{                                                                       \
92    demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint);   \
93    if (demo->fp##entrypoint == NULL) {                                 \
94        ERR_EXIT("vkGetDeviceProcAddr failed to find vk"#entrypoint,    \
95                 "vkGetDeviceProcAddr Failure");                        \
96    }                                                                   \
97}
98
99struct texture_object {
100    VkSampler sampler;
101
102    VkImage image;
103    VkImageLayout imageLayout;
104
105    VkDeviceMemory mem;
106    VkImageView view;
107    int32_t tex_width, tex_height;
108};
109
110VkBool32 dbgFunc(
111    VkFlags                             msgFlags,
112    VkDebugReportObjectTypeLUNARG                     objType,
113    uint64_t                            srcObject,
114    size_t                              location,
115    int32_t                             msgCode,
116    const char*                         pLayerPrefix,
117    const char*                         pMsg,
118    void*                               pUserData)
119{
120    char *message = (char *) malloc(strlen(pMsg)+100);
121
122    assert (message);
123
124    if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT) {
125        sprintf(message,"ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
126    } else if (msgFlags & VK_DEBUG_REPORT_WARN_BIT) {
127        sprintf(message,"WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
128    } else {
129        return false;
130    }
131
132#ifdef _WIN32
133    MessageBox(NULL, message, "Alert", MB_OK);
134#else
135    printf("%s\n",message);
136    fflush(stdout);
137#endif
138    free(message);
139
140    /*
141     * false indicates that layer should not bail-out of an
142     * API call that had validation failures. This may mean that the
143     * app dies inside the driver due to invalid parameter(s).
144     * That's what would happen without validation layers, so we'll
145     * keep that behavior here.
146     */
147    return false;
148}
149
150typedef struct _SwapchainBuffers {
151    VkImage image;
152    VkCommandBuffer cmd;
153    VkImageView view;
154} SwapchainBuffers;
155
156struct demo {
157#ifdef _WIN32
158#define APP_NAME_STR_LEN 80
159    HINSTANCE connection;        // hInstance - Windows Instance
160    char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
161    HWND        window;          // hWnd - window handle
162#else  // _WIN32
163    xcb_connection_t *connection;
164    xcb_screen_t *screen;
165    xcb_window_t window;
166    xcb_intern_atom_reply_t *atom_wm_delete_window;
167#endif // _WIN32
168    VkSurfaceKHR surface;
169    bool prepared;
170    bool use_staging_buffer;
171
172    VkAllocationCallbacks allocator;
173
174    VkInstance inst;
175    VkPhysicalDevice gpu;
176    VkDevice device;
177    VkQueue queue;
178    VkPhysicalDeviceProperties gpu_props;
179    VkQueueFamilyProperties *queue_props;
180    uint32_t graphics_queue_node_index;
181
182    int width, height;
183    VkFormat format;
184    VkColorSpaceKHR color_space;
185
186    PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
187    PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
188    PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
189    PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
190    PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
191    PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
192    PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
193    PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
194    PFN_vkQueuePresentKHR fpQueuePresentKHR;
195    uint32_t swapchainImageCount;
196    VkSwapchainKHR swapchain;
197    SwapchainBuffers *buffers;
198
199    VkCommandPool cmd_pool;
200
201    struct {
202        VkFormat format;
203
204        VkImage image;
205        VkDeviceMemory mem;
206        VkImageView view;
207    } depth;
208
209    struct texture_object textures[DEMO_TEXTURE_COUNT];
210
211    struct {
212        VkBuffer buf;
213        VkDeviceMemory mem;
214
215        VkPipelineVertexInputStateCreateInfo vi;
216        VkVertexInputBindingDescription vi_bindings[1];
217        VkVertexInputAttributeDescription vi_attrs[2];
218    } vertices;
219
220    VkCommandBuffer setup_cmd;  // Command Buffer for initialization commands
221    VkCommandBuffer draw_cmd;  // Command Buffer for drawing commands
222    VkPipelineLayout pipeline_layout;
223    VkDescriptorSetLayout desc_layout;
224    VkPipelineCache pipelineCache;
225    VkRenderPass render_pass;
226    VkPipeline pipeline;
227
228    VkShaderModule vert_shader_module;
229    VkShaderModule frag_shader_module;
230
231    VkDescriptorPool desc_pool;
232    VkDescriptorSet desc_set;
233
234    VkFramebuffer *framebuffers;
235
236    VkPhysicalDeviceMemoryProperties memory_properties;
237
238    bool validate;
239    PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback;
240    PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback;
241    VkDbgMsgCallback msg_callback;
242
243    float depthStencil;
244    float depthIncrement;
245
246    bool quit;
247    uint32_t current_buffer;
248    uint32_t queue_count;
249};
250
251// Forward declaration:
252static void demo_resize(struct demo *demo);
253
254static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex)
255{
256     // Search memtypes to find first index with those properties
257     for (uint32_t i = 0; i < 32; i++) {
258         if ((typeBits & 1) == 1) {
259             // Type is available, does it match user properties?
260             if ((demo->memory_properties.memoryTypes[i].propertyFlags & requirements_mask) == requirements_mask) {
261                 *typeIndex = i;
262                 return true;
263             }
264         }
265         typeBits >>= 1;
266     }
267     // No memory types matched, return failure
268     return false;
269}
270
271static void demo_flush_init_cmd(struct demo *demo)
272{
273    VkResult U_ASSERT_ONLY err;
274
275    if (demo->setup_cmd == VK_NULL_HANDLE)
276        return;
277
278    err = vkEndCommandBuffer(demo->setup_cmd);
279    assert(!err);
280
281    const VkCommandBuffer cmd_bufs[] = { demo->setup_cmd };
282    VkFence nullFence = {VK_NULL_HANDLE};
283    VkSubmitInfo submit_info = {
284        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
285        .pNext = NULL,
286        .waitSemaphoreCount = 0,
287        .pWaitSemaphores = NULL,
288        .commandBufferCount = 1,
289        .pCommandBuffers = cmd_bufs,
290        .signalSemaphoreCount = 0,
291        .pSignalSemaphores = NULL
292    };
293
294    err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
295    assert(!err);
296
297    err = vkQueueWaitIdle(demo->queue);
298    assert(!err);
299
300    vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
301    demo->setup_cmd = VK_NULL_HANDLE;
302}
303
304static void demo_set_image_layout(
305        struct demo *demo,
306        VkImage image,
307        VkImageAspectFlags aspectMask,
308        VkImageLayout old_image_layout,
309        VkImageLayout new_image_layout)
310{
311    VkResult U_ASSERT_ONLY err;
312
313    if (demo->setup_cmd == VK_NULL_HANDLE) {
314        const VkCommandBufferAllocateInfo cmd = {
315            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
316            .pNext = NULL,
317            .commandPool = demo->cmd_pool,
318            .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
319            .bufferCount = 1,
320        };
321
322        err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->setup_cmd);
323        assert(!err);
324
325        VkCommandBufferBeginInfo cmd_buf_info = {
326            .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
327            .pNext = NULL,
328            .flags = 0,
329            .renderPass = VK_NULL_HANDLE,
330            .subpass = 0,
331            .framebuffer = VK_NULL_HANDLE,
332            .occlusionQueryEnable = VK_FALSE,
333            .queryFlags = 0,
334            .pipelineStatistics = 0,
335        };
336        err = vkBeginCommandBuffer(demo->setup_cmd, &cmd_buf_info);
337        assert(!err);
338    }
339
340    VkImageMemoryBarrier image_memory_barrier = {
341        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
342        .pNext = NULL,
343        .srcAccessMask = 0,
344        .dstAccessMask = 0,
345        .oldLayout = old_image_layout,
346        .newLayout = new_image_layout,
347        .image = image,
348        .subresourceRange = { aspectMask, 0, 1, 0, 1 }
349    };
350
351    if (new_image_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
352        /* Make sure anything that was copying from this image has completed */
353        image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
354    }
355
356    if (new_image_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
357         image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
358     }
359
360    if (new_image_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
361        image_memory_barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
362    }
363
364    if (new_image_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
365        /* Make sure any Copy or CPU writes to image are flushed */
366        image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
367    }
368
369    VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
370
371    VkPipelineStageFlags src_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
372    VkPipelineStageFlags dest_stages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
373
374    vkCmdPipelineBarrier(demo->setup_cmd, src_stages, dest_stages, 0, 1, (const void * const*)&pmemory_barrier);
375}
376
377static void demo_draw_build_cmd(struct demo *demo)
378{
379    const VkCommandBufferBeginInfo cmd_buf_info = {
380        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
381        .pNext = NULL,
382        .flags = 0,
383        .renderPass = VK_NULL_HANDLE,
384        .subpass = 0,
385        .framebuffer = VK_NULL_HANDLE,
386        .occlusionQueryEnable = VK_FALSE,
387        .queryFlags = 0,
388        .pipelineStatistics = 0,
389    };
390    const VkClearValue clear_values[2] = {
391        [0] = { .color.float32 = { 0.2f, 0.2f, 0.2f, 0.2f } },
392        [1] = { .depthStencil = { demo->depthStencil, 0 } },
393    };
394    const VkRenderPassBeginInfo rp_begin = {
395        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
396        .pNext = NULL,
397        .renderPass = demo->render_pass,
398        .framebuffer = demo->framebuffers[demo->current_buffer],
399        .renderArea.offset.x = 0,
400        .renderArea.offset.y = 0,
401        .renderArea.extent.width = demo->width,
402        .renderArea.extent.height = demo->height,
403        .clearValueCount = 2,
404        .pClearValues = clear_values,
405    };
406    VkResult U_ASSERT_ONLY err;
407
408    err = vkBeginCommandBuffer(demo->draw_cmd, &cmd_buf_info);
409    assert(!err);
410
411    vkCmdBeginRenderPass(demo->draw_cmd, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
412    vkCmdBindPipeline(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
413                                  demo->pipeline);
414    vkCmdBindDescriptorSets(demo->draw_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline_layout,
415            0, 1, & demo->desc_set, 0, NULL);
416
417    VkViewport viewport;
418    memset(&viewport, 0, sizeof(viewport));
419    viewport.height = (float) demo->height;
420    viewport.width = (float) demo->width;
421    viewport.minDepth = (float) 0.0f;
422    viewport.maxDepth = (float) 1.0f;
423    vkCmdSetViewport(demo->draw_cmd, 1, &viewport);
424
425    VkRect2D scissor;
426    memset(&scissor, 0, sizeof(scissor));
427    scissor.extent.width = demo->width;
428    scissor.extent.height = demo->height;
429    scissor.offset.x = 0;
430    scissor.offset.y = 0;
431    vkCmdSetScissor(demo->draw_cmd, 1, &scissor);
432
433    VkDeviceSize offsets[1] = {0};
434    vkCmdBindVertexBuffers(demo->draw_cmd, VERTEX_BUFFER_BIND_ID, 1, &demo->vertices.buf, offsets);
435
436    vkCmdDraw(demo->draw_cmd, 3, 1, 0, 0);
437    vkCmdEndRenderPass(demo->draw_cmd);
438
439    VkImageMemoryBarrier prePresentBarrier = {
440        .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
441        .pNext = NULL,
442        .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
443        .dstAccessMask = 0,
444        .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
445        .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
446        .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
447        .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
448        .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }
449    };
450
451    prePresentBarrier.image = demo->buffers[demo->current_buffer].image;
452    VkImageMemoryBarrier *pmemory_barrier = &prePresentBarrier;
453    vkCmdPipelineBarrier(demo->draw_cmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
454                         0, 1, (const void * const*)&pmemory_barrier);
455
456    err = vkEndCommandBuffer(demo->draw_cmd);
457    assert(!err);
458}
459
460static void demo_draw(struct demo *demo)
461{
462    VkResult U_ASSERT_ONLY err;
463    VkSemaphore presentCompleteSemaphore;
464    VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
465        .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
466        .pNext = NULL,
467        .flags = 0,
468    };
469
470    err = vkCreateSemaphore(demo->device,
471                            &presentCompleteSemaphoreCreateInfo,
472                            NULL,
473                            &presentCompleteSemaphore);
474    assert(!err);
475
476    // Get the index of the next available swapchain image:
477    err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain,
478                                      UINT64_MAX,
479                                      presentCompleteSemaphore,
480                                      NULL,// TODO: Show use of fence
481                                      &demo->current_buffer);
482    if (err == VK_ERROR_OUT_OF_DATE_KHR) {
483        // demo->swapchain is out of date (e.g. the window was resized) and
484        // must be recreated:
485        demo_resize(demo);
486        demo_draw(demo);
487        vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
488        return;
489    } else if (err == VK_SUBOPTIMAL_KHR) {
490        // demo->swapchain is not as optimal as it could be, but the platform's
491        // presentation engine will still present the image correctly.
492    } else {
493        assert(!err);
494    }
495
496    // Assume the command buffer has been run on current_buffer before so
497    // we need to set the image layout back to COLOR_ATTACHMENT_OPTIMAL
498    demo_set_image_layout(demo, demo->buffers[demo->current_buffer].image,
499                           VK_IMAGE_ASPECT_COLOR_BIT,
500                           VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
501                           VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
502    demo_flush_init_cmd(demo);
503
504    // Wait for the present complete semaphore to be signaled to ensure
505    // that the image won't be rendered to until the presentation
506    // engine has fully released ownership to the application, and it is
507    // okay to render to the image.
508
509// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
510    demo_draw_build_cmd(demo);
511    VkFence nullFence = VK_NULL_HANDLE;
512
513    VkSubmitInfo submit_info = {
514        .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
515        .pNext = NULL,
516        .waitSemaphoreCount = 1,
517        .pWaitSemaphores = &presentCompleteSemaphore,
518        .commandBufferCount = 1,
519        .pCommandBuffers = &demo->draw_cmd,
520        .signalSemaphoreCount = 0,
521        .pSignalSemaphores = NULL
522    };
523
524    err = vkQueueSubmit(demo->queue, 1, &submit_info, nullFence);
525    assert(!err);
526
527    VkPresentInfoKHR present = {
528        .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
529        .pNext = NULL,
530        .swapchainCount = 1,
531        .pSwapchains = &demo->swapchain,
532        .pImageIndices = &demo->current_buffer,
533    };
534
535// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
536    err = demo->fpQueuePresentKHR(demo->queue, &present);
537    if (err == VK_ERROR_OUT_OF_DATE_KHR) {
538        // demo->swapchain is out of date (e.g. the window was resized) and
539        // must be recreated:
540        demo_resize(demo);
541    } else if (err == VK_SUBOPTIMAL_KHR) {
542        // demo->swapchain is not as optimal as it could be, but the platform's
543        // presentation engine will still present the image correctly.
544    } else {
545        assert(!err);
546    }
547
548    err = vkQueueWaitIdle(demo->queue);
549    assert(err == VK_SUCCESS);
550
551    vkDestroySemaphore(demo->device, presentCompleteSemaphore, NULL);
552}
553
554static void demo_prepare_buffers(struct demo *demo)
555{
556    VkResult U_ASSERT_ONLY err;
557    VkSwapchainKHR oldSwapchain = demo->swapchain;
558
559    // Check the surface capabilities and formats
560    VkSurfaceCapabilitiesKHR surfCapabilities;
561    err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(demo->gpu,
562        demo->surface,
563        &surfCapabilities);
564    assert(!err);
565
566    uint32_t presentModeCount;
567    err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(demo->gpu,
568        demo->surface,
569        &presentModeCount, NULL);
570    assert(!err);
571    VkPresentModeKHR *presentModes =
572        (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
573    assert(presentModes);
574    err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(demo->gpu,
575        demo->surface,
576        &presentModeCount, presentModes);
577    assert(!err);
578
579    VkExtent2D swapchainExtent;
580    // width and height are either both -1, or both not -1.
581    if (surfCapabilities.currentExtent.width == -1)
582    {
583        // If the surface size is undefined, the size is set to
584        // the size of the images requested.
585        swapchainExtent.width = demo->width;
586        swapchainExtent.height = demo->height;
587    }
588    else
589    {
590        // If the surface size is defined, the swap chain size must match
591        swapchainExtent = surfCapabilities.currentExtent;
592        demo->width = surfCapabilities.currentExtent.width;
593        demo->height = surfCapabilities.currentExtent.height;
594    }
595
596    VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
597
598    // Determine the number of VkImage's to use in the swap chain (we desire to
599    // own only 1 image at a time, besides the images being displayed and
600    // queued for display):
601    uint32_t desiredNumberOfSwapchainImages = surfCapabilities.minImageCount + 1;
602    if ((surfCapabilities.maxImageCount > 0) &&
603        (desiredNumberOfSwapchainImages > surfCapabilities.maxImageCount))
604    {
605        // Application must settle for fewer images than desired:
606        desiredNumberOfSwapchainImages = surfCapabilities.maxImageCount;
607    }
608
609    VkSurfaceTransformFlagsKHR preTransform;
610    if (surfCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_KHR) {
611        preTransform = VK_SURFACE_TRANSFORM_NONE_BIT_KHR;
612    } else {
613        preTransform = surfCapabilities.currentTransform;
614    }
615
616    const VkSwapchainCreateInfoKHR swapchain = {
617        .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
618        .pNext = NULL,
619        .surface = demo->surface,
620        .minImageCount = desiredNumberOfSwapchainImages,
621        .imageFormat = demo->format,
622        .imageColorSpace = demo->color_space,
623        .imageExtent = {
624            .width = swapchainExtent.width,
625            .height = swapchainExtent.height,
626        },
627        .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
628        .preTransform = preTransform,
629        .imageArrayLayers = 1,
630        .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
631        .queueFamilyIndexCount = 0,
632        .pQueueFamilyIndices = NULL,
633        .presentMode = swapchainPresentMode,
634        .oldSwapchain = oldSwapchain,
635        .clipped = true,
636    };
637    uint32_t i;
638
639    err = demo->fpCreateSwapchainKHR(demo->device, &swapchain, NULL, &demo->swapchain);
640    assert(!err);
641
642    // If we just re-created an existing swapchain, we should destroy the old
643    // swapchain at this point.
644    // Note: destroying the swapchain also cleans up all its associated
645    // presentable images once the platform is done with them.
646    if (oldSwapchain != VK_NULL_HANDLE) {
647        demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
648    }
649
650    err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
651                                        &demo->swapchainImageCount, NULL);
652    assert(!err);
653
654    VkImage* swapchainImages =
655        (VkImage*)malloc(demo->swapchainImageCount * sizeof(VkImage));
656    assert(swapchainImages);
657    err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
658                                        &demo->swapchainImageCount,
659                                        swapchainImages);
660    assert(!err);
661
662    demo->buffers = (SwapchainBuffers*)malloc(sizeof(SwapchainBuffers)*demo->swapchainImageCount);
663    assert(demo->buffers);
664
665    for (i = 0; i < demo->swapchainImageCount; i++) {
666        VkImageViewCreateInfo color_attachment_view = {
667            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
668            .pNext = NULL,
669            .format = demo->format,
670            .components = {
671                .r = VK_COMPONENT_SWIZZLE_R,
672                .g = VK_COMPONENT_SWIZZLE_G,
673                .b = VK_COMPONENT_SWIZZLE_B,
674                .a = VK_COMPONENT_SWIZZLE_A,
675            },
676            .subresourceRange = {
677                .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
678                .baseMipLevel = 0,
679                .levelCount = 1,
680                .baseArrayLayer = 0,
681                .layerCount = 1
682            },
683            .viewType = VK_IMAGE_VIEW_TYPE_2D,
684            .flags = 0,
685        };
686
687        demo->buffers[i].image = swapchainImages[i];
688
689        // Render loop will expect image to have been used before and in VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
690        // layout and will change to COLOR_ATTACHMENT_OPTIMAL, so init the image to that state
691        demo_set_image_layout(demo, demo->buffers[i].image,
692                               VK_IMAGE_ASPECT_COLOR_BIT,
693                               VK_IMAGE_LAYOUT_UNDEFINED,
694                               VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
695
696        color_attachment_view.image = demo->buffers[i].image;
697
698        err = vkCreateImageView(demo->device,
699                &color_attachment_view, NULL, &demo->buffers[i].view);
700        assert(!err);
701    }
702
703    demo->current_buffer = 0;
704}
705
706static void demo_prepare_depth(struct demo *demo)
707{
708    const VkFormat depth_format = VK_FORMAT_D16_UNORM;
709    const VkImageCreateInfo image = {
710        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
711        .pNext = NULL,
712        .imageType = VK_IMAGE_TYPE_2D,
713        .format = depth_format,
714        .extent = { demo->width, demo->height, 1 },
715        .mipLevels = 1,
716        .arrayLayers = 1,
717        .samples = VK_SAMPLE_COUNT_1_BIT,
718        .tiling = VK_IMAGE_TILING_OPTIMAL,
719        .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
720        .flags = 0,
721    };
722    VkMemoryAllocateInfo mem_alloc = {
723        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
724        .pNext = NULL,
725        .allocationSize = 0,
726        .memoryTypeIndex = 0,
727    };
728    VkImageViewCreateInfo view = {
729        .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
730        .pNext = NULL,
731        .image = VK_NULL_HANDLE,
732        .format = depth_format,
733        .subresourceRange = {
734            .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
735            .baseMipLevel = 0,
736            .levelCount = 1,
737            .baseArrayLayer = 0,
738            .layerCount = 1
739        },
740        .flags = 0,
741        .viewType = VK_IMAGE_VIEW_TYPE_2D,
742    };
743
744    VkMemoryRequirements mem_reqs;
745    VkResult U_ASSERT_ONLY err;
746    bool U_ASSERT_ONLY pass;
747
748    demo->depth.format = depth_format;
749
750    /* create image */
751    err = vkCreateImage(demo->device, &image, NULL,
752            &demo->depth.image);
753    assert(!err);
754
755    /* get memory requirements for this object */
756    vkGetImageMemoryRequirements(demo->device, demo->depth.image,
757                                       &mem_reqs);
758
759    /* select memory size and type */
760    mem_alloc.allocationSize = mem_reqs.size;
761    pass = memory_type_from_properties(demo,
762                                      mem_reqs.memoryTypeBits,
763                                      0, /* No requirements */
764                                      &mem_alloc.memoryTypeIndex);
765    assert(pass);
766
767    /* allocate memory */
768    err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->depth.mem);
769    assert(!err);
770
771    /* bind memory */
772    err = vkBindImageMemory(demo->device, demo->depth.image,
773                            demo->depth.mem, 0);
774    assert(!err);
775
776    demo_set_image_layout(demo, demo->depth.image,
777                           VK_IMAGE_ASPECT_DEPTH_BIT,
778                           VK_IMAGE_LAYOUT_UNDEFINED,
779                           VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
780
781    /* create image view */
782    view.image = demo->depth.image;
783    err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
784    assert(!err);
785}
786
787static void demo_prepare_texture_image(struct demo *demo,
788                                       const uint32_t *tex_colors,
789                                       struct texture_object *tex_obj,
790                                       VkImageTiling tiling,
791                                       VkImageUsageFlags usage,
792                                       VkFlags required_props)
793{
794    const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
795    const int32_t tex_width = 2;
796    const int32_t tex_height = 2;
797    VkResult U_ASSERT_ONLY err;
798    bool U_ASSERT_ONLY pass;
799
800    tex_obj->tex_width = tex_width;
801    tex_obj->tex_height = tex_height;
802
803    const VkImageCreateInfo image_create_info = {
804        .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
805        .pNext = NULL,
806        .imageType = VK_IMAGE_TYPE_2D,
807        .format = tex_format,
808        .extent = { tex_width, tex_height, 1 },
809        .mipLevels = 1,
810        .arrayLayers = 1,
811        .samples = VK_SAMPLE_COUNT_1_BIT,
812        .tiling = tiling,
813        .usage = usage,
814        .flags = 0,
815    };
816    VkMemoryAllocateInfo mem_alloc = {
817        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
818        .pNext = NULL,
819        .allocationSize = 0,
820        .memoryTypeIndex = 0,
821    };
822
823    VkMemoryRequirements mem_reqs;
824
825    err = vkCreateImage(demo->device, &image_create_info, NULL,
826            &tex_obj->image);
827    assert(!err);
828
829    vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
830
831    mem_alloc.allocationSize  = mem_reqs.size;
832    pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits, required_props, &mem_alloc.memoryTypeIndex);
833    assert(pass);
834
835    /* allocate memory */
836    err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &tex_obj->mem);
837    assert(!err);
838
839    /* bind memory */
840    err = vkBindImageMemory(demo->device, tex_obj->image,
841            tex_obj->mem, 0);
842    assert(!err);
843
844    if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
845        const VkImageSubresource subres = {
846            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
847            .mipLevel = 0,
848            .arrayLayer = 0,
849        };
850        VkSubresourceLayout layout;
851        void *data;
852        int32_t x, y;
853
854        vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres, &layout);
855
856        err = vkMapMemory(demo->device, tex_obj->mem, 0, mem_alloc.allocationSize, 0, &data);
857        assert(!err);
858
859        for (y = 0; y < tex_height; y++) {
860            uint32_t *row = (uint32_t *) ((char *) data + layout.rowPitch * y);
861            for (x = 0; x < tex_width; x++)
862                row[x] = tex_colors[(x & 1) ^ (y & 1)];
863        }
864
865        vkUnmapMemory(demo->device, tex_obj->mem);
866    }
867
868    tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
869    demo_set_image_layout(demo, tex_obj->image,
870                           VK_IMAGE_ASPECT_COLOR_BIT,
871                           VK_IMAGE_LAYOUT_UNDEFINED,
872                           tex_obj->imageLayout);
873    /* setting the image layout does not reference the actual memory so no need to add a mem ref */
874}
875
876static void demo_destroy_texture_image(struct demo *demo, struct texture_object *tex_obj)
877{
878    /* clean up staging resources */
879    vkDestroyImage(demo->device, tex_obj->image, NULL);
880    vkFreeMemory(demo->device, tex_obj->mem, NULL);
881}
882
883static void demo_prepare_textures(struct demo *demo)
884{
885    const VkFormat tex_format = VK_FORMAT_B8G8R8A8_UNORM;
886    VkFormatProperties props;
887    const uint32_t tex_colors[DEMO_TEXTURE_COUNT][2] = {
888        { 0xffff0000, 0xff00ff00 },
889    };
890    uint32_t i;
891    VkResult err;
892
893    vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
894
895    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
896        if ((props.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) && !demo->use_staging_buffer) {
897            /* Device can texture using linear textures */
898            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
899                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
900        } else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT){
901            /* Must use staging buffer to copy linear texture to optimized */
902            struct texture_object staging_texture;
903
904            memset(&staging_texture, 0, sizeof(staging_texture));
905            demo_prepare_texture_image(demo, tex_colors[i], &staging_texture,
906                                       VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
907
908            demo_prepare_texture_image(demo, tex_colors[i], &demo->textures[i],
909                                       VK_IMAGE_TILING_OPTIMAL,
910                                       (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
911                                       VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
912
913            demo_set_image_layout(demo, staging_texture.image,
914                                   VK_IMAGE_ASPECT_COLOR_BIT,
915                                   staging_texture.imageLayout,
916                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
917
918            demo_set_image_layout(demo, demo->textures[i].image,
919                                   VK_IMAGE_ASPECT_COLOR_BIT,
920                                   demo->textures[i].imageLayout,
921                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
922
923            VkImageCopy copy_region = {
924                .srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
925                .srcOffset = { 0, 0, 0 },
926                .dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 },
927                .dstOffset = { 0, 0, 0 },
928                .extent = { staging_texture.tex_width, staging_texture.tex_height, 1 },
929            };
930            vkCmdCopyImage(demo->setup_cmd,
931                            staging_texture.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
932                            demo->textures[i].image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
933                            1, &copy_region);
934
935            demo_set_image_layout(demo, demo->textures[i].image,
936                                   VK_IMAGE_ASPECT_COLOR_BIT,
937                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
938                                   demo->textures[i].imageLayout);
939
940            demo_flush_init_cmd(demo);
941
942            demo_destroy_texture_image(demo, &staging_texture);
943        } else {
944            /* Can't support VK_FORMAT_B8G8R8A8_UNORM !? */
945            assert(!"No support for B8G8R8A8_UNORM as texture image format");
946        }
947
948        const VkSamplerCreateInfo sampler = {
949            .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
950            .pNext = NULL,
951            .magFilter = VK_FILTER_NEAREST,
952            .minFilter = VK_FILTER_NEAREST,
953            .mipmapMode = VK_SAMPLER_MIPMAP_MODE_BASE,
954            .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
955            .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
956            .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
957            .mipLodBias = 0.0f,
958            .anisotropyEnable = VK_FALSE,
959            .maxAnisotropy = 1,
960            .compareOp = VK_COMPARE_OP_NEVER,
961            .minLod = 0.0f,
962            .maxLod = 0.0f,
963            .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
964            .unnormalizedCoordinates = VK_FALSE,
965        };
966        VkImageViewCreateInfo view = {
967            .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
968            .pNext = NULL,
969            .image = VK_NULL_HANDLE,
970            .viewType = VK_IMAGE_VIEW_TYPE_2D,
971            .format = tex_format,
972            .components = { VK_COMPONENT_SWIZZLE_R,
973                          VK_COMPONENT_SWIZZLE_G,
974                          VK_COMPONENT_SWIZZLE_B,
975                          VK_COMPONENT_SWIZZLE_A, },
976            .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 },
977            .flags = 0,
978        };
979
980        /* create sampler */
981        err = vkCreateSampler(demo->device, &sampler, NULL,
982                &demo->textures[i].sampler);
983        assert(!err);
984
985        /* create image view */
986        view.image = demo->textures[i].image;
987        err = vkCreateImageView(demo->device, &view, NULL,
988                                 &demo->textures[i].view);
989        assert(!err);
990    }
991}
992
993static void demo_prepare_vertices(struct demo *demo)
994{
995    const float vb[3][5] = {
996        /*      position             texcoord */
997        { -1.0f, -1.0f,  0.25f,     0.0f, 0.0f },
998        {  1.0f, -1.0f,  0.25f,     1.0f, 0.0f },
999        {  0.0f,  1.0f,  1.0f,      0.5f, 1.0f },
1000    };
1001    const VkBufferCreateInfo buf_info = {
1002        .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1003        .pNext = NULL,
1004        .size = sizeof(vb),
1005        .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
1006        .flags = 0,
1007    };
1008    VkMemoryAllocateInfo mem_alloc = {
1009        .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1010        .pNext = NULL,
1011        .allocationSize = 0,
1012        .memoryTypeIndex = 0,
1013    };
1014    VkMemoryRequirements mem_reqs;
1015    VkResult U_ASSERT_ONLY err;
1016    bool U_ASSERT_ONLY pass;
1017    void *data;
1018
1019    memset(&demo->vertices, 0, sizeof(demo->vertices));
1020
1021    err = vkCreateBuffer(demo->device, &buf_info, NULL, &demo->vertices.buf);
1022    assert(!err);
1023
1024    vkGetBufferMemoryRequirements(demo->device,
1025            demo->vertices.buf, &mem_reqs);
1026    assert(!err);
1027
1028    mem_alloc.allocationSize  = mem_reqs.size;
1029    pass = memory_type_from_properties(demo,
1030                                      mem_reqs.memoryTypeBits,
1031                                      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
1032                                      &mem_alloc.memoryTypeIndex);
1033    assert(pass);
1034
1035    err = vkAllocateMemory(demo->device, &mem_alloc, NULL, &demo->vertices.mem);
1036    assert(!err);
1037
1038    err = vkMapMemory(demo->device, demo->vertices.mem, 0, mem_alloc.allocationSize, 0, &data);
1039    assert(!err);
1040
1041    memcpy(data, vb, sizeof(vb));
1042
1043    vkUnmapMemory(demo->device, demo->vertices.mem);
1044
1045    err = vkBindBufferMemory(demo->device, demo->vertices.buf,
1046            demo->vertices.mem, 0);
1047    assert(!err);
1048
1049    demo->vertices.vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1050    demo->vertices.vi.pNext = NULL;
1051    demo->vertices.vi.vertexBindingDescriptionCount = 1;
1052    demo->vertices.vi.pVertexBindingDescriptions = demo->vertices.vi_bindings;
1053    demo->vertices.vi.vertexAttributeDescriptionCount = 2;
1054    demo->vertices.vi.pVertexAttributeDescriptions = demo->vertices.vi_attrs;
1055
1056    demo->vertices.vi_bindings[0].binding = VERTEX_BUFFER_BIND_ID;
1057    demo->vertices.vi_bindings[0].stride = sizeof(vb[0]);
1058    demo->vertices.vi_bindings[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1059
1060    demo->vertices.vi_attrs[0].binding = VERTEX_BUFFER_BIND_ID;
1061    demo->vertices.vi_attrs[0].location = 0;
1062    demo->vertices.vi_attrs[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1063    demo->vertices.vi_attrs[0].offset = 0;
1064
1065    demo->vertices.vi_attrs[1].binding = VERTEX_BUFFER_BIND_ID;
1066    demo->vertices.vi_attrs[1].location = 1;
1067    demo->vertices.vi_attrs[1].format = VK_FORMAT_R32G32_SFLOAT;
1068    demo->vertices.vi_attrs[1].offset = sizeof(float) * 3;
1069}
1070
1071static void demo_prepare_descriptor_layout(struct demo *demo)
1072{
1073    const VkDescriptorSetLayoutBinding layout_binding = {
1074        .binding = 0,
1075        .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1076        .descriptorCount = DEMO_TEXTURE_COUNT,
1077        .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1078        .pImmutableSamplers = NULL,
1079    };
1080    const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
1081        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1082        .pNext = NULL,
1083        .bindingCount = 1,
1084        .pBinding = &layout_binding,
1085    };
1086    VkResult U_ASSERT_ONLY err;
1087
1088    err = vkCreateDescriptorSetLayout(demo->device,
1089            &descriptor_layout, NULL, &demo->desc_layout);
1090    assert(!err);
1091
1092    const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
1093        .sType              = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1094        .pNext              = NULL,
1095        .setLayoutCount = 1,
1096        .pSetLayouts        = &demo->desc_layout,
1097    };
1098
1099    err = vkCreatePipelineLayout(demo->device,
1100                                 &pPipelineLayoutCreateInfo,
1101                                 NULL,
1102                                 &demo->pipeline_layout);
1103    assert(!err);
1104}
1105
1106static void demo_prepare_render_pass(struct demo *demo)
1107{
1108    const VkAttachmentDescription attachments[2] = {
1109        [0] = {
1110            .format = demo->format,
1111            .samples = VK_SAMPLE_COUNT_1_BIT,
1112            .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1113            .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1114            .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1115            .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1116            .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1117            .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1118        },
1119        [1] = {
1120            .format = demo->depth.format,
1121            .samples = VK_SAMPLE_COUNT_1_BIT,
1122            .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1123            .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1124            .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1125            .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1126            .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1127            .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1128        },
1129    };
1130    const VkAttachmentReference color_reference = {
1131        .attachment = 0,
1132        .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1133    };
1134    const VkAttachmentReference depth_reference = {
1135        .attachment = 1,
1136        .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1137    };
1138    const VkSubpassDescription subpass = {
1139        .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1140        .flags = 0,
1141        .inputAttachmentCount = 0,
1142        .pInputAttachments = NULL,
1143        .colorAttachmentCount = 1,
1144        .pColorAttachments = &color_reference,
1145        .pResolveAttachments = NULL,
1146        .pDepthStencilAttachment = &depth_reference,
1147        .preserveAttachmentCount = 0,
1148        .pPreserveAttachments = NULL,
1149    };
1150    const VkRenderPassCreateInfo rp_info = {
1151        .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1152        .pNext = NULL,
1153        .attachmentCount = 2,
1154        .pAttachments = attachments,
1155        .subpassCount = 1,
1156        .pSubpasses = &subpass,
1157        .dependencyCount = 0,
1158        .pDependencies = NULL,
1159    };
1160    VkResult U_ASSERT_ONLY err;
1161
1162    err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
1163    assert(!err);
1164}
1165
1166static VkShaderModule demo_prepare_shader_module(struct demo *demo,
1167                                                 const void *code,
1168                                                 size_t size)
1169{
1170    VkShaderModuleCreateInfo moduleCreateInfo;
1171    VkShaderModule module;
1172    VkResult U_ASSERT_ONLY err;
1173
1174    moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1175    moduleCreateInfo.pNext = NULL;
1176
1177    moduleCreateInfo.codeSize = size;
1178    moduleCreateInfo.pCode = code;
1179    moduleCreateInfo.flags = 0;
1180    err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
1181    assert(!err);
1182
1183    return module;
1184}
1185
1186char *demo_read_spv(const char *filename, size_t *psize)
1187{
1188    long int size;
1189    void *shader_code;
1190    size_t retVal;
1191
1192    FILE *fp = fopen(filename, "rb");
1193    if (!fp) return NULL;
1194
1195    fseek(fp, 0L, SEEK_END);
1196    size = ftell(fp);
1197
1198    fseek(fp, 0L, SEEK_SET);
1199
1200    shader_code = malloc(size);
1201    retVal = fread(shader_code, size, 1, fp);
1202    if (!retVal) return NULL;
1203
1204    *psize = size;
1205
1206    fclose(fp);
1207    return shader_code;
1208}
1209
1210static VkShaderModule demo_prepare_vs(struct demo *demo)
1211{
1212    void *vertShaderCode;
1213    size_t size;
1214
1215    vertShaderCode = demo_read_spv("tri-vert.spv", &size);
1216
1217    demo->vert_shader_module = demo_prepare_shader_module(demo, vertShaderCode, size);
1218
1219    free(vertShaderCode);
1220
1221    return demo->vert_shader_module;
1222}
1223
1224static VkShaderModule demo_prepare_fs(struct demo *demo)
1225{
1226    void *fragShaderCode;
1227    size_t size;
1228
1229    fragShaderCode = demo_read_spv("tri-frag.spv", &size);
1230
1231    demo->frag_shader_module = demo_prepare_shader_module(demo, fragShaderCode, size);
1232
1233    free(fragShaderCode);
1234
1235    return demo->frag_shader_module;
1236}
1237
1238static void demo_prepare_pipeline(struct demo *demo)
1239{
1240    VkGraphicsPipelineCreateInfo pipeline;
1241    VkPipelineCacheCreateInfo pipelineCache;
1242
1243    VkPipelineVertexInputStateCreateInfo   vi;
1244    VkPipelineInputAssemblyStateCreateInfo ia;
1245    VkPipelineRasterizationStateCreateInfo        rs;
1246    VkPipelineColorBlendStateCreateInfo    cb;
1247    VkPipelineDepthStencilStateCreateInfo  ds;
1248    VkPipelineViewportStateCreateInfo      vp;
1249    VkPipelineMultisampleStateCreateInfo   ms;
1250    VkDynamicState                         dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
1251    VkPipelineDynamicStateCreateInfo       dynamicState;
1252
1253    VkResult U_ASSERT_ONLY err;
1254
1255    memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
1256    memset(&dynamicState, 0, sizeof dynamicState);
1257    dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1258    dynamicState.pDynamicStates = dynamicStateEnables;
1259
1260    memset(&pipeline, 0, sizeof(pipeline));
1261    pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1262    pipeline.layout = demo->pipeline_layout;
1263
1264    vi = demo->vertices.vi;
1265
1266    memset(&ia, 0, sizeof(ia));
1267    ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1268    ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1269
1270    memset(&rs, 0, sizeof(rs));
1271    rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1272    rs.polygonMode = VK_POLYGON_MODE_FILL;
1273    rs.cullMode = VK_CULL_MODE_BACK_BIT;
1274    rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
1275    rs.depthClampEnable = VK_FALSE;
1276    rs.rasterizerDiscardEnable = VK_FALSE;
1277    rs.depthBiasEnable = VK_FALSE;
1278
1279    memset(&cb, 0, sizeof(cb));
1280    cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1281    VkPipelineColorBlendAttachmentState att_state[1];
1282    memset(att_state, 0, sizeof(att_state));
1283    att_state[0].colorWriteMask = 0xf;
1284    att_state[0].blendEnable = VK_FALSE;
1285    cb.attachmentCount = 1;
1286    cb.pAttachments = att_state;
1287
1288    memset(&vp, 0, sizeof(vp));
1289    vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1290    vp.viewportCount = 1;
1291    dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
1292    vp.scissorCount = 1;
1293    dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
1294
1295    memset(&ds, 0, sizeof(ds));
1296    ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1297    ds.depthTestEnable = VK_TRUE;
1298    ds.depthWriteEnable = VK_TRUE;
1299    ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
1300    ds.depthBoundsTestEnable = VK_FALSE;
1301    ds.back.failOp = VK_STENCIL_OP_KEEP;
1302    ds.back.passOp = VK_STENCIL_OP_KEEP;
1303    ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
1304    ds.stencilTestEnable = VK_FALSE;
1305    ds.front = ds.back;
1306
1307    memset(&ms, 0, sizeof(ms));
1308    ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1309    ms.pSampleMask = NULL;
1310    ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1311
1312    // Two stages: vs and fs
1313    pipeline.stageCount = 2;
1314    VkPipelineShaderStageCreateInfo shaderStages[2];
1315    memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
1316
1317    shaderStages[0].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1318    shaderStages[0].stage  = VK_SHADER_STAGE_VERTEX_BIT;
1319    shaderStages[0].module = demo_prepare_vs(demo);
1320    shaderStages[0].pName  = "main";
1321
1322    shaderStages[1].sType  = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1323    shaderStages[1].stage  = VK_SHADER_STAGE_FRAGMENT_BIT;
1324    shaderStages[1].module = demo_prepare_fs(demo);
1325    shaderStages[1].pName  = "main";
1326
1327    pipeline.pVertexInputState   = &vi;
1328    pipeline.pInputAssemblyState = &ia;
1329    pipeline.pRasterizationState        = &rs;
1330    pipeline.pColorBlendState    = &cb;
1331    pipeline.pMultisampleState   = &ms;
1332    pipeline.pViewportState      = &vp;
1333    pipeline.pDepthStencilState  = &ds;
1334    pipeline.pStages             = shaderStages;
1335    pipeline.renderPass          = demo->render_pass;
1336    pipeline.pDynamicState       = &dynamicState;
1337
1338    memset(&pipelineCache, 0, sizeof(pipelineCache));
1339    pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
1340
1341    err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL, &demo->pipelineCache);
1342    assert(!err);
1343    err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache,
1344            1, &pipeline, NULL, &demo->pipeline);
1345    assert(!err);
1346
1347    vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
1348
1349    vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
1350    vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
1351}
1352
1353static void demo_prepare_descriptor_pool(struct demo *demo)
1354{
1355    const VkDescriptorPoolSize type_count = {
1356        .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1357        .descriptorCount = DEMO_TEXTURE_COUNT,
1358    };
1359    const VkDescriptorPoolCreateInfo descriptor_pool = {
1360        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1361        .pNext = NULL,
1362        .maxSets = 1,
1363        .poolSizeCount = 1,
1364        .pPoolSizes = &type_count,
1365    };
1366    VkResult U_ASSERT_ONLY err;
1367
1368    err = vkCreateDescriptorPool(demo->device,
1369            &descriptor_pool, NULL, &demo->desc_pool);
1370    assert(!err);
1371}
1372
1373static void demo_prepare_descriptor_set(struct demo *demo)
1374{
1375    VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
1376    VkWriteDescriptorSet write;
1377    VkResult U_ASSERT_ONLY err;
1378    uint32_t i;
1379
1380    VkDescriptorSetAllocateInfo alloc_info = {
1381        .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1382        .pNext = NULL,
1383        .descriptorPool = demo->desc_pool,
1384        .setLayoutCount = 1,
1385        .pSetLayouts = &demo->desc_layout
1386    };
1387    err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
1388    assert(!err);
1389
1390    memset(&tex_descs, 0, sizeof(tex_descs));
1391    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1392        tex_descs[i].sampler = demo->textures[i].sampler;
1393        tex_descs[i].imageView = demo->textures[i].view;
1394        tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1395    }
1396
1397    memset(&write, 0, sizeof(write));
1398    write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1399    write.dstSet = demo->desc_set;
1400    write.descriptorCount = DEMO_TEXTURE_COUNT;
1401    write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1402    write.pImageInfo = tex_descs;
1403
1404    vkUpdateDescriptorSets(demo->device, 1, &write, 0, NULL);
1405}
1406
1407static void demo_prepare_framebuffers(struct demo *demo)
1408{
1409    VkImageView attachments[2];
1410    attachments[1] = demo->depth.view;
1411
1412    const VkFramebufferCreateInfo fb_info = {
1413         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1414         .pNext = NULL,
1415         .renderPass = demo->render_pass,
1416         .attachmentCount = 2,
1417         .pAttachments = attachments,
1418         .width  = demo->width,
1419         .height = demo->height,
1420         .layers = 1,
1421    };
1422    VkResult U_ASSERT_ONLY err;
1423    uint32_t i;
1424
1425    demo->framebuffers = (VkFramebuffer *) malloc(demo->swapchainImageCount * sizeof(VkFramebuffer));
1426    assert(demo->framebuffers);
1427
1428    for (i = 0; i < demo->swapchainImageCount; i++) {
1429        attachments[0]= demo->buffers[i].view;
1430        err = vkCreateFramebuffer(demo->device, &fb_info, NULL, &demo->framebuffers[i]);
1431        assert(!err);
1432    }
1433}
1434
1435static void demo_prepare(struct demo *demo)
1436{
1437    VkResult U_ASSERT_ONLY err;
1438
1439    const VkCommandPoolCreateInfo cmd_pool_info = {
1440        .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1441        .pNext = NULL,
1442        .queueFamilyIndex = demo->graphics_queue_node_index,
1443        .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1444    };
1445    err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL, &demo->cmd_pool);
1446    assert(!err);
1447
1448    const VkCommandBufferAllocateInfo cmd = {
1449        .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1450        .pNext = NULL,
1451        .commandPool = demo->cmd_pool,
1452        .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1453        .bufferCount = 1,
1454    };
1455    err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->draw_cmd);
1456    assert(!err);
1457
1458    demo_prepare_buffers(demo);
1459    demo_prepare_depth(demo);
1460    demo_prepare_textures(demo);
1461    demo_prepare_vertices(demo);
1462    demo_prepare_descriptor_layout(demo);
1463    demo_prepare_render_pass(demo);
1464    demo_prepare_pipeline(demo);
1465
1466    demo_prepare_descriptor_pool(demo);
1467    demo_prepare_descriptor_set(demo);
1468
1469    demo_prepare_framebuffers(demo);
1470
1471    demo->prepared = true;
1472}
1473
1474#ifdef _WIN32
1475static void demo_run(struct demo *demo)
1476{
1477    if (!demo->prepared)
1478        return;
1479    demo_draw(demo);
1480
1481    if (demo->depthStencil > 0.99f)
1482        demo->depthIncrement = -0.001f;
1483    if (demo->depthStencil < 0.8f)
1484        demo->depthIncrement = 0.001f;
1485
1486    demo->depthStencil += demo->depthIncrement;
1487}
1488
1489// On MS-Windows, make this a global, so it's available to WndProc()
1490struct demo demo;
1491
1492// MS-Windows event handling function:
1493LRESULT CALLBACK WndProc(HWND hWnd,
1494                         UINT uMsg,
1495                         WPARAM wParam,
1496                         LPARAM lParam)
1497{
1498    char tmp_str[] = APP_LONG_NAME;
1499
1500    switch(uMsg)
1501    {
1502    case WM_CREATE:
1503        return 0;
1504    case WM_CLOSE:
1505        PostQuitMessage(0);
1506        return 0;
1507    case WM_PAINT:
1508        if (demo.prepared) {
1509            demo_run(&demo);
1510            break;
1511        }
1512    case WM_SIZE:
1513        demo.width = lParam & 0xffff;
1514        demo.height = lParam & 0xffff0000 >> 16;
1515        demo_resize(&demo);
1516        break;
1517    default:
1518        break;
1519    }
1520    return (DefWindowProc(hWnd, uMsg, wParam, lParam));
1521}
1522
1523static void demo_create_window(struct demo *demo)
1524{
1525    WNDCLASSEX  win_class;
1526
1527    // Initialize the window class structure:
1528    win_class.cbSize = sizeof(WNDCLASSEX);
1529    win_class.style = CS_HREDRAW | CS_VREDRAW;
1530    win_class.lpfnWndProc = WndProc;
1531    win_class.cbClsExtra = 0;
1532    win_class.cbWndExtra = 0;
1533    win_class.hInstance = demo->connection; // hInstance
1534    win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1535    win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1536    win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1537    win_class.lpszMenuName = NULL;
1538    win_class.lpszClassName = demo->name;
1539    win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
1540    // Register window class:
1541    if (!RegisterClassEx(&win_class)) {
1542        // It didn't work, so try to give a useful error:
1543        printf("Unexpected error trying to start the application!\n");
1544        fflush(stdout);
1545        exit(1);
1546    }
1547    // Create window with the registered class:
1548    RECT wr = { 0, 0, demo->width, demo->height };
1549    AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
1550    demo->window = CreateWindowEx(0,
1551                                  demo->name,           // class name
1552                                  demo->name,           // app name
1553                                  WS_OVERLAPPEDWINDOW | // window style
1554                                  WS_VISIBLE |
1555                                  WS_SYSMENU,
1556                                  100,100,              // x/y coords
1557                                  wr.right-wr.left,     // width
1558                                  wr.bottom-wr.top,     // height
1559                                  NULL,                 // handle to parent
1560                                  NULL,                 // handle to menu
1561                                  demo->connection,     // hInstance
1562                                  NULL);                // no extra parameters
1563    if (!demo->window) {
1564        // It didn't work, so try to give a useful error:
1565        printf("Cannot create a window in which to draw!\n");
1566        fflush(stdout);
1567        exit(1);
1568    }
1569}
1570#else  // _WIN32
1571
1572static void demo_handle_event(struct demo *demo,
1573                              const xcb_generic_event_t *event)
1574{
1575    switch (event->response_type & 0x7f) {
1576    case XCB_EXPOSE:
1577        demo_draw(demo);
1578        break;
1579    case XCB_CLIENT_MESSAGE:
1580        if((*(xcb_client_message_event_t*)event).data.data32[0] ==
1581           (*demo->atom_wm_delete_window).atom) {
1582            demo->quit = true;
1583        }
1584        break;
1585    case XCB_KEY_RELEASE:
1586        {
1587            const xcb_key_release_event_t *key =
1588                (const xcb_key_release_event_t *) event;
1589
1590            if (key->detail == 0x9)
1591                demo->quit = true;
1592        }
1593        break;
1594    case XCB_DESTROY_NOTIFY:
1595        demo->quit = true;
1596        break;
1597    case XCB_CONFIGURE_NOTIFY:
1598        {
1599            const xcb_configure_notify_event_t *cfg =
1600                (const xcb_configure_notify_event_t *) event;
1601            if ((demo->width != cfg->width) || (demo->height != cfg->height)) {
1602              demo_resize(demo);
1603            }
1604        }
1605        break;
1606    default:
1607        break;
1608    }
1609}
1610
1611static void demo_run(struct demo *demo)
1612{
1613    xcb_flush(demo->connection);
1614
1615    while (!demo->quit) {
1616        xcb_generic_event_t *event;
1617
1618        event = xcb_poll_for_event(demo->connection);
1619        if (event) {
1620            demo_handle_event(demo, event);
1621            free(event);
1622        }
1623
1624        demo_draw(demo);
1625
1626        if (demo->depthStencil > 0.99f)
1627            demo->depthIncrement = -0.001f;
1628        if (demo->depthStencil < 0.8f)
1629            demo->depthIncrement = 0.001f;
1630
1631        demo->depthStencil += demo->depthIncrement;
1632
1633        // Wait for work to finish before updating MVP.
1634        vkDeviceWaitIdle(demo->device);
1635    }
1636}
1637
1638static void demo_create_window(struct demo *demo)
1639{
1640    uint32_t value_mask, value_list[32];
1641
1642    demo->window = xcb_generate_id(demo->connection);
1643
1644    value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
1645    value_list[0] = demo->screen->black_pixel;
1646    value_list[1] = XCB_EVENT_MASK_KEY_RELEASE |
1647                    XCB_EVENT_MASK_EXPOSURE |
1648                    XCB_EVENT_MASK_STRUCTURE_NOTIFY;
1649
1650    xcb_create_window(demo->connection,
1651            XCB_COPY_FROM_PARENT,
1652            demo->window, demo->screen->root,
1653            0, 0, demo->width, demo->height, 0,
1654            XCB_WINDOW_CLASS_INPUT_OUTPUT,
1655            demo->screen->root_visual,
1656            value_mask, value_list);
1657
1658    /* Magic code that will send notification when window is destroyed */
1659    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(demo->connection, 1, 12,
1660                                                      "WM_PROTOCOLS");
1661    xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(demo->connection, cookie, 0);
1662
1663    xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
1664    demo->atom_wm_delete_window = xcb_intern_atom_reply(demo->connection, cookie2, 0);
1665
1666    xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE,
1667                        demo->window, (*reply).atom, 4, 32, 1,
1668                        &(*demo->atom_wm_delete_window).atom);
1669    free(reply);
1670
1671    xcb_map_window(demo->connection, demo->window);
1672}
1673#endif // _WIN32
1674
1675/*
1676 * Return 1 (true) if all layer names specified in check_names
1677 * can be found in given layer properties.
1678 */
1679static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1680                              uint32_t layer_count, VkLayerProperties *layers)
1681{
1682    for (uint32_t i = 0; i < check_count; i++) {
1683        VkBool32 found = 0;
1684        for (uint32_t j = 0; j < layer_count; j++) {
1685            if (!strcmp(check_names[i], layers[j].layerName)) {
1686                found = 1;
1687            }
1688        }
1689        if (!found) {
1690            fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1691            return 0;
1692        }
1693    }
1694    return 1;
1695}
1696VKAPI_ATTR void* VKAPI_CALL myrealloc(
1697    void*                                       pUserData,
1698    void*                                       pOriginal,
1699    size_t                                      size,
1700    size_t                                      alignment,
1701    VkSystemAllocationScope                     allocationScope)
1702{
1703    return realloc(pOriginal, size);
1704}
1705
1706VKAPI_ATTR void* VKAPI_CALL myalloc(
1707    void*                           pUserData,
1708    size_t                          size,
1709    size_t                          alignment,
1710    VkSystemAllocationScope              allocationScope)
1711{
1712    return malloc(size);
1713}
1714VKAPI_ATTR void VKAPI_CALL myfree(
1715    void*                           pUserData,
1716    void*                           pMemory)
1717{
1718    free(pMemory);
1719}
1720static void demo_init_vk(struct demo *demo)
1721{
1722    VkResult err;
1723    char *extension_names[64];
1724    char *layer_names[64];
1725    VkExtensionProperties *instance_extensions;
1726    VkPhysicalDevice *physical_devices;
1727    VkLayerProperties *instance_layers;
1728    VkLayerProperties *device_layers;
1729    uint32_t instance_extension_count = 0;
1730    uint32_t instance_layer_count = 0;
1731    uint32_t enabled_extension_count = 0;
1732    uint32_t enabled_layer_count = 0;
1733
1734    char *instance_validation_layers[] = {
1735        "MemTracker",
1736    };
1737
1738    char *device_validation_layers[] = {
1739        "MemTracker",
1740    };
1741
1742    /* Look for validation layers */
1743    VkBool32 validation_found = 0;
1744    err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1745    assert(!err);
1746
1747    instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count);
1748    err = vkEnumerateInstanceLayerProperties(&instance_layer_count, instance_layers);
1749    assert(!err);
1750
1751    if (demo->validate) {
1752        validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers,
1753                                             instance_layer_count, instance_layers);
1754        if (!validation_found) {
1755            ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1756                     "required validation layer.\n\n"
1757                     "Please look at the Getting Started guide for additional "
1758                     "information.\n",
1759                     "vkCreateInstance Failure");
1760        }
1761        enabled_layer_count = ARRAY_SIZE(instance_validation_layers);
1762    }
1763
1764    err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, NULL);
1765    assert(!err);
1766
1767    VkBool32 surfaceExtFound = 0;
1768    VkBool32 platformSurfaceExtFound = 0;
1769    memset(extension_names, 0, sizeof(extension_names));
1770    instance_extensions = malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1771    err = vkEnumerateInstanceExtensionProperties(NULL, &instance_extension_count, instance_extensions);
1772    assert(!err);
1773    for (uint32_t i = 0; i < instance_extension_count; i++) {
1774        if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
1775            surfaceExtFound = 1;
1776            extension_names[enabled_extension_count++] = VK_KHR_SURFACE_EXTENSION_NAME;
1777        }
1778#ifdef _WIN32
1779        if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
1780            platformSurfaceExtFound = 1;
1781            extension_names[enabled_extension_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1782        }
1783#else  // _WIN32
1784        if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
1785            platformSurfaceExtFound = 1;
1786            extension_names[enabled_extension_count++] = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
1787        }
1788#endif // _WIN32
1789        if (!strcmp(VK_EXT_LUNARG_DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extensionName)) {
1790            if (demo->validate) {
1791                extension_names[enabled_extension_count++] = VK_EXT_LUNARG_DEBUG_REPORT_EXTENSION_NAME;
1792            }
1793        }
1794        assert(enabled_extension_count < 64);
1795    }
1796    if (!surfaceExtFound) {
1797        ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the "
1798                 VK_KHR_SURFACE_EXTENSION_NAME" extension.\n\nDo you have a compatible "
1799                 "Vulkan installable client driver (ICD) installed?\nPlease "
1800                 "look at the Getting Started guide for additional "
1801                 "information.\n",
1802                 "vkCreateInstance Failure");
1803    }
1804    if (!platformSurfaceExtFound) {
1805#ifdef _WIN32
1806        ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the "
1807            VK_KHR_WIN32_SURFACE_EXTENSION_NAME" extension.\n\nDo you have a compatible "
1808            "Vulkan installable client driver (ICD) installed?\nPlease "
1809            "look at the Getting Started guide for additional "
1810            "information.\n",
1811            "vkCreateInstance Failure");
1812#else  // _WIN32
1813        ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find the "
1814            VK_KHR_XCB_SURFACE_EXTENSION_NAME" extension.\n\nDo you have a compatible "
1815            "Vulkan installable client driver (ICD) installed?\nPlease "
1816            "look at the Getting Started guide for additional "
1817            "information.\n",
1818            "vkCreateInstance Failure");
1819#endif // _WIN32
1820    }
1821    const VkApplicationInfo app = {
1822        .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1823        .pNext = NULL,
1824        .pApplicationName = APP_SHORT_NAME,
1825        .applicationVersion = 0,
1826        .pEngineName = APP_SHORT_NAME,
1827        .engineVersion = 0,
1828        .apiVersion = VK_API_VERSION,
1829    };
1830    VkInstanceCreateInfo inst_info = {
1831        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1832        .pNext = NULL,
1833        .pApplicationInfo = &app,
1834        .enabledLayerNameCount = enabled_layer_count,
1835        .ppEnabledLayerNames = (const char *const*) layer_names,
1836        .enabledExtensionNameCount = enabled_extension_count,
1837        .ppEnabledExtensionNames = (const char *const*) extension_names,
1838    };
1839    float queue_priorities[1] = { 0.0 };
1840    const VkDeviceQueueCreateInfo queue = {
1841        .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
1842        .pNext = NULL,
1843        .queueFamilyIndex = 0,
1844        .queueCount = 1,
1845        .pQueuePriorities = queue_priorities
1846    };
1847    uint32_t gpu_count;
1848
1849    demo->allocator.pfnAllocation = myalloc;
1850    demo->allocator.pfnFree = myfree;
1851    demo->allocator.pfnReallocation = myrealloc;
1852
1853    err = vkCreateInstance(&inst_info, &demo->allocator, &demo->inst);
1854    if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1855        ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1856                 "(ICD).\n\nPlease look at the Getting Started guide for "
1857                 "additional information.\n",
1858                 "vkCreateInstance Failure");
1859    } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1860        ERR_EXIT("Cannot find a specified extension library"
1861                 ".\nMake sure your layers path is set appropriately\n",
1862                 "vkCreateInstance Failure");
1863    } else if (err) {
1864        ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
1865                 "installable client driver (ICD) installed?\nPlease look at "
1866                 "the Getting Started guide for additional information.\n",
1867                 "vkCreateInstance Failure");
1868    }
1869
1870    free(instance_layers);
1871    free(instance_extensions);
1872
1873    /* Make initial call to query gpu_count, then second call for gpu info*/
1874    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
1875    assert(!err && gpu_count > 0);
1876    physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
1877    err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
1878    assert(!err);
1879    /* For tri demo we just grab the first physical device */
1880    demo->gpu = physical_devices[0];
1881    free(physical_devices);
1882
1883    /* Look for validation layers */
1884    validation_found = 0;
1885    enabled_layer_count = 0;
1886    uint32_t device_layer_count = 0;
1887    err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
1888    assert(!err);
1889
1890    device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count);
1891    err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers);
1892    assert(!err);
1893
1894    if (demo->validate) {
1895        validation_found = demo_check_layers(ARRAY_SIZE(device_validation_layers), device_validation_layers,
1896                                             device_layer_count, device_layers);
1897        if (!validation_found) {
1898            ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find"
1899                     "a required validation layer.\n\n"
1900                     "Please look at the Getting Started guide for additional "
1901                     "information.\n",
1902                     "vkCreateDevice Failure");
1903        }
1904        enabled_layer_count = ARRAY_SIZE(device_validation_layers);
1905    }
1906
1907    uint32_t device_extension_count = 0;
1908    VkExtensionProperties *device_extensions = NULL;
1909    err = vkEnumerateDeviceExtensionProperties(
1910              demo->gpu, NULL, &device_extension_count, NULL);
1911    assert(!err);
1912
1913    VkBool32 swapchainExtFound = 0;
1914    enabled_extension_count = 0;
1915    memset(extension_names, 0, sizeof(extension_names));
1916    device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count);
1917    err = vkEnumerateDeviceExtensionProperties(
1918              demo->gpu, NULL, &device_extension_count, device_extensions);
1919    assert(!err);
1920
1921    for (uint32_t i = 0; i < device_extension_count; i++) {
1922        if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME, device_extensions[i].extensionName)) {
1923            swapchainExtFound = 1;
1924            extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
1925        }
1926        assert(enabled_extension_count < 64);
1927    }
1928    if (!swapchainExtFound) {
1929        ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find the "
1930                 VK_KHR_SWAPCHAIN_EXTENSION_NAME" extension.\n\nDo you have a compatible "
1931                 "Vulkan installable client driver (ICD) installed?\nPlease "
1932                 "look at the Getting Started guide for additional "
1933                 "information.\n",
1934                 "vkCreateInstance Failure");
1935    }
1936
1937    VkDeviceCreateInfo device = {
1938        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
1939        .pNext = NULL,
1940        .queueCreateInfoCount = 1,
1941        .pQueueCreateInfos = &queue,
1942        .enabledLayerNameCount = enabled_layer_count,
1943        .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? device_validation_layers : NULL),
1944        .enabledExtensionNameCount = enabled_extension_count,
1945        .ppEnabledExtensionNames = (const char *const*) extension_names,
1946    };
1947
1948    if (demo->validate) {
1949        demo->dbgCreateMsgCallback = (PFN_vkDbgCreateMsgCallback) vkGetInstanceProcAddr(demo->inst, "vkDbgCreateMsgCallback");
1950        if (!demo->dbgCreateMsgCallback) {
1951            ERR_EXIT("GetProcAddr: Unable to find vkDbgCreateMsgCallback\n",
1952                     "vkGetProcAddr Failure");
1953        }
1954        err = demo->dbgCreateMsgCallback(
1955                  demo->inst,
1956                  VK_DEBUG_REPORT_ERROR_BIT | VK_DEBUG_REPORT_WARN_BIT,
1957                  dbgFunc, NULL,
1958                  &demo->msg_callback);
1959        switch (err) {
1960        case VK_SUCCESS:
1961            break;
1962        case VK_ERROR_OUT_OF_HOST_MEMORY:
1963            ERR_EXIT("dbgCreateMsgCallback: out of host memory\n",
1964                     "dbgCreateMsgCallback Failure");
1965            break;
1966        default:
1967            ERR_EXIT("dbgCreateMsgCallback: unknown failure\n",
1968                     "dbgCreateMsgCallback Failure");
1969            break;
1970        }
1971    }
1972
1973    // Having these GIPA queries of device extension entry points both
1974    // BEFORE and AFTER vkCreateDevice is a good test for the loader
1975    GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
1976    GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
1977    GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
1978
1979    err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
1980    assert(!err);
1981
1982    GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
1983    GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
1984    GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
1985    GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
1986    GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
1987    GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
1988
1989    vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
1990
1991    // Query with NULL data to get count
1992    vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, NULL);
1993
1994    demo->queue_props = (VkQueueFamilyProperties *) malloc(demo->queue_count * sizeof(VkQueueFamilyProperties));
1995    vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count, demo->queue_props);
1996    assert(demo->queue_count >= 1);
1997
1998    // Graphics queue and MemMgr queue can be separate.
1999    // TODO: Add support for separate queues, including synchronization,
2000    //       and appropriate tracking for QueueSubmit
2001}
2002
2003static void demo_init_vk_swapchain(struct demo *demo)
2004{
2005    VkResult U_ASSERT_ONLY err;
2006    uint32_t i;
2007
2008    // Create a WSI surface for the window:
2009#ifdef _WIN32
2010    err = vkCreateWin32SurfaceKHR(demo->inst, demo->connection, demo->window,
2011                                  NULL, &demo->surface);
2012
2013#else  // _WIN32
2014    err = vkCreateXcbSurfaceKHR(demo->inst, demo->connection, demo->window,
2015                                NULL, &demo->surface);
2016#endif // _WIN32
2017
2018    // Iterate over each queue to learn whether it supports presenting:
2019    VkBool32* supportsPresent = (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2020    for (i = 0; i < demo->queue_count; i++) {
2021        demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i,
2022                                                   demo->surface,
2023                                                   &supportsPresent[i]);
2024    }
2025
2026    // Search for a graphics and a present queue in the array of queue
2027    // families, try to find one that supports both
2028    uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2029    uint32_t presentQueueNodeIndex  = UINT32_MAX;
2030    for (i = 0; i < demo->queue_count; i++) {
2031        if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2032            if (graphicsQueueNodeIndex == UINT32_MAX) {
2033                graphicsQueueNodeIndex = i;
2034            }
2035
2036            if (supportsPresent[i] == VK_TRUE) {
2037                graphicsQueueNodeIndex = i;
2038                presentQueueNodeIndex = i;
2039                break;
2040            }
2041        }
2042    }
2043    if (presentQueueNodeIndex == UINT32_MAX) {
2044        // If didn't find a queue that supports both graphics and present, then
2045        // find a separate present queue.
2046        for (uint32_t i = 0; i < demo->queue_count; ++i) {
2047            if (supportsPresent[i] == VK_TRUE) {
2048                presentQueueNodeIndex = i;
2049                break;
2050            }
2051        }
2052    }
2053    free(supportsPresent);
2054
2055    // Generate error if could not find both a graphics and a present queue
2056    if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
2057        ERR_EXIT("Could not find a graphics and a present queue\n",
2058                 "Swapchain Initialization Failure");
2059    }
2060
2061    // TODO: Add support for separate queues, including presentation,
2062    //       synchronization, and appropriate tracking for QueueSubmit.
2063    // NOTE: While it is possible for an application to use a separate graphics
2064    //       and a present queues, this demo program assumes it is only using
2065    //       one:
2066    if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2067        ERR_EXIT("Could not find a common graphics and a present queue\n",
2068                 "Swapchain Initialization Failure");
2069    }
2070
2071    demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2072
2073    vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
2074            0, &demo->queue);
2075
2076    // Get the list of VkFormat's that are supported:
2077    uint32_t formatCount;
2078    err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu,
2079                                                     demo->surface,
2080                                                     &formatCount, NULL);
2081    assert(!err);
2082    VkSurfaceFormatKHR *surfFormats =
2083        (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2084    err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu,
2085                                                     demo->surface,
2086                                                     &formatCount, surfFormats);
2087    assert(!err);
2088    // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2089    // the surface has no preferred format.  Otherwise, at least one
2090    // supported format will be returned.
2091    if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
2092    {
2093        demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2094    }
2095    else
2096    {
2097        assert(formatCount >= 1);
2098        demo->format = surfFormats[0].format;
2099    }
2100    demo->color_space = surfFormats[0].colorSpace;
2101
2102    // Get Memory information and properties
2103    vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2104}
2105
2106static void demo_init_connection(struct demo *demo)
2107{
2108#ifndef _WIN32
2109    const xcb_setup_t *setup;
2110    xcb_screen_iterator_t iter;
2111    int scr;
2112
2113    demo->connection = xcb_connect(NULL, &scr);
2114    if (demo->connection == NULL) {
2115        printf("Cannot find a compatible Vulkan installable client driver "
2116               "(ICD).\nExiting ...\n");
2117        fflush(stdout);
2118        exit(1);
2119    }
2120
2121    setup = xcb_get_setup(demo->connection);
2122    iter = xcb_setup_roots_iterator(setup);
2123    while (scr-- > 0)
2124        xcb_screen_next(&iter);
2125
2126    demo->screen = iter.data;
2127#endif // _WIN32
2128}
2129
2130#ifdef _WIN32
2131static void demo_init(struct demo *demo, HINSTANCE hInstance, LPSTR pCmdLine)
2132#else  // _WIN32
2133static void demo_init(struct demo *demo, const int argc, const char *argv[])
2134#endif // _WIN32
2135{
2136    bool argv_error = false;
2137
2138    memset(demo, 0, sizeof(*demo));
2139
2140#ifdef _WIN32
2141    demo->connection = hInstance;
2142    strncpy(demo->name, APP_SHORT_NAME, APP_NAME_STR_LEN);
2143
2144    if (strncmp(pCmdLine, "--use_staging", strlen("--use_staging")) == 0)
2145        demo->use_staging_buffer = true;
2146    else if (strlen(pCmdLine) != 0) {
2147        fprintf(stderr, "Do not recognize argument \"%s\".\n", pCmdLine);
2148        argv_error = true;
2149    }
2150#else  // _WIN32
2151    for (int i = 0; i < argc; i++) {
2152        if (strncmp(argv[i], "--use_staging", strlen("--use_staging")) == 0)
2153            demo->use_staging_buffer = true;
2154    }
2155#endif // _WIN32
2156    if (argv_error) {
2157        fprintf(stderr, "Usage:\n  %s [--use_staging]\n", APP_SHORT_NAME);
2158        fflush(stderr);
2159        exit(1);
2160    }
2161
2162    demo_init_connection(demo);
2163    demo_init_vk(demo);
2164
2165    demo->width = 300;
2166    demo->height = 300;
2167    demo->depthStencil = 1.0;
2168    demo->depthIncrement = -0.01f;
2169}
2170
2171static void demo_cleanup(struct demo *demo)
2172{
2173    uint32_t i;
2174
2175    demo->prepared = false;
2176
2177    for (i = 0; i < demo->swapchainImageCount; i++) {
2178        vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2179    }
2180    free(demo->framebuffers);
2181    vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2182
2183    if (demo->setup_cmd) {
2184        vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2185    }
2186    vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2187    vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2188
2189    vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2190    vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2191    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2192    vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2193
2194    vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2195    vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2196
2197    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2198        vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2199        vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2200        vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2201        vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2202    }
2203
2204    for (i = 0; i < demo->swapchainImageCount; i++) {
2205        vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2206    }
2207
2208    vkDestroyImageView(demo->device, demo->depth.view, NULL);
2209    vkDestroyImage(demo->device, demo->depth.image, NULL);
2210    vkFreeMemory(demo->device, demo->depth.mem, NULL);
2211
2212    demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2213    free(demo->buffers);
2214
2215    vkDestroyDevice(demo->device, NULL);
2216    vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2217    vkDestroyInstance(demo->inst, &demo->allocator);
2218
2219    free(demo->queue_props);
2220
2221#ifndef _WIN32
2222    xcb_destroy_window(demo->connection, demo->window);
2223    xcb_disconnect(demo->connection);
2224    free(demo->atom_wm_delete_window);
2225#endif // _WIN32
2226}
2227
2228static void demo_resize(struct demo *demo)
2229{
2230    uint32_t i;
2231
2232    // Don't react to resize until after first initialization.
2233    if (!demo->prepared) {
2234        return;
2235    }
2236    // In order to properly resize the window, we must re-create the swapchain
2237    // AND redo the command buffers, etc.
2238    //
2239    // First, perform part of the demo_cleanup() function:
2240    demo->prepared = false;
2241
2242    for (i = 0; i < demo->swapchainImageCount; i++) {
2243        vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2244    }
2245    free(demo->framebuffers);
2246    vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2247
2248    if (demo->setup_cmd) {
2249        vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2250    }
2251    vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2252    vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2253
2254    vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2255    vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2256    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2257    vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2258
2259    vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2260    vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2261
2262    for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2263        vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2264        vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2265        vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2266        vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2267    }
2268
2269    for (i = 0; i < demo->swapchainImageCount; i++) {
2270        vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2271    }
2272
2273    vkDestroyImageView(demo->device, demo->depth.view, NULL);
2274    vkDestroyImage(demo->device, demo->depth.image, NULL);
2275    vkFreeMemory(demo->device, demo->depth.mem, NULL);
2276
2277    free(demo->buffers);
2278
2279    // Second, re-perform the demo_prepare() function, which will re-create the
2280    // swapchain:
2281    demo_prepare(demo);
2282}
2283
2284#ifdef _WIN32
2285int APIENTRY WinMain(HINSTANCE hInstance,
2286                     HINSTANCE hPrevInstance,
2287                     LPSTR pCmdLine,
2288                     int nCmdShow)
2289{
2290    MSG msg;         // message
2291    bool done;        // flag saying when app is complete
2292
2293    demo_init(&demo, hInstance, pCmdLine);
2294    demo_create_window(&demo);
2295    demo_init_vk_swapchain(&demo);
2296
2297    demo_prepare(&demo);
2298
2299    done = false; //initialize loop condition variable
2300    /* main message loop*/
2301    while(!done)
2302    {
2303        PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2304        if (msg.message == WM_QUIT) //check for a quit message
2305        {
2306            done = true; //if found, quit app
2307        }
2308        else
2309        {
2310            /* Translate and dispatch to event queue*/
2311            TranslateMessage(&msg);
2312            DispatchMessage(&msg);
2313        }
2314        RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2315    }
2316
2317    demo_cleanup(&demo);
2318
2319    return (int) msg.wParam;
2320}
2321#else  // _WIN32
2322int main(const int argc, const char *argv[])
2323{
2324    struct demo demo;
2325
2326    demo_init(&demo, argc, argv);
2327    demo_create_window(&demo);
2328    demo_init_vk_swapchain(&demo);
2329
2330    demo_prepare(&demo);
2331    demo_run(&demo);
2332
2333    demo_cleanup(&demo);
2334
2335    return 0;
2336}
2337#endif // _WIN32
2338