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