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