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