dcbfd8676e9b98c71d80adefdaa1a7a7babe2997
[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                 wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1787         }
1788
1789         wl_surface_set_user_data(demo->wl_surface, demo);
1790         wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1791 }
1792 #endif // _WIN32
1793
1794 /*
1795  * Return 1 (true) if all layer names specified in check_names
1796  * can be found in given layer properties.
1797  */
1798 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1799                                   uint32_t layer_count,
1800                                   VkLayerProperties *layers) {
1801         uint32_t i, j;
1802     for (i = 0; i < check_count; i++) {
1803         VkBool32 found = 0;
1804         for (j = 0; j < layer_count; j++) {
1805             if (!strcmp(check_names[i], layers[j].layerName)) {
1806                 found = 1;
1807                 break;
1808             }
1809         }
1810         if (!found) {
1811             fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1812             return 0;
1813         }
1814     }
1815     return 1;
1816 }
1817
1818 static void demo_init_vk(struct demo *demo) {
1819     VkResult err;
1820     uint32_t instance_extension_count = 0;
1821     uint32_t instance_layer_count = 0;
1822     uint32_t device_validation_layer_count = 0;
1823     char **instance_validation_layers = NULL;
1824         uint32_t i;
1825     demo->enabled_extension_count = 0;
1826     demo->enabled_layer_count = 0;
1827
1828     char *instance_validation_layers_alt1[] = {
1829         "VK_LAYER_LUNARG_standard_validation"
1830     };
1831
1832     char *instance_validation_layers_alt2[] = {
1833         "VK_LAYER_GOOGLE_threading",     "VK_LAYER_LUNARG_parameter_validation",
1834         "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
1835         "VK_LAYER_LUNARG_image",         "VK_LAYER_LUNARG_core_validation",
1836         "VK_LAYER_LUNARG_swapchain",     "VK_LAYER_GOOGLE_unique_objects"
1837     };
1838
1839     /* Look for validation layers */
1840     VkBool32 validation_found = 0;
1841     if (demo->validate) {
1842
1843         err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1844         assert(!err);
1845
1846         instance_validation_layers = instance_validation_layers_alt1;
1847         if (instance_layer_count > 0) {
1848             VkLayerProperties *instance_layers =
1849                     malloc(sizeof (VkLayerProperties) * instance_layer_count);
1850             err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
1851                     instance_layers);
1852             assert(!err);
1853
1854
1855             validation_found = demo_check_layers(
1856                     ARRAY_SIZE(instance_validation_layers_alt1),
1857                     instance_validation_layers, instance_layer_count,
1858                     instance_layers);
1859             if (validation_found) {
1860                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
1861                 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation";
1862                 device_validation_layer_count = 1;
1863             } else {
1864                 // use alternative set of validation layers
1865                 instance_validation_layers = instance_validation_layers_alt2;
1866                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
1867                 validation_found = demo_check_layers(
1868                     ARRAY_SIZE(instance_validation_layers_alt2),
1869                     instance_validation_layers, instance_layer_count,
1870                     instance_layers);
1871                 device_validation_layer_count =
1872                         ARRAY_SIZE(instance_validation_layers_alt2);
1873                 for (i = 0; i < device_validation_layer_count; i++) {
1874                     demo->device_validation_layers[i] =
1875                             instance_validation_layers[i];
1876                 }
1877             }
1878             free(instance_layers);
1879         }
1880
1881         if (!validation_found) {
1882             ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1883                     "required validation layer.\n\n"
1884                     "Please look at the Getting Started guide for additional "
1885                     "information.\n",
1886                     "vkCreateInstance Failure");
1887         }
1888     }
1889
1890     /* Look for instance extensions */
1891     VkBool32 surfaceExtFound = 0;
1892     VkBool32 platformSurfaceExtFound = 0;
1893     memset(demo->extension_names, 0, sizeof(demo->extension_names));
1894
1895     err = vkEnumerateInstanceExtensionProperties(
1896         NULL, &instance_extension_count, NULL);
1897     assert(!err);
1898
1899     if (instance_extension_count > 0) {
1900                 uint32_t i;
1901         VkExtensionProperties *instance_extensions =
1902             malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1903         err = vkEnumerateInstanceExtensionProperties(
1904             NULL, &instance_extension_count, instance_extensions);
1905         assert(!err);
1906         for (i = 0; i < instance_extension_count; i++) {
1907             if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
1908                         instance_extensions[i].extensionName)) {
1909                 surfaceExtFound = 1;
1910                 demo->extension_names[demo->enabled_extension_count++] =
1911                     VK_KHR_SURFACE_EXTENSION_NAME;
1912             }
1913 #ifdef _WIN32
1914             if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
1915                         instance_extensions[i].extensionName)) {
1916                 platformSurfaceExtFound = 1;
1917                 demo->extension_names[demo->enabled_extension_count++] =
1918                     VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1919             }
1920 #else  // _WIN32
1921                         if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
1922                                     instance_extensions[i].extensionName)) {
1923                                 platformSurfaceExtFound = 1;
1924                                 demo->extension_names[demo->enabled_extension_count++] =
1925                                         VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1926                         }
1927 #endif // _WIN32
1928             if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
1929                         instance_extensions[i].extensionName)) {
1930                 if (demo->validate) {
1931                     demo->extension_names[demo->enabled_extension_count++] =
1932                         VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1933                 }
1934             }
1935             assert(demo->enabled_extension_count < 64);
1936         }
1937
1938         free(instance_extensions);
1939     }
1940
1941     if (!surfaceExtFound) {
1942         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1943                  "the " VK_KHR_SURFACE_EXTENSION_NAME
1944                  " extension.\n\nDo you have a compatible "
1945                  "Vulkan installable client driver (ICD) installed?\nPlease "
1946                  "look at the Getting Started guide for additional "
1947                  "information.\n",
1948                  "vkCreateInstance Failure");
1949     }
1950     if (!platformSurfaceExtFound) {
1951 #ifdef _WIN32
1952         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1953                  "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
1954                  " extension.\n\nDo you have a compatible "
1955                  "Vulkan installable client driver (ICD) installed?\nPlease "
1956                  "look at the Getting Started guide for additional "
1957                  "information.\n",
1958                  "vkCreateInstance Failure");
1959 #else  // _WIN32
1960         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1961                  "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
1962                  " extension.\n\nDo you have a compatible "
1963                  "Vulkan installable client driver (ICD) installed?\nPlease "
1964                  "look at the Getting Started guide for additional "
1965                  "information.\n",
1966                  "vkCreateInstance Failure");
1967 #endif // _WIN32
1968     }
1969     const VkApplicationInfo app = {
1970         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1971         .pNext = NULL,
1972         .pApplicationName = APP_SHORT_NAME,
1973         .applicationVersion = 0,
1974         .pEngineName = APP_SHORT_NAME,
1975         .engineVersion = 0,
1976         .apiVersion = VK_API_VERSION_1_0,
1977     };
1978     VkInstanceCreateInfo inst_info = {
1979         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1980         .pNext = NULL,
1981         .pApplicationInfo = &app,
1982         .enabledLayerCount = demo->enabled_layer_count,
1983         .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
1984         .enabledExtensionCount = demo->enabled_extension_count,
1985         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
1986     };
1987
1988     uint32_t gpu_count;
1989
1990     err = vkCreateInstance(&inst_info, NULL, &demo->inst);
1991     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1992         ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1993                  "(ICD).\n\nPlease look at the Getting Started guide for "
1994                  "additional information.\n",
1995                  "vkCreateInstance Failure");
1996     } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1997         ERR_EXIT("Cannot find a specified extension library"
1998                  ".\nMake sure your layers path is set appropriately\n",
1999                  "vkCreateInstance Failure");
2000     } else if (err) {
2001         ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
2002                  "installable client driver (ICD) installed?\nPlease look at "
2003                  "the Getting Started guide for additional information.\n",
2004                  "vkCreateInstance Failure");
2005     }
2006
2007     /* Make initial call to query gpu_count, then second call for gpu info*/
2008     err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2009     assert(!err && gpu_count > 0);
2010
2011     if (gpu_count > 0) {
2012         VkPhysicalDevice *physical_devices =
2013             malloc(sizeof(VkPhysicalDevice) * gpu_count);
2014         assert(physical_devices);
2015         err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count,
2016                                          physical_devices);
2017         assert(!err);
2018         /* For tri demo we just grab the first physical device */
2019         demo->gpu = physical_devices[0];
2020         free(physical_devices);
2021     } else {
2022         ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices."
2023                  "\n\nDo you have a compatible Vulkan installable client"
2024                  " driver (ICD) installed?\nPlease look at the Getting Started"
2025                  " guide for additional information.\n",
2026                  "vkEnumeratePhysicalDevices Failure");
2027     }
2028
2029     /* Look for validation layers */
2030     if (demo->validate) {
2031         validation_found = 0;
2032         demo->enabled_layer_count = 0;
2033         uint32_t device_layer_count = 0;
2034         err =
2035                 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2036         assert(!err);
2037
2038         if (device_layer_count > 0) {
2039             VkLayerProperties *device_layers =
2040                     malloc(sizeof (VkLayerProperties) * device_layer_count);
2041             err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
2042                     device_layers);
2043             assert(!err);
2044
2045
2046             validation_found = demo_check_layers(device_validation_layer_count,
2047                     demo->device_validation_layers,
2048                     device_layer_count,
2049                     device_layers);
2050             demo->enabled_layer_count = device_validation_layer_count;
2051
2052             free(device_layers);
2053         }
2054
2055         if (!validation_found) {
2056             ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
2057                     "a required validation layer.\n\n"
2058                     "Please look at the Getting Started guide for additional "
2059                     "information.\n",
2060                     "vkCreateDevice Failure");
2061         }
2062     }
2063
2064     /* Look for device extensions */
2065     uint32_t device_extension_count = 0;
2066     VkBool32 swapchainExtFound = 0;
2067     demo->enabled_extension_count = 0;
2068     memset(demo->extension_names, 0, sizeof(demo->extension_names));
2069
2070     err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2071                                                &device_extension_count, NULL);
2072     assert(!err);
2073
2074     if (device_extension_count > 0) {
2075                 uint32_t i;
2076         VkExtensionProperties *device_extensions =
2077                 malloc(sizeof(VkExtensionProperties) * device_extension_count);
2078         err = vkEnumerateDeviceExtensionProperties(
2079             demo->gpu, NULL, &device_extension_count, device_extensions);
2080         assert(!err);
2081
2082         for (i = 0; i < device_extension_count; i++) {
2083             if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2084                         device_extensions[i].extensionName)) {
2085                 swapchainExtFound = 1;
2086                 demo->extension_names[demo->enabled_extension_count++] =
2087                     VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2088             }
2089             assert(demo->enabled_extension_count < 64);
2090         }
2091
2092         free(device_extensions);
2093     }
2094
2095     if (!swapchainExtFound) {
2096         ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2097                  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2098                  " extension.\n\nDo you have a compatible "
2099                  "Vulkan installable client driver (ICD) installed?\nPlease "
2100                  "look at the Getting Started guide for additional "
2101                  "information.\n",
2102                  "vkCreateInstance Failure");
2103     }
2104
2105     if (demo->validate) {
2106         demo->CreateDebugReportCallback =
2107             (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2108                 demo->inst, "vkCreateDebugReportCallbackEXT");
2109         demo->DestroyDebugReportCallback =
2110             (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2111                 demo->inst, "vkDestroyDebugReportCallbackEXT");
2112         if (!demo->CreateDebugReportCallback) {
2113             ERR_EXIT(
2114                 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2115                 "vkGetProcAddr Failure");
2116         }
2117         if (!demo->DestroyDebugReportCallback) {
2118             ERR_EXIT(
2119                 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2120                 "vkGetProcAddr Failure");
2121         }
2122         demo->DebugReportMessage =
2123             (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2124                 demo->inst, "vkDebugReportMessageEXT");
2125         if (!demo->DebugReportMessage) {
2126             ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2127                      "vkGetProcAddr Failure");
2128         }
2129
2130         VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2131         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2132         dbgCreateInfo.flags =
2133             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2134         dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2135         dbgCreateInfo.pUserData = NULL;
2136         dbgCreateInfo.pNext = NULL;
2137         err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2138                                               &demo->msg_callback);
2139         switch (err) {
2140         case VK_SUCCESS:
2141             break;
2142         case VK_ERROR_OUT_OF_HOST_MEMORY:
2143             ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2144                      "CreateDebugReportCallback Failure");
2145             break;
2146         default:
2147             ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2148                      "CreateDebugReportCallback Failure");
2149             break;
2150         }
2151     }
2152
2153     // Having these GIPA queries of device extension entry points both
2154     // BEFORE and AFTER vkCreateDevice is a good test for the loader
2155     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2156     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2157     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2158     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2159     GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
2160     GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
2161     GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2162     GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
2163     GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
2164
2165     vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2166
2167     // Query with NULL data to get count
2168     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2169                                              NULL);
2170
2171     demo->queue_props = (VkQueueFamilyProperties *)malloc(
2172         demo->queue_count * sizeof(VkQueueFamilyProperties));
2173     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2174                                              demo->queue_props);
2175     assert(demo->queue_count >= 1);
2176
2177     VkPhysicalDeviceFeatures features;
2178     vkGetPhysicalDeviceFeatures(demo->gpu, &features);
2179
2180 #if 0 /* Temporarily disable checking shader clip distance feature. */
2181     if (!features.shaderClipDistance) {
2182         ERR_EXIT("Required device feature `shaderClipDistance` not supported\n",
2183                  "GetPhysicalDeviceFeatures failure");
2184     }
2185 #endif
2186
2187     // Graphics queue and MemMgr queue can be separate.
2188     // TODO: Add support for separate queues, including synchronization,
2189     //       and appropriate tracking for QueueSubmit
2190 }
2191
2192 static void demo_init_device(struct demo *demo) {
2193     VkResult U_ASSERT_ONLY err;
2194
2195     float queue_priorities[1] = {0.0};
2196     const VkDeviceQueueCreateInfo queue = {
2197         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2198         .pNext = NULL,
2199         .queueFamilyIndex = demo->graphics_queue_node_index,
2200         .queueCount = 1,
2201         .pQueuePriorities = queue_priorities};
2202
2203     VkPhysicalDeviceFeatures features = {
2204         .shaderClipDistance = VK_TRUE,
2205     };
2206
2207     VkDeviceCreateInfo device = {
2208         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2209         .pNext = NULL,
2210         .queueCreateInfoCount = 1,
2211         .pQueueCreateInfos = &queue,
2212         .enabledLayerCount = demo->enabled_layer_count,
2213         .ppEnabledLayerNames =
2214             (const char *const *)((demo->validate)
2215                                       ? demo->device_validation_layers
2216                                       : NULL),
2217         .enabledExtensionCount = demo->enabled_extension_count,
2218         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2219         .pEnabledFeatures = &features,
2220     };
2221
2222     err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2223     assert(!err);
2224 }
2225
2226 static void demo_init_vk_swapchain(struct demo *demo) {
2227     VkResult U_ASSERT_ONLY err;
2228     uint32_t i;
2229
2230 // Create a WSI surface for the window:
2231 #ifdef _WIN32
2232     VkWin32SurfaceCreateInfoKHR createInfo;
2233     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2234     createInfo.pNext = NULL;
2235     createInfo.flags = 0;
2236     createInfo.hinstance = demo->connection;
2237     createInfo.hwnd = demo->window;
2238
2239     err =
2240         vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2241
2242 #else  // _WIN32
2243         VkWaylandSurfaceCreateInfoKHR createInfo;
2244         createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2245         createInfo.pNext = NULL;
2246         createInfo.flags = 0;
2247         createInfo.display = demo->display;
2248         createInfo.surface = demo->wl_surface;
2249
2250         err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2251 #endif // _WIN32
2252
2253     // Iterate over each queue to learn whether it supports presenting:
2254     VkBool32 *supportsPresent =
2255         (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2256     assert(supportsPresent);
2257     for (i = 0; i < demo->queue_count; i++) {
2258         demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
2259                                                    &supportsPresent[i]);
2260     }
2261
2262     // Search for a graphics and a present queue in the array of queue
2263     // families, try to find one that supports both
2264     uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2265     uint32_t presentQueueNodeIndex = UINT32_MAX;
2266     for (i = 0; i < demo->queue_count; i++) {
2267         if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2268             if (graphicsQueueNodeIndex == UINT32_MAX) {
2269                 graphicsQueueNodeIndex = i;
2270             }
2271
2272             if (supportsPresent[i] == VK_TRUE) {
2273                 graphicsQueueNodeIndex = i;
2274                 presentQueueNodeIndex = i;
2275                 break;
2276             }
2277         }
2278     }
2279     if (presentQueueNodeIndex == UINT32_MAX) {
2280         // If didn't find a queue that supports both graphics and present, then
2281         // find a separate present queue.
2282                 uint32_t i;
2283         for (i = 0; i < demo->queue_count; ++i) {
2284             if (supportsPresent[i] == VK_TRUE) {
2285                 presentQueueNodeIndex = i;
2286                 break;
2287             }
2288         }
2289     }
2290     free(supportsPresent);
2291
2292     // Generate error if could not find both a graphics and a present queue
2293     if (graphicsQueueNodeIndex == UINT32_MAX ||
2294         presentQueueNodeIndex == UINT32_MAX) {
2295         ERR_EXIT("Could not find a graphics and a present queue\n",
2296                  "Swapchain Initialization Failure");
2297     }
2298
2299     // TODO: Add support for separate queues, including presentation,
2300     //       synchronization, and appropriate tracking for QueueSubmit.
2301     // NOTE: While it is possible for an application to use a separate graphics
2302     //       and a present queues, this demo program assumes it is only using
2303     //       one:
2304     if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2305         ERR_EXIT("Could not find a common graphics and a present queue\n",
2306                  "Swapchain Initialization Failure");
2307     }
2308
2309     demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2310
2311     demo_init_device(demo);
2312
2313     vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
2314                      &demo->queue);
2315
2316     // Get the list of VkFormat's that are supported:
2317     uint32_t formatCount;
2318     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2319                                                      &formatCount, NULL);
2320     assert(!err);
2321     VkSurfaceFormatKHR *surfFormats =
2322         (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2323     assert(surfFormats);
2324     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2325                                                      &formatCount, surfFormats);
2326     assert(!err);
2327     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2328     // the surface has no preferred format.  Otherwise, at least one
2329     // supported format will be returned.
2330     if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
2331         demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2332     } else {
2333         assert(formatCount >= 1);
2334         demo->format = surfFormats[0].format;
2335     }
2336     demo->color_space = surfFormats[0].colorSpace;
2337
2338     demo->quit = false;
2339     demo->curFrame = 0;
2340
2341     // Get Memory information and properties
2342     vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2343 }
2344
2345 static void
2346 registry_handle_global(void *data, struct wl_registry *registry,
2347                        uint32_t name, const char *interface, uint32_t version) {
2348         struct demo *d = data;
2349
2350         printf("%s, interface: %s\n", __func__, interface);
2351
2352         if (strcmp(interface, "wl_compositor") == 0) {
2353                 d->compositor =
2354                         wl_registry_bind(registry, name,
2355                                          &wl_compositor_interface, 1);
2356         } else if (strcmp(interface, "wl_shm") == 0) {
2357                 d->shm = wl_registry_bind(registry, name,
2358                                           &wl_shm_interface, 1);
2359         }  else if (strcmp(interface, "wl_shell") == 0) {
2360                 d->shell =
2361                         wl_registry_bind(registry, name,
2362                                          &wl_shell_interface, 1);
2363         }
2364 }
2365
2366 static void
2367 registry_handle_global_remove(void *data, struct wl_registry *registry,
2368                               uint32_t name) {
2369 }
2370
2371 static const struct wl_registry_listener registry_listener = {
2372         registry_handle_global,
2373         registry_handle_global_remove
2374 };
2375
2376 static void demo_init_connection(struct demo *demo) {
2377 #ifndef _WIN32
2378         demo->display = wl_display_connect(NULL);
2379
2380         if (demo->display == NULL) {
2381                 printf("Cannot find a compatible Vulkan installable client driver "
2382                        "(ICD).\nExiting ...\n");
2383                 fflush(stdout);
2384                 exit(1);
2385         }
2386
2387         demo->registry = wl_display_get_registry(demo->display);
2388         wl_registry_add_listener(demo->registry, &registry_listener, demo);
2389         wl_display_dispatch(demo->display);
2390 #endif // _WIN32
2391 }
2392
2393 static void demo_init(struct demo *demo, const int argc, const char *argv[])
2394 {
2395         int i;
2396
2397     memset(demo, 0, sizeof(*demo));
2398     demo->frameCount = INT32_MAX;
2399
2400     for (i = 1; i < argc; i++) {
2401         if (strcmp(argv[i], "--use_staging") == 0) {
2402             demo->use_staging_buffer = true;
2403             continue;
2404         }
2405         if (strcmp(argv[i], "--break") == 0) {
2406             demo->use_break = true;
2407             continue;
2408         }
2409         if (strcmp(argv[i], "--validate") == 0) {
2410             demo->validate = true;
2411             continue;
2412         }
2413         if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
2414             i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
2415             demo->frameCount >= 0) {
2416             i++;
2417             continue;
2418         }
2419
2420         fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] "
2421                         "[--c <framecount>]\n",
2422                 APP_SHORT_NAME);
2423         fflush(stderr);
2424         exit(1);
2425     }
2426
2427     demo_init_connection(demo);
2428     demo_init_vk(demo);
2429
2430     demo->width = 1440;
2431     demo->height = 2560;
2432     demo->depthStencil = 1.0;
2433     demo->depthIncrement = -0.01f;
2434 }
2435
2436 static void demo_cleanup(struct demo *demo) {
2437     uint32_t i;
2438
2439     demo->prepared = false;
2440
2441     for (i = 0; i < demo->swapchainImageCount; i++) {
2442         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2443     }
2444     free(demo->framebuffers);
2445     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2446
2447     if (demo->setup_cmd) {
2448         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2449     }
2450     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2451     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2452
2453     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2454     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2455     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2456     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2457
2458     vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2459     vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2460
2461     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2462         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2463         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2464         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2465         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2466     }
2467
2468     for (i = 0; i < demo->swapchainImageCount; i++) {
2469         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2470     }
2471
2472     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2473     vkDestroyImage(demo->device, demo->depth.image, NULL);
2474     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2475
2476     demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2477     free(demo->buffers);
2478
2479     vkDestroyDevice(demo->device, NULL);
2480     if (demo->validate) {
2481         demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2482     }
2483     vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2484     vkDestroyInstance(demo->inst, NULL);
2485
2486     free(demo->queue_props);
2487 }
2488
2489 static void demo_resize(struct demo *demo) {
2490     uint32_t i;
2491
2492     // Don't react to resize until after first initialization.
2493     if (!demo->prepared) {
2494         return;
2495     }
2496     // In order to properly resize the window, we must re-create the swapchain
2497     // AND redo the command buffers, etc.
2498     //
2499     // First, perform part of the demo_cleanup() function:
2500     demo->prepared = false;
2501
2502     for (i = 0; i < demo->swapchainImageCount; i++) {
2503         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2504     }
2505     free(demo->framebuffers);
2506     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2507
2508     if (demo->setup_cmd) {
2509         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2510     }
2511     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2512     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2513
2514     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2515     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2516     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2517     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2518
2519     vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2520     vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2521
2522     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2523         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2524         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2525         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2526         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2527     }
2528
2529     for (i = 0; i < demo->swapchainImageCount; i++) {
2530         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2531     }
2532
2533     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2534     vkDestroyImage(demo->device, demo->depth.image, NULL);
2535     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2536
2537     free(demo->buffers);
2538
2539     // Second, re-perform the demo_prepare() function, which will re-create the
2540     // swapchain:
2541     demo_prepare(demo);
2542 }
2543
2544 #ifdef _WIN32
2545 // Include header required for parsing the command line options.
2546 #include <shellapi.h>
2547
2548 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2549                      LPSTR pCmdLine, int nCmdShow) {
2550     MSG msg;   // message
2551     bool done; // flag saying when app is complete
2552     int argc;
2553     char **argv;
2554
2555     // Use the CommandLine functions to get the command line arguments.
2556     // Unfortunately, Microsoft outputs
2557     // this information as wide characters for Unicode, and we simply want the
2558     // Ascii version to be compatible
2559     // with the non-Windows side.  So, we have to convert the information to
2560     // Ascii character strings.
2561     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2562     if (NULL == commandLineArgs) {
2563         argc = 0;
2564     }
2565
2566     if (argc > 0) {
2567         argv = (char **)malloc(sizeof(char *) * argc);
2568         if (argv == NULL) {
2569             argc = 0;
2570         } else {
2571             for (int iii = 0; iii < argc; iii++) {
2572                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2573                 size_t numConverted = 0;
2574
2575                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2576                 if (argv[iii] != NULL) {
2577                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2578                                commandLineArgs[iii], wideCharLen + 1);
2579                 }
2580             }
2581         }
2582     } else {
2583         argv = NULL;
2584     }
2585
2586     demo_init(&demo, argc, argv);
2587
2588     // Free up the items we had to allocate for the command line arguments.
2589     if (argc > 0 && argv != NULL) {
2590         for (int iii = 0; iii < argc; iii++) {
2591             if (argv[iii] != NULL) {
2592                 free(argv[iii]);
2593             }
2594         }
2595         free(argv);
2596     }
2597
2598     demo.connection = hInstance;
2599     strncpy(demo.name, "tri", APP_NAME_STR_LEN);
2600     demo_create_window(&demo);
2601     demo_init_vk_swapchain(&demo);
2602
2603     demo_prepare(&demo);
2604
2605     done = false; // initialize loop condition variable
2606     /* main message loop*/
2607     while (!done) {
2608         PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2609         if (msg.message == WM_QUIT) // check for a quit message
2610         {
2611             done = true; // if found, quit app
2612         } else {
2613             /* Translate and dispatch to event queue*/
2614             TranslateMessage(&msg);
2615             DispatchMessage(&msg);
2616         }
2617         RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2618     }
2619
2620     demo_cleanup(&demo);
2621
2622     return (int)msg.wParam;
2623 }
2624 #else  // _WIN32
2625 int main(const int argc, const char *argv[]) {
2626     struct demo demo;
2627
2628     demo_init(&demo, argc, argv);
2629     demo_create_window(&demo);
2630     demo_init_vk_swapchain(&demo);
2631
2632     demo_prepare(&demo);
2633     demo_run(&demo);
2634
2635     demo_cleanup(&demo);
2636
2637     return validation_error;
2638 }
2639 #endif // _WIN32