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