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