396b7c3e6818e5da41a79b3e6edaa9a322501619
[platform/core/uifw/vulkan-wsi-tizen.git] / samples / tri.c
1 /*
2  * Copyright (c) 2015-2016 The Khronos Group Inc.
3  * Copyright (c) 2015-2016 Valve Corporation
4  * Copyright (c) 2015-2016 LunarG, Inc.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials are
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included in
14  * all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS.
24  *
25  * Author: Chia-I Wu <olvaffe@gmail.com>
26  * Author: Cody Northrop <cody@lunarg.com>
27  * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
28  * Author: Ian Elliott <ian@LunarG.com>
29  * Author: Jon Ashburn <jon@lunarg.com>
30  * Author: Piers Daniell <pdaniell@nvidia.com>
31  */
32 /*
33  * Draw a textured triangle with depth testing.  This is written against Intel
34  * ICD.  It does not do state transition nor object memory binding like it
35  * should.  It also does no error checking.
36  */
37
38 #ifndef _MSC_VER
39 #define _ISOC11_SOURCE /* for aligned_alloc() */
40 #endif
41
42 #include <config.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <stdbool.h>
47 #include <assert.h>
48 #include <signal.h>
49 #include <unistd.h>
50
51 #ifdef _WIN32
52 #pragma comment(linker, "/subsystem:windows")
53 #define APP_NAME_STR_LEN 80
54 #endif // _WIN32
55
56 #include <vulkan/vulkan.h>
57
58 #define DEMO_TEXTURE_COUNT 1
59 #define VERTEX_BUFFER_BIND_ID 0
60 #define APP_SHORT_NAME "tri"
61 #define APP_LONG_NAME "The Vulkan Triangle Demo Program"
62
63 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
64
65 #if defined(NDEBUG) && defined(__GNUC__)
66 #define U_ASSERT_ONLY __attribute__((unused))
67 #else
68 #define U_ASSERT_ONLY
69 #endif
70
71 #ifdef _WIN32
72 #define ERR_EXIT(err_msg, err_class)                                           \
73     do {                                                                       \
74         MessageBox(NULL, err_msg, err_class, MB_OK);                           \
75         exit(1);                                                               \
76     } while (0)
77 #else // _WIN32
78
79 #define ERR_EXIT(err_msg, err_class)                                           \
80     do {                                                                       \
81         printf(err_msg);                                                       \
82         fflush(stdout);                                                        \
83         exit(1);                                                               \
84     } while (0)
85 #endif // _WIN32
86
87 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                               \
88     {                                                                          \
89         demo->fp##entrypoint =                                                 \
90             (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
91         if (demo->fp##entrypoint == NULL) {                                    \
92             ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint,    \
93                      "vkGetInstanceProcAddr Failure");                         \
94         }                                                                      \
95     }
96
97 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                  \
98     {                                                                          \
99         demo->fp##entrypoint =                                                 \
100             (PFN_vk##entrypoint)vkGetDeviceProcAddr(dev, "vk" #entrypoint);    \
101         if (demo->fp##entrypoint == NULL) {                                    \
102             ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint,      \
103                      "vkGetDeviceProcAddr Failure");                           \
104         }                                                                      \
105     }
106
107 struct texture_object {
108     VkSampler sampler;
109
110     VkImage image;
111     VkImageLayout imageLayout;
112
113     VkDeviceMemory mem;
114     VkImageView view;
115     int32_t tex_width, tex_height;
116 };
117
118 static int validation_error = 0;
119
120 VKAPI_ATTR VkBool32 VKAPI_CALL
121 dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
122         uint64_t srcObject, size_t location, int32_t msgCode,
123         const char *pLayerPrefix, const char *pMsg, void *pUserData) {
124     char *message = (char *)malloc(strlen(pMsg) + 100);
125
126     assert(message);
127
128     validation_error = 1;
129
130     if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
131         snprintf(message, sizeof(message), "ERROR: [%s] Code %d : %s",
132                  pLayerPrefix, msgCode, pMsg);
133     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
134         snprintf(message, sizeof(message), "WARNING: [%s] Code %d : %s",
135                  pLayerPrefix, msgCode, pMsg);
136     } else {
137         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 = 0,
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     }
1748 }
1749
1750 static void
1751 handle_ping(void *data, struct wl_shell_surface *shell_surface,
1752             uint32_t serial) {
1753         printf("%s\n", __func__);
1754         wl_shell_surface_pong(shell_surface, serial);
1755 }
1756
1757 static void
1758 handle_configure(void *data, struct wl_shell_surface *shell_surface,
1759                  uint32_t edges, int32_t width, int32_t height) {
1760         printf("%s, (%d, %d)\n", __func__, width, height);
1761 }
1762
1763 static void
1764 handle_popup_done(void *data, struct wl_shell_surface *shell_surface) {
1765 }
1766
1767 static const struct wl_shell_surface_listener shell_surface_listener = {
1768         handle_ping,
1769         handle_configure,
1770         handle_popup_done
1771 };
1772
1773 static void demo_create_window(struct demo *demo) {
1774         demo->wl_surface = wl_compositor_create_surface(demo->compositor);
1775
1776         demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->wl_surface);
1777
1778         if (demo->shell_surface) {
1779                 wl_shell_surface_add_listener(demo->shell_surface,
1780                                                                           &shell_surface_listener, demo);
1781                 wl_shell_surface_set_toplevel(demo->shell_surface);
1782         }
1783
1784         wl_surface_set_user_data(demo->wl_surface, demo);
1785         wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
1786 }
1787 #endif // _WIN32
1788
1789 /*
1790  * Return 1 (true) if all layer names specified in check_names
1791  * can be found in given layer properties.
1792  */
1793 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
1794                                   uint32_t layer_count,
1795                                   VkLayerProperties *layers) {
1796         uint32_t i, j;
1797     for (i = 0; i < check_count; i++) {
1798         VkBool32 found = 0;
1799         for (j = 0; j < layer_count; j++) {
1800             if (!strcmp(check_names[i], layers[j].layerName)) {
1801                 found = 1;
1802                 break;
1803             }
1804         }
1805         if (!found) {
1806             fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
1807             return 0;
1808         }
1809     }
1810     return 1;
1811 }
1812
1813 static void demo_init_vk(struct demo *demo) {
1814     VkResult err;
1815     uint32_t instance_extension_count = 0;
1816     uint32_t instance_layer_count = 0;
1817     uint32_t device_validation_layer_count = 0;
1818     char **instance_validation_layers = NULL;
1819         uint32_t i;
1820     demo->enabled_extension_count = 0;
1821     demo->enabled_layer_count = 0;
1822
1823     char *instance_validation_layers_alt1[] = {
1824         "VK_LAYER_LUNARG_standard_validation"
1825     };
1826
1827     char *instance_validation_layers_alt2[] = {
1828         "VK_LAYER_GOOGLE_threading",     "VK_LAYER_LUNARG_parameter_validation",
1829         "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_object_tracker",
1830         "VK_LAYER_LUNARG_image",         "VK_LAYER_LUNARG_core_validation",
1831         "VK_LAYER_LUNARG_swapchain",     "VK_LAYER_GOOGLE_unique_objects"
1832     };
1833
1834     /* Look for validation layers */
1835     VkBool32 validation_found = 0;
1836     if (demo->validate) {
1837
1838         err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
1839         assert(!err);
1840
1841         instance_validation_layers = instance_validation_layers_alt1;
1842         if (instance_layer_count > 0) {
1843             VkLayerProperties *instance_layers =
1844                     malloc(sizeof (VkLayerProperties) * instance_layer_count);
1845             err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
1846                     instance_layers);
1847             assert(!err);
1848
1849
1850             validation_found = demo_check_layers(
1851                     ARRAY_SIZE(instance_validation_layers_alt1),
1852                     instance_validation_layers, instance_layer_count,
1853                     instance_layers);
1854             if (validation_found) {
1855                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
1856                 demo->device_validation_layers[0] = "VK_LAYER_LUNARG_standard_validation";
1857                 device_validation_layer_count = 1;
1858             } else {
1859                 // use alternative set of validation layers
1860                 instance_validation_layers = instance_validation_layers_alt2;
1861                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
1862                 validation_found = demo_check_layers(
1863                     ARRAY_SIZE(instance_validation_layers_alt2),
1864                     instance_validation_layers, instance_layer_count,
1865                     instance_layers);
1866                 device_validation_layer_count =
1867                         ARRAY_SIZE(instance_validation_layers_alt2);
1868                 for (i = 0; i < device_validation_layer_count; i++) {
1869                     demo->device_validation_layers[i] =
1870                             instance_validation_layers[i];
1871                 }
1872             }
1873             free(instance_layers);
1874         }
1875
1876         if (!validation_found) {
1877             ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find"
1878                     "required validation layer.\n\n"
1879                     "Please look at the Getting Started guide for additional "
1880                     "information.\n",
1881                     "vkCreateInstance Failure");
1882         }
1883     }
1884
1885     /* Look for instance extensions */
1886     VkBool32 surfaceExtFound = 0;
1887     VkBool32 platformSurfaceExtFound = 0;
1888     memset(demo->extension_names, 0, sizeof(demo->extension_names));
1889
1890     err = vkEnumerateInstanceExtensionProperties(
1891         NULL, &instance_extension_count, NULL);
1892     assert(!err);
1893
1894     if (instance_extension_count > 0) {
1895                 uint32_t i;
1896         VkExtensionProperties *instance_extensions =
1897             malloc(sizeof(VkExtensionProperties) * instance_extension_count);
1898         err = vkEnumerateInstanceExtensionProperties(
1899             NULL, &instance_extension_count, instance_extensions);
1900         assert(!err);
1901         for (i = 0; i < instance_extension_count; i++) {
1902             if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
1903                         instance_extensions[i].extensionName)) {
1904                 surfaceExtFound = 1;
1905                 demo->extension_names[demo->enabled_extension_count++] =
1906                     VK_KHR_SURFACE_EXTENSION_NAME;
1907             }
1908 #ifdef _WIN32
1909             if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
1910                         instance_extensions[i].extensionName)) {
1911                 platformSurfaceExtFound = 1;
1912                 demo->extension_names[demo->enabled_extension_count++] =
1913                     VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
1914             }
1915 #else  // _WIN32
1916                         if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
1917                                     instance_extensions[i].extensionName)) {
1918                                 platformSurfaceExtFound = 1;
1919                                 demo->extension_names[demo->enabled_extension_count++] =
1920                                         VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
1921                         }
1922 #endif // _WIN32
1923             if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
1924                         instance_extensions[i].extensionName)) {
1925                 if (demo->validate) {
1926                     demo->extension_names[demo->enabled_extension_count++] =
1927                         VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
1928                 }
1929             }
1930             assert(demo->enabled_extension_count < 64);
1931         }
1932
1933         free(instance_extensions);
1934     }
1935
1936     if (!surfaceExtFound) {
1937         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1938                  "the " VK_KHR_SURFACE_EXTENSION_NAME
1939                  " extension.\n\nDo you have a compatible "
1940                  "Vulkan installable client driver (ICD) installed?\nPlease "
1941                  "look at the Getting Started guide for additional "
1942                  "information.\n",
1943                  "vkCreateInstance Failure");
1944     }
1945     if (!platformSurfaceExtFound) {
1946 #ifdef _WIN32
1947         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1948                  "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
1949                  " extension.\n\nDo you have a compatible "
1950                  "Vulkan installable client driver (ICD) installed?\nPlease "
1951                  "look at the Getting Started guide for additional "
1952                  "information.\n",
1953                  "vkCreateInstance Failure");
1954 #else  // _WIN32
1955         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
1956                  "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
1957                  " extension.\n\nDo you have a compatible "
1958                  "Vulkan installable client driver (ICD) installed?\nPlease "
1959                  "look at the Getting Started guide for additional "
1960                  "information.\n",
1961                  "vkCreateInstance Failure");
1962 #endif // _WIN32
1963     }
1964     const VkApplicationInfo app = {
1965         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
1966         .pNext = NULL,
1967         .pApplicationName = APP_SHORT_NAME,
1968         .applicationVersion = 0,
1969         .pEngineName = APP_SHORT_NAME,
1970         .engineVersion = 0,
1971         .apiVersion = VK_API_VERSION_1_0,
1972     };
1973     VkInstanceCreateInfo inst_info = {
1974         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
1975         .pNext = NULL,
1976         .pApplicationInfo = &app,
1977         .enabledLayerCount = demo->enabled_layer_count,
1978         .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
1979         .enabledExtensionCount = demo->enabled_extension_count,
1980         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
1981     };
1982
1983     uint32_t gpu_count;
1984
1985     err = vkCreateInstance(&inst_info, NULL, &demo->inst);
1986     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
1987         ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
1988                  "(ICD).\n\nPlease look at the Getting Started guide for "
1989                  "additional information.\n",
1990                  "vkCreateInstance Failure");
1991     } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
1992         ERR_EXIT("Cannot find a specified extension library"
1993                  ".\nMake sure your layers path is set appropriately\n",
1994                  "vkCreateInstance Failure");
1995     } else if (err) {
1996         ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
1997                  "installable client driver (ICD) installed?\nPlease look at "
1998                  "the Getting Started guide for additional information.\n",
1999                  "vkCreateInstance Failure");
2000     }
2001
2002     /* Make initial call to query gpu_count, then second call for gpu info*/
2003     err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2004     assert(!err && gpu_count > 0);
2005
2006     if (gpu_count > 0) {
2007         VkPhysicalDevice *physical_devices =
2008             malloc(sizeof(VkPhysicalDevice) * gpu_count);
2009         err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count,
2010                                          physical_devices);
2011         assert(!err);
2012         /* For tri demo we just grab the first physical device */
2013         demo->gpu = physical_devices[0];
2014         free(physical_devices);
2015     } else {
2016         ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices."
2017                  "\n\nDo you have a compatible Vulkan installable client"
2018                  " driver (ICD) installed?\nPlease look at the Getting Started"
2019                  " guide for additional information.\n",
2020                  "vkEnumeratePhysicalDevices Failure");
2021     }
2022
2023     /* Look for validation layers */
2024     if (demo->validate) {
2025         validation_found = 0;
2026         demo->enabled_layer_count = 0;
2027         uint32_t device_layer_count = 0;
2028         err =
2029                 vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
2030         assert(!err);
2031
2032         if (device_layer_count > 0) {
2033             VkLayerProperties *device_layers =
2034                     malloc(sizeof (VkLayerProperties) * device_layer_count);
2035             err = vkEnumerateDeviceLayerProperties(demo->gpu, &device_layer_count,
2036                     device_layers);
2037             assert(!err);
2038
2039
2040             validation_found = demo_check_layers(device_validation_layer_count,
2041                     demo->device_validation_layers,
2042                     device_layer_count,
2043                     device_layers);
2044             demo->enabled_layer_count = device_validation_layer_count;
2045
2046             free(device_layers);
2047         }
2048
2049         if (!validation_found) {
2050             ERR_EXIT("vkEnumerateDeviceLayerProperties failed to find "
2051                     "a required validation layer.\n\n"
2052                     "Please look at the Getting Started guide for additional "
2053                     "information.\n",
2054                     "vkCreateDevice Failure");
2055         }
2056     }
2057
2058     /* Look for device extensions */
2059     uint32_t device_extension_count = 0;
2060     VkBool32 swapchainExtFound = 0;
2061     demo->enabled_extension_count = 0;
2062     memset(demo->extension_names, 0, sizeof(demo->extension_names));
2063
2064     err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2065                                                &device_extension_count, NULL);
2066     assert(!err);
2067
2068     if (device_extension_count > 0) {
2069                 uint32_t i;
2070         VkExtensionProperties *device_extensions =
2071                 malloc(sizeof(VkExtensionProperties) * device_extension_count);
2072         err = vkEnumerateDeviceExtensionProperties(
2073             demo->gpu, NULL, &device_extension_count, device_extensions);
2074         assert(!err);
2075
2076         for (i = 0; i < device_extension_count; i++) {
2077             if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2078                         device_extensions[i].extensionName)) {
2079                 swapchainExtFound = 1;
2080                 demo->extension_names[demo->enabled_extension_count++] =
2081                     VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2082             }
2083             assert(demo->enabled_extension_count < 64);
2084         }
2085
2086         free(device_extensions);
2087     }
2088
2089     if (!swapchainExtFound) {
2090         ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2091                  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2092                  " extension.\n\nDo you have a compatible "
2093                  "Vulkan installable client driver (ICD) installed?\nPlease "
2094                  "look at the Getting Started guide for additional "
2095                  "information.\n",
2096                  "vkCreateInstance Failure");
2097     }
2098
2099     if (demo->validate) {
2100         demo->CreateDebugReportCallback =
2101             (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2102                 demo->inst, "vkCreateDebugReportCallbackEXT");
2103         demo->DestroyDebugReportCallback =
2104             (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2105                 demo->inst, "vkDestroyDebugReportCallbackEXT");
2106         if (!demo->CreateDebugReportCallback) {
2107             ERR_EXIT(
2108                 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2109                 "vkGetProcAddr Failure");
2110         }
2111         if (!demo->DestroyDebugReportCallback) {
2112             ERR_EXIT(
2113                 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2114                 "vkGetProcAddr Failure");
2115         }
2116         demo->DebugReportMessage =
2117             (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2118                 demo->inst, "vkDebugReportMessageEXT");
2119         if (!demo->DebugReportMessage) {
2120             ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2121                      "vkGetProcAddr Failure");
2122         }
2123
2124         VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2125         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2126         dbgCreateInfo.flags =
2127             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2128         dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2129         dbgCreateInfo.pUserData = NULL;
2130         dbgCreateInfo.pNext = NULL;
2131         err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2132                                               &demo->msg_callback);
2133         switch (err) {
2134         case VK_SUCCESS:
2135             break;
2136         case VK_ERROR_OUT_OF_HOST_MEMORY:
2137             ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2138                      "CreateDebugReportCallback Failure");
2139             break;
2140         default:
2141             ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2142                      "CreateDebugReportCallback Failure");
2143             break;
2144         }
2145     }
2146
2147     // Having these GIPA queries of device extension entry points both
2148     // BEFORE and AFTER vkCreateDevice is a good test for the loader
2149     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2150     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2151     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2152     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2153     GET_INSTANCE_PROC_ADDR(demo->inst, CreateSwapchainKHR);
2154     GET_INSTANCE_PROC_ADDR(demo->inst, DestroySwapchainKHR);
2155     GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2156     GET_INSTANCE_PROC_ADDR(demo->inst, AcquireNextImageKHR);
2157     GET_INSTANCE_PROC_ADDR(demo->inst, QueuePresentKHR);
2158
2159     vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2160
2161     // Query with NULL data to get count
2162     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2163                                              NULL);
2164
2165     demo->queue_props = (VkQueueFamilyProperties *)malloc(
2166         demo->queue_count * sizeof(VkQueueFamilyProperties));
2167     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu, &demo->queue_count,
2168                                              demo->queue_props);
2169     assert(demo->queue_count >= 1);
2170
2171     VkPhysicalDeviceFeatures features;
2172     vkGetPhysicalDeviceFeatures(demo->gpu, &features);
2173
2174 #if 0 /* Temporarily disable checking shader clip distance feature. */
2175     if (!features.shaderClipDistance) {
2176         ERR_EXIT("Required device feature `shaderClipDistance` not supported\n",
2177                  "GetPhysicalDeviceFeatures failure");
2178     }
2179 #endif
2180
2181     // Graphics queue and MemMgr queue can be separate.
2182     // TODO: Add support for separate queues, including synchronization,
2183     //       and appropriate tracking for QueueSubmit
2184 }
2185
2186 static void demo_init_device(struct demo *demo) {
2187     VkResult U_ASSERT_ONLY err;
2188
2189     float queue_priorities[1] = {0.0};
2190     const VkDeviceQueueCreateInfo queue = {
2191         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
2192         .pNext = NULL,
2193         .queueFamilyIndex = demo->graphics_queue_node_index,
2194         .queueCount = 1,
2195         .pQueuePriorities = queue_priorities};
2196
2197     VkPhysicalDeviceFeatures features = {
2198         .shaderClipDistance = VK_TRUE,
2199     };
2200
2201     VkDeviceCreateInfo device = {
2202         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2203         .pNext = NULL,
2204         .queueCreateInfoCount = 1,
2205         .pQueueCreateInfos = &queue,
2206         .enabledLayerCount = demo->enabled_layer_count,
2207         .ppEnabledLayerNames =
2208             (const char *const *)((demo->validate)
2209                                       ? demo->device_validation_layers
2210                                       : NULL),
2211         .enabledExtensionCount = demo->enabled_extension_count,
2212         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2213         .pEnabledFeatures = &features,
2214     };
2215
2216     err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2217     assert(!err);
2218 }
2219
2220 static void demo_init_vk_swapchain(struct demo *demo) {
2221     VkResult U_ASSERT_ONLY err;
2222     uint32_t i;
2223
2224 // Create a WSI surface for the window:
2225 #ifdef _WIN32
2226     VkWin32SurfaceCreateInfoKHR createInfo;
2227     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2228     createInfo.pNext = NULL;
2229     createInfo.flags = 0;
2230     createInfo.hinstance = demo->connection;
2231     createInfo.hwnd = demo->window;
2232
2233     err =
2234         vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2235
2236 #else  // _WIN32
2237         VkWaylandSurfaceCreateInfoKHR createInfo;
2238         createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2239         createInfo.pNext = NULL;
2240         createInfo.flags = 0;
2241         createInfo.display = demo->display;
2242         createInfo.surface = demo->wl_surface;
2243
2244         err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2245 #endif // _WIN32
2246
2247     // Iterate over each queue to learn whether it supports presenting:
2248     VkBool32 *supportsPresent =
2249         (VkBool32 *)malloc(demo->queue_count * sizeof(VkBool32));
2250     for (i = 0; i < demo->queue_count; i++) {
2251         demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
2252                                                    &supportsPresent[i]);
2253     }
2254
2255     // Search for a graphics and a present queue in the array of queue
2256     // families, try to find one that supports both
2257     uint32_t graphicsQueueNodeIndex = UINT32_MAX;
2258     uint32_t presentQueueNodeIndex = UINT32_MAX;
2259     for (i = 0; i < demo->queue_count; i++) {
2260         if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
2261             if (graphicsQueueNodeIndex == UINT32_MAX) {
2262                 graphicsQueueNodeIndex = i;
2263             }
2264
2265             if (supportsPresent[i] == VK_TRUE) {
2266                 graphicsQueueNodeIndex = i;
2267                 presentQueueNodeIndex = i;
2268                 break;
2269             }
2270         }
2271     }
2272     if (presentQueueNodeIndex == UINT32_MAX) {
2273         // If didn't find a queue that supports both graphics and present, then
2274         // find a separate present queue.
2275                 uint32_t i;
2276         for (i = 0; i < demo->queue_count; ++i) {
2277             if (supportsPresent[i] == VK_TRUE) {
2278                 presentQueueNodeIndex = i;
2279                 break;
2280             }
2281         }
2282     }
2283     free(supportsPresent);
2284
2285     // Generate error if could not find both a graphics and a present queue
2286     if (graphicsQueueNodeIndex == UINT32_MAX ||
2287         presentQueueNodeIndex == UINT32_MAX) {
2288         ERR_EXIT("Could not find a graphics and a present queue\n",
2289                  "Swapchain Initialization Failure");
2290     }
2291
2292     // TODO: Add support for separate queues, including presentation,
2293     //       synchronization, and appropriate tracking for QueueSubmit.
2294     // NOTE: While it is possible for an application to use a separate graphics
2295     //       and a present queues, this demo program assumes it is only using
2296     //       one:
2297     if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
2298         ERR_EXIT("Could not find a common graphics and a present queue\n",
2299                  "Swapchain Initialization Failure");
2300     }
2301
2302     demo->graphics_queue_node_index = graphicsQueueNodeIndex;
2303
2304     demo_init_device(demo);
2305
2306     vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index, 0,
2307                      &demo->queue);
2308
2309     // Get the list of VkFormat's that are supported:
2310     uint32_t formatCount;
2311     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2312                                                      &formatCount, NULL);
2313     assert(!err);
2314     VkSurfaceFormatKHR *surfFormats =
2315         (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
2316     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
2317                                                      &formatCount, surfFormats);
2318     assert(!err);
2319     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
2320     // the surface has no preferred format.  Otherwise, at least one
2321     // supported format will be returned.
2322     if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
2323         demo->format = VK_FORMAT_B8G8R8A8_UNORM;
2324     } else {
2325         assert(formatCount >= 1);
2326         demo->format = surfFormats[0].format;
2327     }
2328     demo->color_space = surfFormats[0].colorSpace;
2329
2330     demo->quit = false;
2331     demo->curFrame = 0;
2332
2333     // Get Memory information and properties
2334     vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
2335 }
2336
2337 static void
2338 registry_handle_global(void *data, struct wl_registry *registry,
2339                        uint32_t name, const char *interface, uint32_t version) {
2340         struct demo *d = data;
2341
2342         printf("%s, interface: %s\n", __func__, interface);
2343
2344         if (strcmp(interface, "wl_compositor") == 0) {
2345                 d->compositor =
2346                         wl_registry_bind(registry, name,
2347                                          &wl_compositor_interface, 1);
2348         } else if (strcmp(interface, "wl_shm") == 0) {
2349                 d->shm = wl_registry_bind(registry, name,
2350                                           &wl_shm_interface, 1);
2351         }  else if (strcmp(interface, "wl_shell") == 0) {
2352                 d->shell =
2353                         wl_registry_bind(registry, name,
2354                                          &wl_shell_interface, 1);
2355         }
2356 }
2357
2358 static void
2359 registry_handle_global_remove(void *data, struct wl_registry *registry,
2360                               uint32_t name) {
2361 }
2362
2363 static const struct wl_registry_listener registry_listener = {
2364         registry_handle_global,
2365         registry_handle_global_remove
2366 };
2367
2368 static void demo_init_connection(struct demo *demo) {
2369 #ifndef _WIN32
2370         demo->display = wl_display_connect(NULL);
2371
2372         if (demo->display == NULL) {
2373                 printf("Cannot find a compatible Vulkan installable client driver "
2374                        "(ICD).\nExiting ...\n");
2375                 fflush(stdout);
2376                 exit(1);
2377         }
2378
2379         demo->registry = wl_display_get_registry(demo->display);
2380         wl_registry_add_listener(demo->registry, &registry_listener, demo);
2381         wl_display_dispatch(demo->display);
2382 #endif // _WIN32
2383 }
2384
2385 static void demo_init(struct demo *demo, const int argc, const char *argv[])
2386 {
2387         int i;
2388
2389     memset(demo, 0, sizeof(*demo));
2390     demo->frameCount = INT32_MAX;
2391
2392     for (i = 1; i < argc; i++) {
2393         if (strcmp(argv[i], "--use_staging") == 0) {
2394             demo->use_staging_buffer = true;
2395             continue;
2396         }
2397         if (strcmp(argv[i], "--break") == 0) {
2398             demo->use_break = true;
2399             continue;
2400         }
2401         if (strcmp(argv[i], "--validate") == 0) {
2402             demo->validate = true;
2403             continue;
2404         }
2405         if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
2406             i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
2407             demo->frameCount >= 0) {
2408             i++;
2409             continue;
2410         }
2411
2412         fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] "
2413                         "[--c <framecount>]\n",
2414                 APP_SHORT_NAME);
2415         fflush(stderr);
2416         exit(1);
2417     }
2418
2419     demo_init_connection(demo);
2420     demo_init_vk(demo);
2421
2422     demo->width = 1440;
2423     demo->height = 2560;
2424     demo->depthStencil = 1.0;
2425     demo->depthIncrement = -0.01f;
2426 }
2427
2428 static void demo_cleanup(struct demo *demo) {
2429     uint32_t i;
2430
2431     demo->prepared = false;
2432
2433     for (i = 0; i < demo->swapchainImageCount; i++) {
2434         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2435     }
2436     free(demo->framebuffers);
2437     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2438
2439     if (demo->setup_cmd) {
2440         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2441     }
2442     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2443     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2444
2445     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2446     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2447     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2448     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2449
2450     vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2451     vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2452
2453     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2454         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2455         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2456         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2457         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2458     }
2459
2460     for (i = 0; i < demo->swapchainImageCount; i++) {
2461         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2462     }
2463
2464     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2465     vkDestroyImage(demo->device, demo->depth.image, NULL);
2466     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2467
2468     demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2469     free(demo->buffers);
2470
2471     vkDestroyDevice(demo->device, NULL);
2472     if (demo->validate) {
2473         demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2474     }
2475     vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2476     vkDestroyInstance(demo->inst, NULL);
2477
2478     free(demo->queue_props);
2479 }
2480
2481 static void demo_resize(struct demo *demo) {
2482     uint32_t i;
2483
2484     // Don't react to resize until after first initialization.
2485     if (!demo->prepared) {
2486         return;
2487     }
2488     // In order to properly resize the window, we must re-create the swapchain
2489     // AND redo the command buffers, etc.
2490     //
2491     // First, perform part of the demo_cleanup() function:
2492     demo->prepared = false;
2493
2494     for (i = 0; i < demo->swapchainImageCount; i++) {
2495         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2496     }
2497     free(demo->framebuffers);
2498     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2499
2500     if (demo->setup_cmd) {
2501         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->setup_cmd);
2502     }
2503     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, &demo->draw_cmd);
2504     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2505
2506     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2507     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2508     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2509     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2510
2511     vkDestroyBuffer(demo->device, demo->vertices.buf, NULL);
2512     vkFreeMemory(demo->device, demo->vertices.mem, NULL);
2513
2514     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2515         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2516         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2517         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2518         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2519     }
2520
2521     for (i = 0; i < demo->swapchainImageCount; i++) {
2522         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2523     }
2524
2525     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2526     vkDestroyImage(demo->device, demo->depth.image, NULL);
2527     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2528
2529     free(demo->buffers);
2530
2531     // Second, re-perform the demo_prepare() function, which will re-create the
2532     // swapchain:
2533     demo_prepare(demo);
2534 }
2535
2536 #ifdef _WIN32
2537 // Include header required for parsing the command line options.
2538 #include <shellapi.h>
2539
2540 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
2541                      LPSTR pCmdLine, int nCmdShow) {
2542     MSG msg;   // message
2543     bool done; // flag saying when app is complete
2544     int argc;
2545     char **argv;
2546
2547     // Use the CommandLine functions to get the command line arguments.
2548     // Unfortunately, Microsoft outputs
2549     // this information as wide characters for Unicode, and we simply want the
2550     // Ascii version to be compatible
2551     // with the non-Windows side.  So, we have to convert the information to
2552     // Ascii character strings.
2553     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
2554     if (NULL == commandLineArgs) {
2555         argc = 0;
2556     }
2557
2558     if (argc > 0) {
2559         argv = (char **)malloc(sizeof(char *) * argc);
2560         if (argv == NULL) {
2561             argc = 0;
2562         } else {
2563             for (int iii = 0; iii < argc; iii++) {
2564                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
2565                 size_t numConverted = 0;
2566
2567                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
2568                 if (argv[iii] != NULL) {
2569                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
2570                                commandLineArgs[iii], wideCharLen + 1);
2571                 }
2572             }
2573         }
2574     } else {
2575         argv = NULL;
2576     }
2577
2578     demo_init(&demo, argc, argv);
2579
2580     // Free up the items we had to allocate for the command line arguments.
2581     if (argc > 0 && argv != NULL) {
2582         for (int iii = 0; iii < argc; iii++) {
2583             if (argv[iii] != NULL) {
2584                 free(argv[iii]);
2585             }
2586         }
2587         free(argv);
2588     }
2589
2590     demo.connection = hInstance;
2591     strncpy(demo.name, "tri", APP_NAME_STR_LEN);
2592     demo_create_window(&demo);
2593     demo_init_vk_swapchain(&demo);
2594
2595     demo_prepare(&demo);
2596
2597     done = false; // initialize loop condition variable
2598     /* main message loop*/
2599     while (!done) {
2600         PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
2601         if (msg.message == WM_QUIT) // check for a quit message
2602         {
2603             done = true; // if found, quit app
2604         } else {
2605             /* Translate and dispatch to event queue*/
2606             TranslateMessage(&msg);
2607             DispatchMessage(&msg);
2608         }
2609         RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
2610     }
2611
2612     demo_cleanup(&demo);
2613
2614     return (int)msg.wParam;
2615 }
2616 #else  // _WIN32
2617 int main(const int argc, const char *argv[]) {
2618     struct demo demo;
2619
2620     demo_init(&demo, argc, argv);
2621     demo_create_window(&demo);
2622     demo_init_vk_swapchain(&demo);
2623
2624     demo_prepare(&demo);
2625     demo_run(&demo);
2626
2627     demo_cleanup(&demo);
2628
2629     return validation_error;
2630 }
2631 #endif // _WIN32