• 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 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Chia-I Wu <olv@lunarg.com>
19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
20 * Author: Ian Elliott <ian@LunarG.com>
21 * Author: Jon Ashburn <jon@lunarg.com>
22 * Author: Gwan-gyeong Mun <elongbug@gmail.com>
23 * Author: Tony Barbour <tony@LunarG.com>
24 */
25 
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdbool.h>
31 #include <assert.h>
32 #include <signal.h>
33 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
34 #include <X11/Xutil.h>
35 #endif
36 
37 #ifdef _WIN32
38 #pragma comment(linker, "/subsystem:windows")
39 #define APP_NAME_STR_LEN 80
40 #endif // _WIN32
41 
42 #ifdef ANDROID
43 #include "vulkan_wrapper.h"
44 #else
45 #include <vulkan/vulkan.h>
46 #endif
47 
48 #include <vulkan/vk_sdk_platform.h>
49 #include "linmath.h"
50 
51 #define DEMO_TEXTURE_COUNT 1
52 #define APP_SHORT_NAME "cube"
53 #define APP_LONG_NAME "The Vulkan Cube Demo Program"
54 
55 // Allow a maximum of two outstanding presentation operations.
56 #define FRAME_LAG 2
57 
58 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
59 
60 #if defined(NDEBUG) && defined(__GNUC__)
61 #define U_ASSERT_ONLY __attribute__((unused))
62 #else
63 #define U_ASSERT_ONLY
64 #endif
65 
66 #if defined(__GNUC__)
67 #define UNUSED __attribute__((unused))
68 #else
69 #define UNUSED
70 #endif
71 
72 #ifdef _WIN32
73 bool in_callback = false;
74 #define ERR_EXIT(err_msg, err_class)                                           \
75     do {                                                                       \
76         if (!demo->suppress_popups)                                            \
77             MessageBox(NULL, err_msg, err_class, MB_OK);                       \
78         exit(1);                                                               \
79     } while (0)
80 
81 #elif defined __ANDROID__
82 #include <android/log.h>
83 #define ERR_EXIT(err_msg, err_class)                                           \
84     do {                                                                       \
85         ((void)__android_log_print(ANDROID_LOG_INFO, "Cube", err_msg));        \
86         exit(1);                                                               \
87     } while (0)
88 #else
89 #define ERR_EXIT(err_msg, err_class)                                           \
90     do {                                                                       \
91         printf(err_msg);                                                       \
92         fflush(stdout);                                                        \
93         exit(1);                                                               \
94     } while (0)
95 #endif
96 
97 #define GET_INSTANCE_PROC_ADDR(inst, entrypoint)                               \
98     {                                                                          \
99         demo->fp##entrypoint =                                                 \
100             (PFN_vk##entrypoint)vkGetInstanceProcAddr(inst, "vk" #entrypoint); \
101         if (demo->fp##entrypoint == NULL) {                                    \
102             ERR_EXIT("vkGetInstanceProcAddr failed to find vk" #entrypoint,    \
103                      "vkGetInstanceProcAddr Failure");                         \
104         }                                                                      \
105     }
106 
107 static PFN_vkGetDeviceProcAddr g_gdpa = NULL;
108 
109 #define GET_DEVICE_PROC_ADDR(dev, entrypoint)                                  \
110     {                                                                          \
111         if (!g_gdpa)                                                           \
112             g_gdpa = (PFN_vkGetDeviceProcAddr)vkGetInstanceProcAddr(           \
113                 demo->inst, "vkGetDeviceProcAddr");                            \
114         demo->fp##entrypoint =                                                 \
115             (PFN_vk##entrypoint)g_gdpa(dev, "vk" #entrypoint);                 \
116         if (demo->fp##entrypoint == NULL) {                                    \
117             ERR_EXIT("vkGetDeviceProcAddr failed to find vk" #entrypoint,      \
118                      "vkGetDeviceProcAddr Failure");                           \
119         }                                                                      \
120     }
121 
122 /*
123  * structure to track all objects related to a texture.
124  */
125 struct texture_object {
126     VkSampler sampler;
127 
128     VkImage image;
129     VkImageLayout imageLayout;
130 
131     VkMemoryAllocateInfo mem_alloc;
132     VkDeviceMemory mem;
133     VkImageView view;
134     int32_t tex_width, tex_height;
135 };
136 
137 static char *tex_files[] = {"lunarg.ppm"};
138 
139 static int validation_error = 0;
140 
141 struct vkcube_vs_uniform {
142     // Must start with MVP
143     float mvp[4][4];
144     float position[12 * 3][4];
145     float color[12 * 3][4];
146 };
147 
148 struct vktexcube_vs_uniform {
149     // Must start with MVP
150     float mvp[4][4];
151     float position[12 * 3][4];
152     float attr[12 * 3][4];
153 };
154 
155 //--------------------------------------------------------------------------------------
156 // Mesh and VertexFormat Data
157 //--------------------------------------------------------------------------------------
158 // clang-format off
159 static const float g_vertex_buffer_data[] = {
160     -1.0f,-1.0f,-1.0f,  // -X side
161     -1.0f,-1.0f, 1.0f,
162     -1.0f, 1.0f, 1.0f,
163     -1.0f, 1.0f, 1.0f,
164     -1.0f, 1.0f,-1.0f,
165     -1.0f,-1.0f,-1.0f,
166 
167     -1.0f,-1.0f,-1.0f,  // -Z side
168      1.0f, 1.0f,-1.0f,
169      1.0f,-1.0f,-1.0f,
170     -1.0f,-1.0f,-1.0f,
171     -1.0f, 1.0f,-1.0f,
172      1.0f, 1.0f,-1.0f,
173 
174     -1.0f,-1.0f,-1.0f,  // -Y side
175      1.0f,-1.0f,-1.0f,
176      1.0f,-1.0f, 1.0f,
177     -1.0f,-1.0f,-1.0f,
178      1.0f,-1.0f, 1.0f,
179     -1.0f,-1.0f, 1.0f,
180 
181     -1.0f, 1.0f,-1.0f,  // +Y side
182     -1.0f, 1.0f, 1.0f,
183      1.0f, 1.0f, 1.0f,
184     -1.0f, 1.0f,-1.0f,
185      1.0f, 1.0f, 1.0f,
186      1.0f, 1.0f,-1.0f,
187 
188      1.0f, 1.0f,-1.0f,  // +X side
189      1.0f, 1.0f, 1.0f,
190      1.0f,-1.0f, 1.0f,
191      1.0f,-1.0f, 1.0f,
192      1.0f,-1.0f,-1.0f,
193      1.0f, 1.0f,-1.0f,
194 
195     -1.0f, 1.0f, 1.0f,  // +Z side
196     -1.0f,-1.0f, 1.0f,
197      1.0f, 1.0f, 1.0f,
198     -1.0f,-1.0f, 1.0f,
199      1.0f,-1.0f, 1.0f,
200      1.0f, 1.0f, 1.0f,
201 };
202 
203 static const float g_uv_buffer_data[] = {
204     0.0f, 1.0f,  // -X side
205     1.0f, 1.0f,
206     1.0f, 0.0f,
207     1.0f, 0.0f,
208     0.0f, 0.0f,
209     0.0f, 1.0f,
210 
211     1.0f, 1.0f,  // -Z side
212     0.0f, 0.0f,
213     0.0f, 1.0f,
214     1.0f, 1.0f,
215     1.0f, 0.0f,
216     0.0f, 0.0f,
217 
218     1.0f, 0.0f,  // -Y side
219     1.0f, 1.0f,
220     0.0f, 1.0f,
221     1.0f, 0.0f,
222     0.0f, 1.0f,
223     0.0f, 0.0f,
224 
225     1.0f, 0.0f,  // +Y side
226     0.0f, 0.0f,
227     0.0f, 1.0f,
228     1.0f, 0.0f,
229     0.0f, 1.0f,
230     1.0f, 1.0f,
231 
232     1.0f, 0.0f,  // +X side
233     0.0f, 0.0f,
234     0.0f, 1.0f,
235     0.0f, 1.0f,
236     1.0f, 1.0f,
237     1.0f, 0.0f,
238 
239     0.0f, 0.0f,  // +Z side
240     0.0f, 1.0f,
241     1.0f, 0.0f,
242     0.0f, 1.0f,
243     1.0f, 1.0f,
244     1.0f, 0.0f,
245 };
246 // clang-format on
247 
dumpMatrix(const char * note,mat4x4 MVP)248 void dumpMatrix(const char *note, mat4x4 MVP) {
249     int i;
250 
251     printf("%s: \n", note);
252     for (i = 0; i < 4; i++) {
253         printf("%f, %f, %f, %f\n", MVP[i][0], MVP[i][1], MVP[i][2], MVP[i][3]);
254     }
255     printf("\n");
256     fflush(stdout);
257 }
258 
dumpVec4(const char * note,vec4 vector)259 void dumpVec4(const char *note, vec4 vector) {
260     printf("%s: \n", note);
261     printf("%f, %f, %f, %f\n", vector[0], vector[1], vector[2], vector[3]);
262     printf("\n");
263     fflush(stdout);
264 }
265 
266 VKAPI_ATTR VkBool32 VKAPI_CALL
BreakCallback(VkFlags msgFlags,VkDebugReportObjectTypeEXT objType,uint64_t srcObject,size_t location,int32_t msgCode,const char * pLayerPrefix,const char * pMsg,void * pUserData)267 BreakCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
268               uint64_t srcObject, size_t location, int32_t msgCode,
269               const char *pLayerPrefix, const char *pMsg,
270               void *pUserData) {
271 #ifndef WIN32
272     raise(SIGTRAP);
273 #else
274     DebugBreak();
275 #endif
276 
277     return false;
278 }
279 
280 typedef struct {
281     VkImage image;
282     VkCommandBuffer cmd;
283     VkCommandBuffer graphics_to_present_cmd;
284     VkImageView view;
285 } SwapchainBuffers;
286 
287 struct demo {
288 #if defined(VK_USE_PLATFORM_WIN32_KHR)
289 #define APP_NAME_STR_LEN 80
290     HINSTANCE connection;        // hInstance - Windows Instance
291     char name[APP_NAME_STR_LEN]; // Name to put on the window/icon
292     HWND window;                 // hWnd - window handle
293     POINT minsize;               // minimum window size
294 #elif defined(VK_USE_PLATFORM_XLIB_KHR) | defined(VK_USE_PLATFORM_XCB_KHR)
295     Display* display;
296     Window xlib_window;
297     Atom xlib_wm_delete_window;
298 
299     xcb_connection_t *connection;
300     xcb_screen_t *screen;
301     xcb_window_t xcb_window;
302     xcb_intern_atom_reply_t *atom_wm_delete_window;
303 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
304     struct wl_display *display;
305     struct wl_registry *registry;
306     struct wl_compositor *compositor;
307     struct wl_surface *window;
308     struct wl_shell *shell;
309     struct wl_shell_surface *shell_surface;
310 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
311     ANativeWindow* window;
312 #endif
313     VkSurfaceKHR surface;
314     bool prepared;
315     bool use_staging_buffer;
316     bool use_xlib;
317     bool separate_present_queue;
318 
319     VkInstance inst;
320     VkPhysicalDevice gpu;
321     VkDevice device;
322     VkQueue graphics_queue;
323     VkQueue present_queue;
324     uint32_t graphics_queue_family_index;
325     uint32_t present_queue_family_index;
326     VkSemaphore image_acquired_semaphores[FRAME_LAG];
327     VkSemaphore draw_complete_semaphores[FRAME_LAG];
328     VkSemaphore image_ownership_semaphores[FRAME_LAG];
329     VkPhysicalDeviceProperties gpu_props;
330     VkQueueFamilyProperties *queue_props;
331     VkPhysicalDeviceMemoryProperties memory_properties;
332 
333     uint32_t enabled_extension_count;
334     uint32_t enabled_layer_count;
335     char *extension_names[64];
336     char *enabled_layers[64];
337 
338     int width, height;
339     VkFormat format;
340     VkColorSpaceKHR color_space;
341 
342     PFN_vkGetPhysicalDeviceSurfaceSupportKHR
343         fpGetPhysicalDeviceSurfaceSupportKHR;
344     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
345         fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
346     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR
347         fpGetPhysicalDeviceSurfaceFormatsKHR;
348     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR
349         fpGetPhysicalDeviceSurfacePresentModesKHR;
350     PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
351     PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
352     PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
353     PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
354     PFN_vkQueuePresentKHR fpQueuePresentKHR;
355     uint32_t swapchainImageCount;
356     VkSwapchainKHR swapchain;
357     SwapchainBuffers *buffers;
358     VkFence fences[FRAME_LAG];
359     int frame_index;
360 
361     VkCommandPool cmd_pool;
362     VkCommandPool present_cmd_pool;
363 
364     struct {
365         VkFormat format;
366 
367         VkImage image;
368         VkMemoryAllocateInfo mem_alloc;
369         VkDeviceMemory mem;
370         VkImageView view;
371     } depth;
372 
373     struct texture_object textures[DEMO_TEXTURE_COUNT];
374 
375     struct {
376         VkBuffer buf;
377         VkMemoryAllocateInfo mem_alloc;
378         VkDeviceMemory mem;
379         VkDescriptorBufferInfo buffer_info;
380     } uniform_data;
381 
382     VkCommandBuffer cmd; // Buffer for initialization commands
383     VkPipelineLayout pipeline_layout;
384     VkDescriptorSetLayout desc_layout;
385     VkPipelineCache pipelineCache;
386     VkRenderPass render_pass;
387     VkPipeline pipeline;
388 
389     mat4x4 projection_matrix;
390     mat4x4 view_matrix;
391     mat4x4 model_matrix;
392 
393     float spin_angle;
394     float spin_increment;
395     bool pause;
396 
397     VkShaderModule vert_shader_module;
398     VkShaderModule frag_shader_module;
399 
400     VkDescriptorPool desc_pool;
401     VkDescriptorSet desc_set;
402 
403     VkFramebuffer *framebuffers;
404 
405     bool quit;
406     int32_t curFrame;
407     int32_t frameCount;
408     bool validate;
409     bool use_break;
410     bool suppress_popups;
411     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
412     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
413     VkDebugReportCallbackEXT msg_callback;
414     PFN_vkDebugReportMessageEXT DebugReportMessage;
415 
416     uint32_t current_buffer;
417     uint32_t queue_family_count;
418 };
419 
420 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)421 dbgFunc(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
422     uint64_t srcObject, size_t location, int32_t msgCode,
423     const char *pLayerPrefix, const char *pMsg, void *pUserData) {
424 
425     // clang-format off
426     char *message = (char *)malloc(strlen(pMsg) + 100);
427 
428     assert(message);
429 
430     // We know we're submitting queues without fences, ignore this
431     if (strstr(pMsg, "vkQueueSubmit parameter, VkFence fence, is null pointer"))
432         return false;
433 
434     if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
435         sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
436         validation_error = 1;
437     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
438         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
439         validation_error = 1;
440     } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
441         sprintf(message, "PERFORMANCE WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
442         validation_error = 1;
443     } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
444         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
445         validation_error = 1;
446     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
447         sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
448         validation_error = 1;
449     } else {
450         sprintf(message, "INFORMATION: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
451         validation_error = 1;
452     }
453 
454 #ifdef _WIN32
455 
456     in_callback = true;
457     struct demo *demo = (struct demo*) pUserData;
458     if (!demo->suppress_popups)
459         MessageBox(NULL, message, "Alert", MB_OK);
460     in_callback = false;
461 
462 #elif defined(ANDROID)
463 
464     if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
465         __android_log_print(ANDROID_LOG_INFO,  APP_SHORT_NAME, "%s", message);
466     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
467         __android_log_print(ANDROID_LOG_WARN,  APP_SHORT_NAME, "%s", message);
468     } else if (msgFlags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT) {
469         __android_log_print(ANDROID_LOG_WARN,  APP_SHORT_NAME, "%s", message);
470     } else if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
471         __android_log_print(ANDROID_LOG_ERROR, APP_SHORT_NAME, "%s", message);
472     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
473         __android_log_print(ANDROID_LOG_DEBUG, APP_SHORT_NAME, "%s", message);
474     } else {
475         __android_log_print(ANDROID_LOG_INFO,  APP_SHORT_NAME, "%s", message);
476     }
477 
478 #else
479 
480     printf("%s\n", message);
481     fflush(stdout);
482 
483 #endif
484 
485     free(message);
486 
487     //clang-format on
488 
489     /*
490     * false indicates that layer should not bail-out of an
491     * API call that had validation failures. This may mean that the
492     * app dies inside the driver due to invalid parameter(s).
493     * That's what would happen without validation layers, so we'll
494     * keep that behavior here.
495     */
496     return false;
497 }
498 
499 // Forward declaration:
500 static void demo_resize(struct demo *demo);
501 
memory_type_from_properties(struct demo * demo,uint32_t typeBits,VkFlags requirements_mask,uint32_t * typeIndex)502 static bool memory_type_from_properties(struct demo *demo, uint32_t typeBits,
503                                         VkFlags requirements_mask,
504                                         uint32_t *typeIndex) {
505     // Search memtypes to find first index with those properties
506     for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; i++) {
507         if ((typeBits & 1) == 1) {
508             // Type is available, does it match user properties?
509             if ((demo->memory_properties.memoryTypes[i].propertyFlags &
510                  requirements_mask) == requirements_mask) {
511                 *typeIndex = i;
512                 return true;
513             }
514         }
515         typeBits >>= 1;
516     }
517     // No memory types matched, return failure
518     return false;
519 }
520 
demo_flush_init_cmd(struct demo * demo)521 static void demo_flush_init_cmd(struct demo *demo) {
522     VkResult U_ASSERT_ONLY err;
523 
524     // This function could get called twice if the texture uses a staging buffer
525     // In that case the second call should be ignored
526     if (demo->cmd == VK_NULL_HANDLE)
527         return;
528 
529     err = vkEndCommandBuffer(demo->cmd);
530     assert(!err);
531 
532     VkFence fence;
533     VkFenceCreateInfo fence_ci = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
534                                   .pNext = NULL,
535                                   .flags = 0};
536     vkCreateFence(demo->device, &fence_ci, NULL, &fence);
537     const VkCommandBuffer cmd_bufs[] = {demo->cmd};
538     VkSubmitInfo submit_info = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
539                                 .pNext = NULL,
540                                 .waitSemaphoreCount = 0,
541                                 .pWaitSemaphores = NULL,
542                                 .pWaitDstStageMask = NULL,
543                                 .commandBufferCount = 1,
544                                 .pCommandBuffers = cmd_bufs,
545                                 .signalSemaphoreCount = 0,
546                                 .pSignalSemaphores = NULL};
547 
548     err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence);
549     assert(!err);
550 
551     err = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX);
552     assert(!err);
553 
554     vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1, cmd_bufs);
555     vkDestroyFence(demo->device, fence, NULL);
556     demo->cmd = VK_NULL_HANDLE;
557 }
558 
demo_set_image_layout(struct demo * demo,VkImage image,VkImageAspectFlags aspectMask,VkImageLayout old_image_layout,VkImageLayout new_image_layout,VkAccessFlagBits srcAccessMask,VkPipelineStageFlags src_stages,VkPipelineStageFlags dest_stages)559 static void demo_set_image_layout(struct demo *demo, VkImage image,
560                                   VkImageAspectFlags aspectMask,
561                                   VkImageLayout old_image_layout,
562                                   VkImageLayout new_image_layout,
563                                   VkAccessFlagBits srcAccessMask,
564                                   VkPipelineStageFlags src_stages,
565                                   VkPipelineStageFlags dest_stages) {
566     VkResult U_ASSERT_ONLY err;
567 
568     if (demo->cmd == VK_NULL_HANDLE) {
569         const VkCommandBufferAllocateInfo cmd = {
570             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
571             .pNext = NULL,
572             .commandPool = demo->cmd_pool,
573             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
574             .commandBufferCount = 1,
575         };
576 
577         err = vkAllocateCommandBuffers(demo->device, &cmd, &demo->cmd);
578         assert(!err);
579         VkCommandBufferBeginInfo cmd_buf_info = {
580             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
581             .pNext = NULL,
582             .flags = 0,
583             .pInheritanceInfo = NULL,
584         };
585         err = vkBeginCommandBuffer(demo->cmd, &cmd_buf_info);
586         assert(!err);
587     }
588 
589     VkImageMemoryBarrier image_memory_barrier = {
590         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
591         .pNext = NULL,
592         .srcAccessMask = srcAccessMask,
593         .dstAccessMask = 0,
594         .oldLayout = old_image_layout,
595         .newLayout = new_image_layout,
596         .image = image,
597         .subresourceRange = {aspectMask, 0, 1, 0, 1}};
598 
599     switch (new_image_layout) {
600     case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
601         /* Make sure anything that was copying from this image has completed */
602         image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
603         break;
604 
605     case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
606         image_memory_barrier.dstAccessMask =
607             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
608         break;
609 
610     case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
611         image_memory_barrier.dstAccessMask =
612             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
613         break;
614 
615     case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
616         image_memory_barrier.dstAccessMask =
617             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
618         break;
619 
620     case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
621         image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
622         break;
623 
624     case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
625         image_memory_barrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
626         break;
627 
628     default:
629         image_memory_barrier.dstAccessMask = 0;
630         break;
631     }
632 
633 
634     VkImageMemoryBarrier *pmemory_barrier = &image_memory_barrier;
635 
636     vkCmdPipelineBarrier(demo->cmd, src_stages, dest_stages, 0, 0, NULL, 0,
637                          NULL, 1, pmemory_barrier);
638 }
639 
demo_draw_build_cmd(struct demo * demo,VkCommandBuffer cmd_buf)640 static void demo_draw_build_cmd(struct demo *demo, VkCommandBuffer cmd_buf) {
641     const VkCommandBufferBeginInfo cmd_buf_info = {
642         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
643         .pNext = NULL,
644         .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
645         .pInheritanceInfo = NULL,
646     };
647     const VkClearValue clear_values[2] = {
648             [0] = {.color.float32 = {0.2f, 0.2f, 0.2f, 0.2f}},
649             [1] = {.depthStencil = {1.0f, 0}},
650     };
651     const VkRenderPassBeginInfo rp_begin = {
652         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
653         .pNext = NULL,
654         .renderPass = demo->render_pass,
655         .framebuffer = demo->framebuffers[demo->current_buffer],
656         .renderArea.offset.x = 0,
657         .renderArea.offset.y = 0,
658         .renderArea.extent.width = demo->width,
659         .renderArea.extent.height = demo->height,
660         .clearValueCount = 2,
661         .pClearValues = clear_values,
662     };
663     VkResult U_ASSERT_ONLY err;
664 
665     err = vkBeginCommandBuffer(cmd_buf, &cmd_buf_info);
666     assert(!err);
667     vkCmdBeginRenderPass(cmd_buf, &rp_begin, VK_SUBPASS_CONTENTS_INLINE);
668     vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, demo->pipeline);
669     vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS,
670                             demo->pipeline_layout, 0, 1, &demo->desc_set, 0,
671                             NULL);
672     VkViewport viewport;
673     memset(&viewport, 0, sizeof(viewport));
674     viewport.height = (float)demo->height;
675     viewport.width = (float)demo->width;
676     viewport.minDepth = (float)0.0f;
677     viewport.maxDepth = (float)1.0f;
678     vkCmdSetViewport(cmd_buf, 0, 1, &viewport);
679 
680     VkRect2D scissor;
681     memset(&scissor, 0, sizeof(scissor));
682     scissor.extent.width = demo->width;
683     scissor.extent.height = demo->height;
684     scissor.offset.x = 0;
685     scissor.offset.y = 0;
686     vkCmdSetScissor(cmd_buf, 0, 1, &scissor);
687     vkCmdDraw(cmd_buf, 12 * 3, 1, 0, 0);
688     // Note that ending the renderpass changes the image's layout from
689     // COLOR_ATTACHMENT_OPTIMAL to PRESENT_SRC_KHR
690     vkCmdEndRenderPass(cmd_buf);
691 
692     if (demo->separate_present_queue) {
693         // We have to transfer ownership from the graphics queue family to the
694         // present queue family to be able to present.  Note that we don't have
695         // to transfer from present queue family back to graphics queue family at
696         // the start of the next frame because we don't care about the image's
697         // contents at that point.
698         VkImageMemoryBarrier image_ownership_barrier = {
699             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
700             .pNext = NULL,
701             .srcAccessMask = 0,
702             .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
703             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
704             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
705             .srcQueueFamilyIndex = demo->graphics_queue_family_index,
706             .dstQueueFamilyIndex = demo->present_queue_family_index,
707             .image = demo->buffers[demo->current_buffer].image,
708             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
709 
710         vkCmdPipelineBarrier(cmd_buf,
711                              VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
712                              VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0,
713                              0, NULL, 0, NULL, 1, &image_ownership_barrier);
714     }
715     err = vkEndCommandBuffer(cmd_buf);
716     assert(!err);
717 }
718 
demo_build_image_ownership_cmd(struct demo * demo,int i)719 void demo_build_image_ownership_cmd(struct demo *demo, int i) {
720     VkResult U_ASSERT_ONLY err;
721 
722     const VkCommandBufferBeginInfo cmd_buf_info = {
723         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
724         .pNext = NULL,
725         .flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
726         .pInheritanceInfo = NULL,
727     };
728     err = vkBeginCommandBuffer(demo->buffers[i].graphics_to_present_cmd,
729                                &cmd_buf_info);
730     assert(!err);
731 
732     VkImageMemoryBarrier image_ownership_barrier = {
733         .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
734         .pNext = NULL,
735         .srcAccessMask = 0,
736         .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
737         .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
738         .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
739         .srcQueueFamilyIndex = demo->graphics_queue_family_index,
740         .dstQueueFamilyIndex = demo->present_queue_family_index,
741         .image = demo->buffers[i].image,
742         .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}};
743 
744     vkCmdPipelineBarrier(demo->buffers[i].graphics_to_present_cmd,
745                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
746                          VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0,
747                          NULL, 0, NULL, 1, &image_ownership_barrier);
748     err = vkEndCommandBuffer(demo->buffers[i].graphics_to_present_cmd);
749     assert(!err);
750 }
751 
demo_update_data_buffer(struct demo * demo)752 void demo_update_data_buffer(struct demo *demo) {
753     mat4x4 MVP, Model, VP;
754     int matrixSize = sizeof(MVP);
755     uint8_t *pData;
756     VkResult U_ASSERT_ONLY err;
757 
758     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
759 
760     // Rotate 22.5 degrees around the Y axis
761     mat4x4_dup(Model, demo->model_matrix);
762     mat4x4_rotate(demo->model_matrix, Model, 0.0f, 1.0f, 0.0f,
763                   (float)degreesToRadians(demo->spin_angle));
764     mat4x4_mul(MVP, VP, demo->model_matrix);
765 
766     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
767                       demo->uniform_data.mem_alloc.allocationSize, 0,
768                       (void **)&pData);
769     assert(!err);
770 
771     memcpy(pData, (const void *)&MVP[0][0], matrixSize);
772 
773     vkUnmapMemory(demo->device, demo->uniform_data.mem);
774 }
775 
demo_draw(struct demo * demo)776 static void demo_draw(struct demo *demo) {
777     VkResult U_ASSERT_ONLY err;
778 
779     // Ensure no more than FRAME_LAG presentations are outstanding
780     vkWaitForFences(demo->device, 1, &demo->fences[demo->frame_index], VK_TRUE, UINT64_MAX);
781     vkResetFences(demo->device, 1, &demo->fences[demo->frame_index]);
782 
783     // Get the index of the next available swapchain image:
784     err = demo->fpAcquireNextImageKHR(demo->device, demo->swapchain, UINT64_MAX,
785                                       demo->image_acquired_semaphores[demo->frame_index], demo->fences[demo->frame_index],
786                                       &demo->current_buffer);
787 
788     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
789         // demo->swapchain is out of date (e.g. the window was resized) and
790         // must be recreated:
791         demo->frame_index += 1;
792         demo->frame_index %= FRAME_LAG;
793 
794         demo_resize(demo);
795         demo_draw(demo);
796         return;
797     } else if (err == VK_SUBOPTIMAL_KHR) {
798         // demo->swapchain is not as optimal as it could be, but the platform's
799         // presentation engine will still present the image correctly.
800     } else {
801         assert(!err);
802     }
803     // Wait for the image acquired semaphore to be signaled to ensure
804     // that the image won't be rendered to until the presentation
805     // engine has fully released ownership to the application, and it is
806     // okay to render to the image.
807     VkFence nullFence = VK_NULL_HANDLE;
808     VkPipelineStageFlags pipe_stage_flags;
809     VkSubmitInfo submit_info;
810     submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
811     submit_info.pNext = NULL;
812     submit_info.pWaitDstStageMask = &pipe_stage_flags;
813     pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
814     submit_info.waitSemaphoreCount = 1;
815     submit_info.pWaitSemaphores = &demo->image_acquired_semaphores[demo->frame_index];
816     submit_info.commandBufferCount = 1;
817     submit_info.pCommandBuffers = &demo->buffers[demo->current_buffer].cmd;
818     submit_info.signalSemaphoreCount = 1;
819     submit_info.pSignalSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
820     err = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, nullFence);
821     assert(!err);
822 
823     if (demo->separate_present_queue) {
824         // If we are using separate queues, change image ownership to the
825         // present queue before presenting, waiting for the draw complete
826         // semaphore and signalling the ownership released semaphore when finished
827         pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
828         submit_info.waitSemaphoreCount = 1;
829         submit_info.pWaitSemaphores = &demo->draw_complete_semaphores[demo->frame_index];
830         submit_info.commandBufferCount = 1;
831         submit_info.pCommandBuffers =
832             &demo->buffers[demo->current_buffer].graphics_to_present_cmd;
833         submit_info.signalSemaphoreCount = 1;
834         submit_info.pSignalSemaphores = &demo->image_ownership_semaphores[demo->frame_index];
835         err = vkQueueSubmit(demo->present_queue, 1, &submit_info, nullFence);
836         assert(!err);
837     }
838 
839     // If we are using separate queues we have to wait for image ownership,
840     // otherwise wait for draw complete
841     VkPresentInfoKHR present = {
842         .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
843         .pNext = NULL,
844         .waitSemaphoreCount = 1,
845         .pWaitSemaphores = (demo->separate_present_queue)
846                                ? &demo->image_ownership_semaphores[demo->frame_index]
847                                : &demo->draw_complete_semaphores[demo->frame_index],
848         .swapchainCount = 1,
849         .pSwapchains = &demo->swapchain,
850         .pImageIndices = &demo->current_buffer,
851     };
852 
853     err = demo->fpQueuePresentKHR(demo->present_queue, &present);
854     demo->frame_index += 1;
855     demo->frame_index %= FRAME_LAG;
856 
857     if (err == VK_ERROR_OUT_OF_DATE_KHR) {
858         // demo->swapchain is out of date (e.g. the window was resized) and
859         // must be recreated:
860         demo_resize(demo);
861     } else if (err == VK_SUBOPTIMAL_KHR) {
862         // demo->swapchain is not as optimal as it could be, but the platform's
863         // presentation engine will still present the image correctly.
864     } else {
865         assert(!err);
866     }
867 }
868 
demo_prepare_buffers(struct demo * demo)869 static void demo_prepare_buffers(struct demo *demo) {
870     VkResult U_ASSERT_ONLY err;
871     VkSwapchainKHR oldSwapchain = demo->swapchain;
872 
873     // Check the surface capabilities and formats
874     VkSurfaceCapabilitiesKHR surfCapabilities;
875     err = demo->fpGetPhysicalDeviceSurfaceCapabilitiesKHR(
876         demo->gpu, demo->surface, &surfCapabilities);
877     assert(!err);
878 
879     uint32_t presentModeCount;
880     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
881         demo->gpu, demo->surface, &presentModeCount, NULL);
882     assert(!err);
883     VkPresentModeKHR *presentModes =
884         (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
885     assert(presentModes);
886     err = demo->fpGetPhysicalDeviceSurfacePresentModesKHR(
887         demo->gpu, demo->surface, &presentModeCount, presentModes);
888     assert(!err);
889 
890     VkExtent2D swapchainExtent;
891     // width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
892     if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
893         // If the surface size is undefined, the size is set to the size
894         // of the images requested, which must fit within the minimum and
895         // maximum values.
896         swapchainExtent.width = demo->width;
897         swapchainExtent.height = demo->height;
898 
899         if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
900             swapchainExtent.width = surfCapabilities.minImageExtent.width;
901         } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) {
902             swapchainExtent.width = surfCapabilities.maxImageExtent.width;
903         }
904 
905         if (swapchainExtent.height < surfCapabilities.minImageExtent.height) {
906             swapchainExtent.height = surfCapabilities.minImageExtent.height;
907         } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {
908             swapchainExtent.height = surfCapabilities.maxImageExtent.height;
909         }
910     } else {
911         // If the surface size is defined, the swap chain size must match
912         swapchainExtent = surfCapabilities.currentExtent;
913         demo->width = surfCapabilities.currentExtent.width;
914         demo->height = surfCapabilities.currentExtent.height;
915     }
916 
917     // The FIFO present mode is guaranteed by the spec to be supported
918     // and to have no tearing.  It's a great default present mode to use.
919     VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
920     //  There are times when you may wish to use another present mode.  The
921     //  following code shows how to select them, and the comments provide some
922     //  reasons you may wish to use them.
923     //
924     // It should be noted that Vulkan 1.0 doesn't provide a method for
925     // synchronizing rendering with the presentation engine's display.  There
926     // is a method provided for throttling rendering with the display, but
927     // there are some presentation engines for which this method will not work.
928     // If an application doesn't throttle its rendering, and if it renders much
929     // faster than the refresh rate of the display, this can waste power on
930     // mobile devices.  That is because power is being spent rendering images
931     // that may never be seen.
932 //#define DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR
933 //#define DESIRE_VK_PRESENT_MODE_MAILBOX_KHR
934 //#define DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR
935 #if defined(DESIRE_VK_PRESENT_MODE_IMMEDIATE_KHR)
936     // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
937     // tearing, or have some way of synchronizing their rendering with the
938     // display.
939     for (size_t i = 0; i < presentModeCount; ++i) {
940         if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
941             swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
942             break;
943         }
944     }
945 #elif defined(DESIRE_VK_PRESENT_MODE_MAILBOX_KHR)
946     // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
947     // generally render a new presentable image every refresh cycle, but are
948     // occasionally early.  In this case, the application wants the new image
949     // to be displayed instead of the previously-queued-for-presentation image
950     // that has not yet been displayed.
951     for (size_t i = 0; i < presentModeCount; ++i) {
952         if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
953             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
954             break;
955         }
956     }
957 #elif defined(DESIRE_VK_PRESENT_MODE_FIFO_RELAXED_KHR)
958     // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
959     // render a new presentable image every refresh cycle, but are occasionally
960     // late.  In this case (perhaps because of stuttering/latency concerns),
961     // the application wants the late image to be immediately displayed, even
962     // though that may mean some tearing.
963     for (size_t i = 0; i < presentModeCount; ++i) {
964         if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
965             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
966             break;
967         }
968     }
969 #endif
970 
971     // Determine the number of VkImage's to use in the swap chain.
972     // Application desires to only acquire 1 image at a time (which is
973     // "surfCapabilities.minImageCount").
974     uint32_t desiredNumOfSwapchainImages = surfCapabilities.minImageCount;
975     // If maxImageCount is 0, we can ask for as many images as we want;
976     // otherwise we're limited to maxImageCount
977     if ((surfCapabilities.maxImageCount > 0) &&
978         (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
979         // Application must settle for fewer images than desired:
980         desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
981     }
982 
983     VkSurfaceTransformFlagsKHR preTransform;
984     if (surfCapabilities.supportedTransforms &
985         VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
986         preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
987     } else {
988         preTransform = surfCapabilities.currentTransform;
989     }
990 
991     VkSwapchainCreateInfoKHR swapchain_ci = {
992         .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
993         .pNext = NULL,
994         .surface = demo->surface,
995         .minImageCount = desiredNumOfSwapchainImages,
996         .imageFormat = demo->format,
997         .imageColorSpace = demo->color_space,
998         .imageExtent =
999             {
1000              .width = swapchainExtent.width, .height = swapchainExtent.height,
1001             },
1002         .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1003         .preTransform = preTransform,
1004         .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
1005         .imageArrayLayers = 1,
1006         .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
1007         .queueFamilyIndexCount = 0,
1008         .pQueueFamilyIndices = NULL,
1009         .presentMode = swapchainPresentMode,
1010         .oldSwapchain = oldSwapchain,
1011         .clipped = true,
1012     };
1013     uint32_t i;
1014     err = demo->fpCreateSwapchainKHR(demo->device, &swapchain_ci, NULL,
1015                                      &demo->swapchain);
1016     assert(!err);
1017 
1018     // If we just re-created an existing swapchain, we should destroy the old
1019     // swapchain at this point.
1020     // Note: destroying the swapchain also cleans up all its associated
1021     // presentable images once the platform is done with them.
1022     if (oldSwapchain != VK_NULL_HANDLE) {
1023         demo->fpDestroySwapchainKHR(demo->device, oldSwapchain, NULL);
1024     }
1025 
1026     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
1027                                         &demo->swapchainImageCount, NULL);
1028     assert(!err);
1029 
1030     VkImage *swapchainImages =
1031         (VkImage *)malloc(demo->swapchainImageCount * sizeof(VkImage));
1032     assert(swapchainImages);
1033     err = demo->fpGetSwapchainImagesKHR(demo->device, demo->swapchain,
1034                                         &demo->swapchainImageCount,
1035                                         swapchainImages);
1036     assert(!err);
1037 
1038     demo->buffers = (SwapchainBuffers *)malloc(sizeof(SwapchainBuffers) *
1039                                                demo->swapchainImageCount);
1040     assert(demo->buffers);
1041 
1042     for (i = 0; i < demo->swapchainImageCount; i++) {
1043         VkImageViewCreateInfo color_image_view = {
1044             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1045             .pNext = NULL,
1046             .format = demo->format,
1047             .components =
1048                 {
1049                  .r = VK_COMPONENT_SWIZZLE_R,
1050                  .g = VK_COMPONENT_SWIZZLE_G,
1051                  .b = VK_COMPONENT_SWIZZLE_B,
1052                  .a = VK_COMPONENT_SWIZZLE_A,
1053                 },
1054             .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1055                                  .baseMipLevel = 0,
1056                                  .levelCount = 1,
1057                                  .baseArrayLayer = 0,
1058                                  .layerCount = 1},
1059             .viewType = VK_IMAGE_VIEW_TYPE_2D,
1060             .flags = 0,
1061         };
1062 
1063         demo->buffers[i].image = swapchainImages[i];
1064 
1065         color_image_view.image = demo->buffers[i].image;
1066 
1067         err = vkCreateImageView(demo->device, &color_image_view, NULL,
1068                                 &demo->buffers[i].view);
1069         assert(!err);
1070 
1071     }
1072 
1073     if (NULL != presentModes) {
1074         free(presentModes);
1075     }
1076 }
1077 
demo_prepare_depth(struct demo * demo)1078 static void demo_prepare_depth(struct demo *demo) {
1079     const VkFormat depth_format = VK_FORMAT_D16_UNORM;
1080     const VkImageCreateInfo image = {
1081         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1082         .pNext = NULL,
1083         .imageType = VK_IMAGE_TYPE_2D,
1084         .format = depth_format,
1085         .extent = {demo->width, demo->height, 1},
1086         .mipLevels = 1,
1087         .arrayLayers = 1,
1088         .samples = VK_SAMPLE_COUNT_1_BIT,
1089         .tiling = VK_IMAGE_TILING_OPTIMAL,
1090         .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
1091         .flags = 0,
1092     };
1093 
1094     VkImageViewCreateInfo view = {
1095         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1096         .pNext = NULL,
1097         .image = VK_NULL_HANDLE,
1098         .format = depth_format,
1099         .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
1100                              .baseMipLevel = 0,
1101                              .levelCount = 1,
1102                              .baseArrayLayer = 0,
1103                              .layerCount = 1},
1104         .flags = 0,
1105         .viewType = VK_IMAGE_VIEW_TYPE_2D,
1106     };
1107 
1108     VkMemoryRequirements mem_reqs;
1109     VkResult U_ASSERT_ONLY err;
1110     bool U_ASSERT_ONLY pass;
1111 
1112     demo->depth.format = depth_format;
1113 
1114     /* create image */
1115     err = vkCreateImage(demo->device, &image, NULL, &demo->depth.image);
1116     assert(!err);
1117 
1118     vkGetImageMemoryRequirements(demo->device, demo->depth.image, &mem_reqs);
1119     assert(!err);
1120 
1121     demo->depth.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1122     demo->depth.mem_alloc.pNext = NULL;
1123     demo->depth.mem_alloc.allocationSize = mem_reqs.size;
1124     demo->depth.mem_alloc.memoryTypeIndex = 0;
1125 
1126     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
1127                                        0, /* No requirements */
1128                                        &demo->depth.mem_alloc.memoryTypeIndex);
1129     assert(pass);
1130 
1131     /* allocate memory */
1132     err = vkAllocateMemory(demo->device, &demo->depth.mem_alloc, NULL,
1133                            &demo->depth.mem);
1134     assert(!err);
1135 
1136     /* bind memory */
1137     err =
1138         vkBindImageMemory(demo->device, demo->depth.image, demo->depth.mem, 0);
1139     assert(!err);
1140 
1141     /* create image view */
1142     view.image = demo->depth.image;
1143     err = vkCreateImageView(demo->device, &view, NULL, &demo->depth.view);
1144     assert(!err);
1145 }
1146 
1147 /* Load a ppm file into memory */
loadTexture(const char * filename,uint8_t * rgba_data,VkSubresourceLayout * layout,int32_t * width,int32_t * height)1148 bool loadTexture(const char *filename, uint8_t *rgba_data,
1149                  VkSubresourceLayout *layout, int32_t *width, int32_t *height) {
1150 #ifdef __ANDROID__
1151 #include <lunarg.ppm.h>
1152     char *cPtr;
1153     cPtr = (char*)lunarg_ppm;
1154     if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "P6\n", 3)) {
1155         return false;
1156     }
1157     while(strncmp(cPtr++, "\n", 1));
1158     sscanf(cPtr, "%u %u", width, height);
1159     if (rgba_data == NULL) {
1160         return true;
1161     }
1162     while(strncmp(cPtr++, "\n", 1));
1163     if ((unsigned char*)cPtr >= (lunarg_ppm + lunarg_ppm_len) || strncmp(cPtr, "255\n", 4)) {
1164         return false;
1165     }
1166     while(strncmp(cPtr++, "\n", 1));
1167 
1168     for (int y = 0; y < *height; y++) {
1169         uint8_t *rowPtr = rgba_data;
1170         for (int x = 0; x < *width; x++) {
1171             memcpy(rowPtr, cPtr, 3);
1172             rowPtr[3] = 255; /* Alpha of 1 */
1173             rowPtr += 4;
1174             cPtr += 3;
1175         }
1176         rgba_data += layout->rowPitch;
1177     }
1178 
1179     return true;
1180 #else
1181     FILE *fPtr = fopen(filename, "rb");
1182     char header[256], *cPtr, *tmp;
1183 
1184     if (!fPtr)
1185         return false;
1186 
1187     cPtr = fgets(header, 256, fPtr); // P6
1188     if (cPtr == NULL || strncmp(header, "P6\n", 3)) {
1189         fclose(fPtr);
1190         return false;
1191     }
1192 
1193     do {
1194         cPtr = fgets(header, 256, fPtr);
1195         if (cPtr == NULL) {
1196             fclose(fPtr);
1197             return false;
1198         }
1199     } while (!strncmp(header, "#", 1));
1200 
1201     sscanf(header, "%u %u", width, height);
1202     if (rgba_data == NULL) {
1203         fclose(fPtr);
1204         return true;
1205     }
1206     tmp = fgets(header, 256, fPtr); // Format
1207     (void)tmp;
1208     if (cPtr == NULL || strncmp(header, "255\n", 3)) {
1209         fclose(fPtr);
1210         return false;
1211     }
1212 
1213     for (int y = 0; y < *height; y++) {
1214         uint8_t *rowPtr = rgba_data;
1215         for (int x = 0; x < *width; x++) {
1216             size_t s = fread(rowPtr, 3, 1, fPtr);
1217             (void)s;
1218             rowPtr[3] = 255; /* Alpha of 1 */
1219             rowPtr += 4;
1220         }
1221         rgba_data += layout->rowPitch;
1222     }
1223     fclose(fPtr);
1224     return true;
1225 #endif
1226 }
1227 
demo_prepare_texture_image(struct demo * demo,const char * filename,struct texture_object * tex_obj,VkImageTiling tiling,VkImageUsageFlags usage,VkFlags required_props)1228 static void demo_prepare_texture_image(struct demo *demo, const char *filename,
1229                                        struct texture_object *tex_obj,
1230                                        VkImageTiling tiling,
1231                                        VkImageUsageFlags usage,
1232                                        VkFlags required_props) {
1233     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
1234     int32_t tex_width;
1235     int32_t tex_height;
1236     VkResult U_ASSERT_ONLY err;
1237     bool U_ASSERT_ONLY pass;
1238 
1239     if (!loadTexture(filename, NULL, NULL, &tex_width, &tex_height)) {
1240         ERR_EXIT("Failed to load textures", "Load Texture Failure");
1241     }
1242 
1243     tex_obj->tex_width = tex_width;
1244     tex_obj->tex_height = tex_height;
1245 
1246     const VkImageCreateInfo image_create_info = {
1247         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1248         .pNext = NULL,
1249         .imageType = VK_IMAGE_TYPE_2D,
1250         .format = tex_format,
1251         .extent = {tex_width, tex_height, 1},
1252         .mipLevels = 1,
1253         .arrayLayers = 1,
1254         .samples = VK_SAMPLE_COUNT_1_BIT,
1255         .tiling = tiling,
1256         .usage = usage,
1257         .flags = 0,
1258         .initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED,
1259     };
1260 
1261     VkMemoryRequirements mem_reqs;
1262 
1263     err =
1264         vkCreateImage(demo->device, &image_create_info, NULL, &tex_obj->image);
1265     assert(!err);
1266 
1267     vkGetImageMemoryRequirements(demo->device, tex_obj->image, &mem_reqs);
1268 
1269     tex_obj->mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1270     tex_obj->mem_alloc.pNext = NULL;
1271     tex_obj->mem_alloc.allocationSize = mem_reqs.size;
1272     tex_obj->mem_alloc.memoryTypeIndex = 0;
1273 
1274     pass = memory_type_from_properties(demo, mem_reqs.memoryTypeBits,
1275                                        required_props,
1276                                        &tex_obj->mem_alloc.memoryTypeIndex);
1277     assert(pass);
1278 
1279     /* allocate memory */
1280     err = vkAllocateMemory(demo->device, &tex_obj->mem_alloc, NULL,
1281                            &(tex_obj->mem));
1282     assert(!err);
1283 
1284     /* bind memory */
1285     err = vkBindImageMemory(demo->device, tex_obj->image, tex_obj->mem, 0);
1286     assert(!err);
1287 
1288     if (required_props & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1289         const VkImageSubresource subres = {
1290             .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1291             .mipLevel = 0,
1292             .arrayLayer = 0,
1293         };
1294         VkSubresourceLayout layout;
1295         void *data;
1296 
1297         vkGetImageSubresourceLayout(demo->device, tex_obj->image, &subres,
1298                                     &layout);
1299 
1300         err = vkMapMemory(demo->device, tex_obj->mem, 0,
1301                           tex_obj->mem_alloc.allocationSize, 0, &data);
1302         assert(!err);
1303 
1304         if (!loadTexture(filename, data, &layout, &tex_width, &tex_height)) {
1305             fprintf(stderr, "Error loading texture: %s\n", filename);
1306         }
1307 
1308         vkUnmapMemory(demo->device, tex_obj->mem);
1309     }
1310 
1311     tex_obj->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1312 }
1313 
demo_destroy_texture_image(struct demo * demo,struct texture_object * tex_objs)1314 static void demo_destroy_texture_image(struct demo *demo,
1315                                        struct texture_object *tex_objs) {
1316     /* clean up staging resources */
1317     vkFreeMemory(demo->device, tex_objs->mem, NULL);
1318     vkDestroyImage(demo->device, tex_objs->image, NULL);
1319 }
1320 
demo_prepare_textures(struct demo * demo)1321 static void demo_prepare_textures(struct demo *demo) {
1322     const VkFormat tex_format = VK_FORMAT_R8G8B8A8_UNORM;
1323     VkFormatProperties props;
1324     uint32_t i;
1325 
1326     vkGetPhysicalDeviceFormatProperties(demo->gpu, tex_format, &props);
1327 
1328     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1329         VkResult U_ASSERT_ONLY err;
1330 
1331         if ((props.linearTilingFeatures &
1332              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
1333             !demo->use_staging_buffer) {
1334             /* Device can texture using linear textures */
1335             demo_prepare_texture_image(
1336                 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_LINEAR,
1337                 VK_IMAGE_USAGE_SAMPLED_BIT,
1338                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1339                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1340             // Nothing in the pipeline needs to be complete to start, and don't allow fragment
1341             // shader to run until layout transition completes
1342             demo_set_image_layout(demo, demo->textures[i].image, VK_IMAGE_ASPECT_COLOR_BIT,
1343                                   VK_IMAGE_LAYOUT_PREINITIALIZED, demo->textures[i].imageLayout,
1344                                   VK_ACCESS_HOST_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1345                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
1346         } else if (props.optimalTilingFeatures &
1347                    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
1348             /* Must use staging buffer to copy linear texture to optimized */
1349             struct texture_object staging_texture;
1350 
1351             memset(&staging_texture, 0, sizeof(staging_texture));
1352             demo_prepare_texture_image(
1353                 demo, tex_files[i], &staging_texture, VK_IMAGE_TILING_LINEAR,
1354                 VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
1355                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1356                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
1357 
1358             demo_prepare_texture_image(
1359                 demo, tex_files[i], &demo->textures[i], VK_IMAGE_TILING_OPTIMAL,
1360                 (VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT),
1361                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
1362 
1363             demo_set_image_layout(demo, staging_texture.image,
1364                                   VK_IMAGE_ASPECT_COLOR_BIT,
1365                                   VK_IMAGE_LAYOUT_PREINITIALIZED,
1366                                   VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1367                                   VK_ACCESS_HOST_WRITE_BIT,
1368                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1369                                   VK_PIPELINE_STAGE_TRANSFER_BIT);
1370 
1371             demo_set_image_layout(demo, demo->textures[i].image,
1372                                   VK_IMAGE_ASPECT_COLOR_BIT,
1373                                   VK_IMAGE_LAYOUT_PREINITIALIZED,
1374                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1375                                   VK_ACCESS_HOST_WRITE_BIT,
1376                                   VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1377                                   VK_PIPELINE_STAGE_TRANSFER_BIT);
1378 
1379             VkImageCopy copy_region = {
1380                 .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
1381                 .srcOffset = {0, 0, 0},
1382                 .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
1383                 .dstOffset = {0, 0, 0},
1384                 .extent = {staging_texture.tex_width,
1385                            staging_texture.tex_height, 1},
1386             };
1387             vkCmdCopyImage(
1388                 demo->cmd, staging_texture.image,
1389                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, demo->textures[i].image,
1390                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy_region);
1391 
1392             demo_set_image_layout(demo, demo->textures[i].image,
1393                                   VK_IMAGE_ASPECT_COLOR_BIT,
1394                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1395                                   demo->textures[i].imageLayout,
1396                                   VK_ACCESS_TRANSFER_WRITE_BIT,
1397                                   VK_PIPELINE_STAGE_TRANSFER_BIT,
1398                                   VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
1399 
1400             demo_flush_init_cmd(demo);
1401 
1402             demo_destroy_texture_image(demo, &staging_texture);
1403         } else {
1404             /* Can't support VK_FORMAT_R8G8B8A8_UNORM !? */
1405             assert(!"No support for R8G8B8A8_UNORM as texture image format");
1406         }
1407 
1408         const VkSamplerCreateInfo sampler = {
1409             .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1410             .pNext = NULL,
1411             .magFilter = VK_FILTER_NEAREST,
1412             .minFilter = VK_FILTER_NEAREST,
1413             .mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
1414             .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1415             .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1416             .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1417             .mipLodBias = 0.0f,
1418             .anisotropyEnable = VK_FALSE,
1419             .maxAnisotropy = 1,
1420             .compareOp = VK_COMPARE_OP_NEVER,
1421             .minLod = 0.0f,
1422             .maxLod = 0.0f,
1423             .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE,
1424             .unnormalizedCoordinates = VK_FALSE,
1425         };
1426 
1427         VkImageViewCreateInfo view = {
1428             .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1429             .pNext = NULL,
1430             .image = VK_NULL_HANDLE,
1431             .viewType = VK_IMAGE_VIEW_TYPE_2D,
1432             .format = tex_format,
1433             .components =
1434                 {
1435                  VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1436                  VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A,
1437                 },
1438             .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
1439             .flags = 0,
1440         };
1441 
1442         /* create sampler */
1443         err = vkCreateSampler(demo->device, &sampler, NULL,
1444                               &demo->textures[i].sampler);
1445         assert(!err);
1446 
1447         /* create image view */
1448         view.image = demo->textures[i].image;
1449         err = vkCreateImageView(demo->device, &view, NULL,
1450                                 &demo->textures[i].view);
1451         assert(!err);
1452     }
1453 }
1454 
demo_prepare_cube_data_buffer(struct demo * demo)1455 void demo_prepare_cube_data_buffer(struct demo *demo) {
1456     VkBufferCreateInfo buf_info;
1457     VkMemoryRequirements mem_reqs;
1458     uint8_t *pData;
1459     int i;
1460     mat4x4 MVP, VP;
1461     VkResult U_ASSERT_ONLY err;
1462     bool U_ASSERT_ONLY pass;
1463     struct vktexcube_vs_uniform data;
1464 
1465     mat4x4_mul(VP, demo->projection_matrix, demo->view_matrix);
1466     mat4x4_mul(MVP, VP, demo->model_matrix);
1467     memcpy(data.mvp, MVP, sizeof(MVP));
1468     //    dumpMatrix("MVP", MVP);
1469 
1470     for (i = 0; i < 12 * 3; i++) {
1471         data.position[i][0] = g_vertex_buffer_data[i * 3];
1472         data.position[i][1] = g_vertex_buffer_data[i * 3 + 1];
1473         data.position[i][2] = g_vertex_buffer_data[i * 3 + 2];
1474         data.position[i][3] = 1.0f;
1475         data.attr[i][0] = g_uv_buffer_data[2 * i];
1476         data.attr[i][1] = g_uv_buffer_data[2 * i + 1];
1477         data.attr[i][2] = 0;
1478         data.attr[i][3] = 0;
1479     }
1480 
1481     memset(&buf_info, 0, sizeof(buf_info));
1482     buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1483     buf_info.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
1484     buf_info.size = sizeof(data);
1485     err =
1486         vkCreateBuffer(demo->device, &buf_info, NULL, &demo->uniform_data.buf);
1487     assert(!err);
1488 
1489     vkGetBufferMemoryRequirements(demo->device, demo->uniform_data.buf,
1490                                   &mem_reqs);
1491 
1492     demo->uniform_data.mem_alloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1493     demo->uniform_data.mem_alloc.pNext = NULL;
1494     demo->uniform_data.mem_alloc.allocationSize = mem_reqs.size;
1495     demo->uniform_data.mem_alloc.memoryTypeIndex = 0;
1496 
1497     pass = memory_type_from_properties(
1498         demo, mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1499                                            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
1500         &demo->uniform_data.mem_alloc.memoryTypeIndex);
1501     assert(pass);
1502 
1503     err = vkAllocateMemory(demo->device, &demo->uniform_data.mem_alloc, NULL,
1504                            &(demo->uniform_data.mem));
1505     assert(!err);
1506 
1507     err = vkMapMemory(demo->device, demo->uniform_data.mem, 0,
1508                       demo->uniform_data.mem_alloc.allocationSize, 0,
1509                       (void **)&pData);
1510     assert(!err);
1511 
1512     memcpy(pData, &data, sizeof data);
1513 
1514     vkUnmapMemory(demo->device, demo->uniform_data.mem);
1515 
1516     err = vkBindBufferMemory(demo->device, demo->uniform_data.buf,
1517                              demo->uniform_data.mem, 0);
1518     assert(!err);
1519 
1520     demo->uniform_data.buffer_info.buffer = demo->uniform_data.buf;
1521     demo->uniform_data.buffer_info.offset = 0;
1522     demo->uniform_data.buffer_info.range = sizeof(data);
1523 }
1524 
demo_prepare_descriptor_layout(struct demo * demo)1525 static void demo_prepare_descriptor_layout(struct demo *demo) {
1526     const VkDescriptorSetLayoutBinding layout_bindings[2] = {
1527             [0] =
1528                 {
1529                  .binding = 0,
1530                  .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1531                  .descriptorCount = 1,
1532                  .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
1533                  .pImmutableSamplers = NULL,
1534                 },
1535             [1] =
1536                 {
1537                  .binding = 1,
1538                  .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1539                  .descriptorCount = DEMO_TEXTURE_COUNT,
1540                  .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
1541                  .pImmutableSamplers = NULL,
1542                 },
1543     };
1544     const VkDescriptorSetLayoutCreateInfo descriptor_layout = {
1545         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1546         .pNext = NULL,
1547         .bindingCount = 2,
1548         .pBindings = layout_bindings,
1549     };
1550     VkResult U_ASSERT_ONLY err;
1551 
1552     err = vkCreateDescriptorSetLayout(demo->device, &descriptor_layout, NULL,
1553                                       &demo->desc_layout);
1554     assert(!err);
1555 
1556     const VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {
1557         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
1558         .pNext = NULL,
1559         .setLayoutCount = 1,
1560         .pSetLayouts = &demo->desc_layout,
1561     };
1562 
1563     err = vkCreatePipelineLayout(demo->device, &pPipelineLayoutCreateInfo, NULL,
1564                                  &demo->pipeline_layout);
1565     assert(!err);
1566 }
1567 
demo_prepare_render_pass(struct demo * demo)1568 static void demo_prepare_render_pass(struct demo *demo) {
1569     // The initial layout for the color and depth attachments will be LAYOUT_UNDEFINED
1570     // because at the start of the renderpass, we don't care about their contents.
1571     // At the start of the subpass, the color attachment's layout will be transitioned
1572     // to LAYOUT_COLOR_ATTACHMENT_OPTIMAL and the depth stencil attachment's layout
1573     // will be transitioned to LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL.  At the end of
1574     // the renderpass, the color attachment's layout will be transitioned to
1575     // LAYOUT_PRESENT_SRC_KHR to be ready to present.  This is all done as part of
1576     // the renderpass, no barriers are necessary.
1577     const VkAttachmentDescription attachments[2] = {
1578             [0] =
1579                 {
1580                  .format = demo->format,
1581                  .samples = VK_SAMPLE_COUNT_1_BIT,
1582                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1583                  .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
1584                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1585                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1586                  .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1587                  .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
1588                 },
1589             [1] =
1590                 {
1591                  .format = demo->depth.format,
1592                  .samples = VK_SAMPLE_COUNT_1_BIT,
1593                  .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
1594                  .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1595                  .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
1596                  .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
1597                  .initialLayout =
1598                      VK_IMAGE_LAYOUT_UNDEFINED,
1599                  .finalLayout =
1600                      VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1601                 },
1602     };
1603     const VkAttachmentReference color_reference = {
1604         .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1605     };
1606     const VkAttachmentReference depth_reference = {
1607         .attachment = 1,
1608         .layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1609     };
1610     const VkSubpassDescription subpass = {
1611         .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
1612         .flags = 0,
1613         .inputAttachmentCount = 0,
1614         .pInputAttachments = NULL,
1615         .colorAttachmentCount = 1,
1616         .pColorAttachments = &color_reference,
1617         .pResolveAttachments = NULL,
1618         .pDepthStencilAttachment = &depth_reference,
1619         .preserveAttachmentCount = 0,
1620         .pPreserveAttachments = NULL,
1621     };
1622     const VkRenderPassCreateInfo rp_info = {
1623         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
1624         .pNext = NULL,
1625         .attachmentCount = 2,
1626         .pAttachments = attachments,
1627         .subpassCount = 1,
1628         .pSubpasses = &subpass,
1629         .dependencyCount = 0,
1630         .pDependencies = NULL,
1631     };
1632     VkResult U_ASSERT_ONLY err;
1633 
1634     err = vkCreateRenderPass(demo->device, &rp_info, NULL, &demo->render_pass);
1635     assert(!err);
1636 }
1637 
1638 //TODO: Merge shader reading
1639 #ifndef __ANDROID__
1640 static VkShaderModule
demo_prepare_shader_module(struct demo * demo,const void * code,size_t size)1641 demo_prepare_shader_module(struct demo *demo, const void *code, size_t size) {
1642     VkShaderModule module;
1643     VkShaderModuleCreateInfo moduleCreateInfo;
1644     VkResult U_ASSERT_ONLY err;
1645 
1646     moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1647     moduleCreateInfo.pNext = NULL;
1648 
1649     moduleCreateInfo.codeSize = size;
1650     moduleCreateInfo.pCode = code;
1651     moduleCreateInfo.flags = 0;
1652     err = vkCreateShaderModule(demo->device, &moduleCreateInfo, NULL, &module);
1653     assert(!err);
1654 
1655     return module;
1656 }
1657 
demo_read_spv(const char * filename,size_t * psize)1658 char *demo_read_spv(const char *filename, size_t *psize) {
1659     long int size;
1660     size_t U_ASSERT_ONLY retval;
1661     void *shader_code;
1662 
1663     FILE *fp = fopen(filename, "rb");
1664     if (!fp)
1665         return NULL;
1666 
1667     fseek(fp, 0L, SEEK_END);
1668     size = ftell(fp);
1669 
1670     fseek(fp, 0L, SEEK_SET);
1671 
1672     shader_code = malloc(size);
1673     retval = fread(shader_code, size, 1, fp);
1674     assert(retval == 1);
1675 
1676     *psize = size;
1677 
1678     fclose(fp);
1679     return shader_code;
1680 }
1681 #endif
1682 
demo_prepare_vs(struct demo * demo)1683 static VkShaderModule demo_prepare_vs(struct demo *demo) {
1684 #ifdef __ANDROID__
1685     VkShaderModuleCreateInfo sh_info = {};
1686     sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1687 
1688 #include "cube.vert.h"
1689     sh_info.codeSize = sizeof(cube_vert);
1690     sh_info.pCode = cube_vert;
1691     VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->vert_shader_module);
1692     assert(!err);
1693 #else
1694     void *vertShaderCode;
1695     size_t size;
1696 
1697     vertShaderCode = demo_read_spv("cube-vert.spv", &size);
1698 
1699     demo->vert_shader_module =
1700         demo_prepare_shader_module(demo, vertShaderCode, size);
1701 
1702     free(vertShaderCode);
1703 #endif
1704 
1705     return demo->vert_shader_module;
1706 }
1707 
demo_prepare_fs(struct demo * demo)1708 static VkShaderModule demo_prepare_fs(struct demo *demo) {
1709 #ifdef __ANDROID__
1710     VkShaderModuleCreateInfo sh_info = {};
1711     sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1712 
1713 #include "cube.frag.h"
1714     sh_info.codeSize = sizeof(cube_frag);
1715     sh_info.pCode = cube_frag;
1716     VkResult U_ASSERT_ONLY err = vkCreateShaderModule(demo->device, &sh_info, NULL, &demo->frag_shader_module);
1717     assert(!err);
1718 #else
1719     void *fragShaderCode;
1720     size_t size;
1721 
1722     fragShaderCode = demo_read_spv("cube-frag.spv", &size);
1723 
1724     demo->frag_shader_module =
1725         demo_prepare_shader_module(demo, fragShaderCode, size);
1726 
1727     free(fragShaderCode);
1728 #endif
1729 
1730     return demo->frag_shader_module;
1731 }
1732 
demo_prepare_pipeline(struct demo * demo)1733 static void demo_prepare_pipeline(struct demo *demo) {
1734     VkGraphicsPipelineCreateInfo pipeline;
1735     VkPipelineCacheCreateInfo pipelineCache;
1736     VkPipelineVertexInputStateCreateInfo vi;
1737     VkPipelineInputAssemblyStateCreateInfo ia;
1738     VkPipelineRasterizationStateCreateInfo rs;
1739     VkPipelineColorBlendStateCreateInfo cb;
1740     VkPipelineDepthStencilStateCreateInfo ds;
1741     VkPipelineViewportStateCreateInfo vp;
1742     VkPipelineMultisampleStateCreateInfo ms;
1743     VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
1744     VkPipelineDynamicStateCreateInfo dynamicState;
1745     VkResult U_ASSERT_ONLY err;
1746 
1747     memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
1748     memset(&dynamicState, 0, sizeof dynamicState);
1749     dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1750     dynamicState.pDynamicStates = dynamicStateEnables;
1751 
1752     memset(&pipeline, 0, sizeof(pipeline));
1753     pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1754     pipeline.layout = demo->pipeline_layout;
1755 
1756     memset(&vi, 0, sizeof(vi));
1757     vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1758 
1759     memset(&ia, 0, sizeof(ia));
1760     ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1761     ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1762 
1763     memset(&rs, 0, sizeof(rs));
1764     rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1765     rs.polygonMode = VK_POLYGON_MODE_FILL;
1766     rs.cullMode = VK_CULL_MODE_BACK_BIT;
1767     rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1768     rs.depthClampEnable = VK_FALSE;
1769     rs.rasterizerDiscardEnable = VK_FALSE;
1770     rs.depthBiasEnable = VK_FALSE;
1771     rs.lineWidth = 1.0f;
1772 
1773     memset(&cb, 0, sizeof(cb));
1774     cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1775     VkPipelineColorBlendAttachmentState att_state[1];
1776     memset(att_state, 0, sizeof(att_state));
1777     att_state[0].colorWriteMask = 0xf;
1778     att_state[0].blendEnable = VK_FALSE;
1779     cb.attachmentCount = 1;
1780     cb.pAttachments = att_state;
1781 
1782     memset(&vp, 0, sizeof(vp));
1783     vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1784     vp.viewportCount = 1;
1785     dynamicStateEnables[dynamicState.dynamicStateCount++] =
1786         VK_DYNAMIC_STATE_VIEWPORT;
1787     vp.scissorCount = 1;
1788     dynamicStateEnables[dynamicState.dynamicStateCount++] =
1789         VK_DYNAMIC_STATE_SCISSOR;
1790 
1791     memset(&ds, 0, sizeof(ds));
1792     ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1793     ds.depthTestEnable = VK_TRUE;
1794     ds.depthWriteEnable = VK_TRUE;
1795     ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
1796     ds.depthBoundsTestEnable = VK_FALSE;
1797     ds.back.failOp = VK_STENCIL_OP_KEEP;
1798     ds.back.passOp = VK_STENCIL_OP_KEEP;
1799     ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
1800     ds.stencilTestEnable = VK_FALSE;
1801     ds.front = ds.back;
1802 
1803     memset(&ms, 0, sizeof(ms));
1804     ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1805     ms.pSampleMask = NULL;
1806     ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1807 
1808     // Two stages: vs and fs
1809     pipeline.stageCount = 2;
1810     VkPipelineShaderStageCreateInfo shaderStages[2];
1811     memset(&shaderStages, 0, 2 * sizeof(VkPipelineShaderStageCreateInfo));
1812 
1813     shaderStages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1814     shaderStages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
1815     shaderStages[0].module = demo_prepare_vs(demo);
1816     shaderStages[0].pName = "main";
1817 
1818     shaderStages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1819     shaderStages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1820     shaderStages[1].module = demo_prepare_fs(demo);
1821     shaderStages[1].pName = "main";
1822 
1823     memset(&pipelineCache, 0, sizeof(pipelineCache));
1824     pipelineCache.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
1825 
1826     err = vkCreatePipelineCache(demo->device, &pipelineCache, NULL,
1827                                 &demo->pipelineCache);
1828     assert(!err);
1829 
1830     pipeline.pVertexInputState = &vi;
1831     pipeline.pInputAssemblyState = &ia;
1832     pipeline.pRasterizationState = &rs;
1833     pipeline.pColorBlendState = &cb;
1834     pipeline.pMultisampleState = &ms;
1835     pipeline.pViewportState = &vp;
1836     pipeline.pDepthStencilState = &ds;
1837     pipeline.pStages = shaderStages;
1838     pipeline.renderPass = demo->render_pass;
1839     pipeline.pDynamicState = &dynamicState;
1840 
1841     pipeline.renderPass = demo->render_pass;
1842 
1843     err = vkCreateGraphicsPipelines(demo->device, demo->pipelineCache, 1,
1844                                     &pipeline, NULL, &demo->pipeline);
1845     assert(!err);
1846 
1847     vkDestroyShaderModule(demo->device, demo->frag_shader_module, NULL);
1848     vkDestroyShaderModule(demo->device, demo->vert_shader_module, NULL);
1849 }
1850 
demo_prepare_descriptor_pool(struct demo * demo)1851 static void demo_prepare_descriptor_pool(struct demo *demo) {
1852     const VkDescriptorPoolSize type_counts[2] = {
1853             [0] =
1854                 {
1855                  .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
1856                  .descriptorCount = 1,
1857                 },
1858             [1] =
1859                 {
1860                  .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1861                  .descriptorCount = DEMO_TEXTURE_COUNT,
1862                 },
1863     };
1864     const VkDescriptorPoolCreateInfo descriptor_pool = {
1865         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1866         .pNext = NULL,
1867         .maxSets = 1,
1868         .poolSizeCount = 2,
1869         .pPoolSizes = type_counts,
1870     };
1871     VkResult U_ASSERT_ONLY err;
1872 
1873     err = vkCreateDescriptorPool(demo->device, &descriptor_pool, NULL,
1874                                  &demo->desc_pool);
1875     assert(!err);
1876 }
1877 
demo_prepare_descriptor_set(struct demo * demo)1878 static void demo_prepare_descriptor_set(struct demo *demo) {
1879     VkDescriptorImageInfo tex_descs[DEMO_TEXTURE_COUNT];
1880     VkWriteDescriptorSet writes[2];
1881     VkResult U_ASSERT_ONLY err;
1882     uint32_t i;
1883 
1884     VkDescriptorSetAllocateInfo alloc_info = {
1885         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1886         .pNext = NULL,
1887         .descriptorPool = demo->desc_pool,
1888         .descriptorSetCount = 1,
1889         .pSetLayouts = &demo->desc_layout};
1890     err = vkAllocateDescriptorSets(demo->device, &alloc_info, &demo->desc_set);
1891     assert(!err);
1892 
1893     memset(&tex_descs, 0, sizeof(tex_descs));
1894     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
1895         tex_descs[i].sampler = demo->textures[i].sampler;
1896         tex_descs[i].imageView = demo->textures[i].view;
1897         tex_descs[i].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
1898     }
1899 
1900     memset(&writes, 0, sizeof(writes));
1901 
1902     writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1903     writes[0].dstSet = demo->desc_set;
1904     writes[0].descriptorCount = 1;
1905     writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1906     writes[0].pBufferInfo = &demo->uniform_data.buffer_info;
1907 
1908     writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
1909     writes[1].dstSet = demo->desc_set;
1910     writes[1].dstBinding = 1;
1911     writes[1].descriptorCount = DEMO_TEXTURE_COUNT;
1912     writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1913     writes[1].pImageInfo = tex_descs;
1914 
1915     vkUpdateDescriptorSets(demo->device, 2, writes, 0, NULL);
1916 }
1917 
demo_prepare_framebuffers(struct demo * demo)1918 static void demo_prepare_framebuffers(struct demo *demo) {
1919     VkImageView attachments[2];
1920     attachments[1] = demo->depth.view;
1921 
1922     const VkFramebufferCreateInfo fb_info = {
1923         .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
1924         .pNext = NULL,
1925         .renderPass = demo->render_pass,
1926         .attachmentCount = 2,
1927         .pAttachments = attachments,
1928         .width = demo->width,
1929         .height = demo->height,
1930         .layers = 1,
1931     };
1932     VkResult U_ASSERT_ONLY err;
1933     uint32_t i;
1934 
1935     demo->framebuffers = (VkFramebuffer *)malloc(demo->swapchainImageCount *
1936                                                  sizeof(VkFramebuffer));
1937     assert(demo->framebuffers);
1938 
1939     for (i = 0; i < demo->swapchainImageCount; i++) {
1940         attachments[0] = demo->buffers[i].view;
1941         err = vkCreateFramebuffer(demo->device, &fb_info, NULL,
1942                                   &demo->framebuffers[i]);
1943         assert(!err);
1944     }
1945 }
1946 
demo_prepare(struct demo * demo)1947 static void demo_prepare(struct demo *demo) {
1948     VkResult U_ASSERT_ONLY err;
1949 
1950     const VkCommandPoolCreateInfo cmd_pool_info = {
1951         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1952         .pNext = NULL,
1953         .queueFamilyIndex = demo->graphics_queue_family_index,
1954         .flags = 0,
1955     };
1956     err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
1957                               &demo->cmd_pool);
1958     assert(!err);
1959 
1960     const VkCommandBufferAllocateInfo cmd = {
1961         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1962         .pNext = NULL,
1963         .commandPool = demo->cmd_pool,
1964         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1965         .commandBufferCount = 1,
1966     };
1967 
1968     demo_prepare_buffers(demo);
1969     demo_prepare_depth(demo);
1970     demo_prepare_textures(demo);
1971     demo_prepare_cube_data_buffer(demo);
1972 
1973     demo_prepare_descriptor_layout(demo);
1974     demo_prepare_render_pass(demo);
1975     demo_prepare_pipeline(demo);
1976 
1977     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
1978         err =
1979             vkAllocateCommandBuffers(demo->device, &cmd, &demo->buffers[i].cmd);
1980         assert(!err);
1981     }
1982 
1983     if (demo->separate_present_queue) {
1984         const VkCommandPoolCreateInfo cmd_pool_info = {
1985             .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1986             .pNext = NULL,
1987             .queueFamilyIndex = demo->present_queue_family_index,
1988             .flags = 0,
1989         };
1990         err = vkCreateCommandPool(demo->device, &cmd_pool_info, NULL,
1991                                   &demo->present_cmd_pool);
1992         assert(!err);
1993         const VkCommandBufferAllocateInfo cmd = {
1994             .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1995             .pNext = NULL,
1996             .commandPool = demo->present_cmd_pool,
1997             .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1998             .commandBufferCount = 1,
1999         };
2000         for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
2001             err = vkAllocateCommandBuffers(
2002                 demo->device, &cmd, &demo->buffers[i].graphics_to_present_cmd);
2003             assert(!err);
2004             demo_build_image_ownership_cmd(demo, i);
2005         }
2006     }
2007 
2008     demo_prepare_descriptor_pool(demo);
2009     demo_prepare_descriptor_set(demo);
2010 
2011     demo_prepare_framebuffers(demo);
2012 
2013     for (uint32_t i = 0; i < demo->swapchainImageCount; i++) {
2014         demo->current_buffer = i;
2015         demo_draw_build_cmd(demo, demo->buffers[i].cmd);
2016     }
2017 
2018     /*
2019      * Prepare functions above may generate pipeline commands
2020      * that need to be flushed before beginning the render loop.
2021      */
2022     demo_flush_init_cmd(demo);
2023 
2024     demo->current_buffer = 0;
2025     demo->prepared = true;
2026 }
2027 
demo_cleanup(struct demo * demo)2028 static void demo_cleanup(struct demo *demo) {
2029     uint32_t i;
2030 
2031     demo->prepared = false;
2032     vkDeviceWaitIdle(demo->device);
2033 
2034     // Wait for fences from present operations
2035     for (i = 0; i < FRAME_LAG; i++) {
2036         vkWaitForFences(demo->device, 1, &demo->fences[i], VK_TRUE, UINT64_MAX);
2037         vkDestroyFence(demo->device, demo->fences[i], NULL);
2038         vkDestroySemaphore(demo->device, demo->image_acquired_semaphores[i], NULL);
2039         vkDestroySemaphore(demo->device, demo->draw_complete_semaphores[i], NULL);
2040         if (demo->separate_present_queue) {
2041             vkDestroySemaphore(demo->device, demo->image_ownership_semaphores[i], NULL);
2042         }
2043     }
2044 
2045     for (i = 0; i < demo->swapchainImageCount; i++) {
2046         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2047     }
2048     free(demo->framebuffers);
2049     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2050 
2051     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2052     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
2053     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2054     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2055     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2056 
2057     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2058         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2059         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2060         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2061         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2062     }
2063     demo->fpDestroySwapchainKHR(demo->device, demo->swapchain, NULL);
2064 
2065     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2066     vkDestroyImage(demo->device, demo->depth.image, NULL);
2067     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2068 
2069     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
2070     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
2071 
2072     for (i = 0; i < demo->swapchainImageCount; i++) {
2073         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2074         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
2075                              &demo->buffers[i].cmd);
2076     }
2077     free(demo->buffers);
2078     free(demo->queue_props);
2079     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2080 
2081     if (demo->separate_present_queue) {
2082         vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL);
2083     }
2084     vkDestroyDevice(demo->device, NULL);
2085     if (demo->validate) {
2086         demo->DestroyDebugReportCallback(demo->inst, demo->msg_callback, NULL);
2087     }
2088     vkDestroySurfaceKHR(demo->inst, demo->surface, NULL);
2089     vkDestroyInstance(demo->inst, NULL);
2090 
2091 #if defined(VK_USE_PLATFORM_XLIB_KHR)
2092     if (demo->use_xlib) {
2093         XDestroyWindow(demo->display, demo->xlib_window);
2094         XCloseDisplay(demo->display);
2095     } else {
2096         xcb_destroy_window(demo->connection, demo->xcb_window);
2097         xcb_disconnect(demo->connection);
2098     }
2099     free(demo->atom_wm_delete_window);
2100 #elif defined(VK_USE_PLATFORM_XCB_KHR)
2101     xcb_destroy_window(demo->connection, demo->xcb_window);
2102     xcb_disconnect(demo->connection);
2103     free(demo->atom_wm_delete_window);
2104 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2105     wl_shell_surface_destroy(demo->shell_surface);
2106     wl_surface_destroy(demo->window);
2107     wl_shell_destroy(demo->shell);
2108     wl_compositor_destroy(demo->compositor);
2109     wl_registry_destroy(demo->registry);
2110     wl_display_disconnect(demo->display);
2111 #endif
2112 }
2113 
demo_resize(struct demo * demo)2114 static void demo_resize(struct demo *demo) {
2115     uint32_t i;
2116 
2117     // Don't react to resize until after first initialization.
2118     if (!demo->prepared) {
2119         return;
2120     }
2121     // In order to properly resize the window, we must re-create the swapchain
2122     // AND redo the command buffers, etc.
2123     //
2124     // First, perform part of the demo_cleanup() function:
2125     demo->prepared = false;
2126     vkDeviceWaitIdle(demo->device);
2127 
2128     for (i = 0; i < demo->swapchainImageCount; i++) {
2129         vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);
2130     }
2131     free(demo->framebuffers);
2132     vkDestroyDescriptorPool(demo->device, demo->desc_pool, NULL);
2133 
2134     vkDestroyPipeline(demo->device, demo->pipeline, NULL);
2135     vkDestroyPipelineCache(demo->device, demo->pipelineCache, NULL);
2136     vkDestroyRenderPass(demo->device, demo->render_pass, NULL);
2137     vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);
2138     vkDestroyDescriptorSetLayout(demo->device, demo->desc_layout, NULL);
2139 
2140     for (i = 0; i < DEMO_TEXTURE_COUNT; i++) {
2141         vkDestroyImageView(demo->device, demo->textures[i].view, NULL);
2142         vkDestroyImage(demo->device, demo->textures[i].image, NULL);
2143         vkFreeMemory(demo->device, demo->textures[i].mem, NULL);
2144         vkDestroySampler(demo->device, demo->textures[i].sampler, NULL);
2145     }
2146 
2147     vkDestroyImageView(demo->device, demo->depth.view, NULL);
2148     vkDestroyImage(demo->device, demo->depth.image, NULL);
2149     vkFreeMemory(demo->device, demo->depth.mem, NULL);
2150 
2151     vkDestroyBuffer(demo->device, demo->uniform_data.buf, NULL);
2152     vkFreeMemory(demo->device, demo->uniform_data.mem, NULL);
2153 
2154     for (i = 0; i < demo->swapchainImageCount; i++) {
2155         vkDestroyImageView(demo->device, demo->buffers[i].view, NULL);
2156         vkFreeCommandBuffers(demo->device, demo->cmd_pool, 1,
2157                              &demo->buffers[i].cmd);
2158     }
2159     vkDestroyCommandPool(demo->device, demo->cmd_pool, NULL);
2160     if (demo->separate_present_queue) {
2161         vkDestroyCommandPool(demo->device, demo->present_cmd_pool, NULL);
2162     }
2163     free(demo->buffers);
2164 
2165     // Second, re-perform the demo_prepare() function, which will re-create the
2166     // swapchain:
2167     demo_prepare(demo);
2168 }
2169 
2170 // On MS-Windows, make this a global, so it's available to WndProc()
2171 struct demo demo;
2172 
2173 #if defined(VK_USE_PLATFORM_WIN32_KHR)
demo_run(struct demo * demo)2174 static void demo_run(struct demo *demo) {
2175     if (!demo->prepared)
2176         return;
2177 
2178     demo_update_data_buffer(demo);
2179     demo_draw(demo);
2180     demo->curFrame++;
2181     if (demo->frameCount != INT_MAX && demo->curFrame == demo->frameCount) {
2182         PostQuitMessage(validation_error);
2183     }
2184 }
2185 
2186 // MS-Windows event handling function:
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2187 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
2188     switch (uMsg) {
2189     case WM_CLOSE:
2190         PostQuitMessage(validation_error);
2191         break;
2192     case WM_PAINT:
2193         // The validation callback calls MessageBox which can generate paint
2194         // events - don't make more Vulkan calls if we got here from the
2195         // callback
2196         if (!in_callback) {
2197             demo_run(&demo);
2198         }
2199         break;
2200     case WM_GETMINMAXINFO:     // set window's minimum size
2201         ((MINMAXINFO*)lParam)->ptMinTrackSize = demo.minsize;
2202         return 0;
2203     case WM_SIZE:
2204         // Resize the application to the new window size, except when
2205         // it was minimized. Vulkan doesn't support images or swapchains
2206         // with width=0 and height=0.
2207         if (wParam != SIZE_MINIMIZED) {
2208             demo.width = lParam & 0xffff;
2209             demo.height = (lParam & 0xffff0000) >> 16;
2210             demo_resize(&demo);
2211         }
2212         break;
2213     default:
2214         break;
2215     }
2216     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
2217 }
2218 
demo_create_window(struct demo * demo)2219 static void demo_create_window(struct demo *demo) {
2220     WNDCLASSEX win_class;
2221 
2222     // Initialize the window class structure:
2223     win_class.cbSize = sizeof(WNDCLASSEX);
2224     win_class.style = CS_HREDRAW | CS_VREDRAW;
2225     win_class.lpfnWndProc = WndProc;
2226     win_class.cbClsExtra = 0;
2227     win_class.cbWndExtra = 0;
2228     win_class.hInstance = demo->connection; // hInstance
2229     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
2230     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
2231     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
2232     win_class.lpszMenuName = NULL;
2233     win_class.lpszClassName = demo->name;
2234     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
2235     // Register window class:
2236     if (!RegisterClassEx(&win_class)) {
2237         // It didn't work, so try to give a useful error:
2238         printf("Unexpected error trying to start the application!\n");
2239         fflush(stdout);
2240         exit(1);
2241     }
2242     // Create window with the registered class:
2243     RECT wr = {0, 0, demo->width, demo->height};
2244     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
2245     demo->window = CreateWindowEx(0,
2246                                   demo->name,           // class name
2247                                   demo->name,           // app name
2248                                   WS_OVERLAPPEDWINDOW | // window style
2249                                       WS_VISIBLE | WS_SYSMENU,
2250                                   100, 100,           // x/y coords
2251                                   wr.right - wr.left, // width
2252                                   wr.bottom - wr.top, // height
2253                                   NULL,               // handle to parent
2254                                   NULL,               // handle to menu
2255                                   demo->connection,   // hInstance
2256                                   NULL);              // no extra parameters
2257     if (!demo->window) {
2258         // It didn't work, so try to give a useful error:
2259         printf("Cannot create a window in which to draw!\n");
2260         fflush(stdout);
2261         exit(1);
2262     }
2263     // Window client area size must be at least 1 pixel high, to prevent crash.
2264     demo->minsize.x = GetSystemMetrics(SM_CXMINTRACK);
2265     demo->minsize.y = GetSystemMetrics(SM_CYMINTRACK)+1;
2266 }
2267 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
demo_create_xlib_window(struct demo * demo)2268 static void demo_create_xlib_window(struct demo *demo) {
2269 
2270     demo->display = XOpenDisplay(NULL);
2271     long visualMask = VisualScreenMask;
2272     int numberOfVisuals;
2273     XVisualInfo vInfoTemplate={};
2274     vInfoTemplate.screen = DefaultScreen(demo->display);
2275     XVisualInfo *visualInfo = XGetVisualInfo(demo->display, visualMask,
2276                                              &vInfoTemplate, &numberOfVisuals);
2277 
2278     Colormap colormap = XCreateColormap(
2279                 demo->display, RootWindow(demo->display, vInfoTemplate.screen),
2280                 visualInfo->visual, AllocNone);
2281 
2282     XSetWindowAttributes windowAttributes={};
2283     windowAttributes.colormap = colormap;
2284     windowAttributes.background_pixel = 0xFFFFFFFF;
2285     windowAttributes.border_pixel = 0;
2286     windowAttributes.event_mask =
2287             KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask;
2288 
2289     demo->xlib_window = XCreateWindow(
2290                 demo->display, RootWindow(demo->display, vInfoTemplate.screen), 0, 0,
2291                 demo->width, demo->height, 0, visualInfo->depth, InputOutput,
2292                 visualInfo->visual,
2293                 CWBackPixel | CWBorderPixel | CWEventMask | CWColormap, &windowAttributes);
2294 
2295     XSelectInput(demo->display, demo->xlib_window, ExposureMask | KeyPressMask);
2296     XMapWindow(demo->display, demo->xlib_window);
2297     XFlush(demo->display);
2298     demo->xlib_wm_delete_window =
2299             XInternAtom(demo->display, "WM_DELETE_WINDOW", False);
2300 }
demo_handle_xlib_event(struct demo * demo,const XEvent * event)2301 static void demo_handle_xlib_event(struct demo *demo, const XEvent *event) {
2302     switch(event->type) {
2303     case ClientMessage:
2304         if ((Atom)event->xclient.data.l[0] == demo->xlib_wm_delete_window)
2305             demo->quit = true;
2306         break;
2307     case KeyPress:
2308         switch (event->xkey.keycode) {
2309         case 0x9: // Escape
2310             demo->quit = true;
2311             break;
2312         case 0x71: // left arrow key
2313             demo->spin_angle += demo->spin_increment;
2314             break;
2315         case 0x72: // right arrow key
2316             demo->spin_angle -= demo->spin_increment;
2317             break;
2318         case 0x41:
2319             demo->pause = !demo->pause;
2320             break;
2321         }
2322         break;
2323     case ConfigureNotify:
2324         if ((demo->width != event->xconfigure.width) ||
2325             (demo->height != event->xconfigure.height)) {
2326             demo->width = event->xconfigure.width;
2327             demo->height = event->xconfigure.height;
2328             demo_resize(demo);
2329         }
2330         break;
2331     default:
2332         break;
2333     }
2334 
2335 }
2336 
demo_run_xlib(struct demo * demo)2337 static void demo_run_xlib(struct demo *demo) {
2338 
2339     while (!demo->quit) {
2340         XEvent event;
2341 
2342         if (demo->pause) {
2343             XNextEvent(demo->display, &event);
2344             demo_handle_xlib_event(demo, &event);
2345         } else {
2346             while (XPending(demo->display) > 0) {
2347                 XNextEvent(demo->display, &event);
2348                 demo_handle_xlib_event(demo, &event);
2349             }
2350         }
2351 
2352         demo_update_data_buffer(demo);
2353         demo_draw(demo);
2354         demo->curFrame++;
2355         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
2356             demo->quit = true;
2357     }
2358 }
2359 #endif // VK_USE_PLATFORM_XLIB_KHR
2360 #ifdef VK_USE_PLATFORM_XCB_KHR
demo_handle_xcb_event(struct demo * demo,const xcb_generic_event_t * event)2361 static void demo_handle_xcb_event(struct demo *demo,
2362                               const xcb_generic_event_t *event) {
2363     uint8_t event_code = event->response_type & 0x7f;
2364     switch (event_code) {
2365     case XCB_EXPOSE:
2366         // TODO: Resize window
2367         break;
2368     case XCB_CLIENT_MESSAGE:
2369         if ((*(xcb_client_message_event_t *)event).data.data32[0] ==
2370             (*demo->atom_wm_delete_window).atom) {
2371             demo->quit = true;
2372         }
2373         break;
2374     case XCB_KEY_RELEASE: {
2375         const xcb_key_release_event_t *key =
2376             (const xcb_key_release_event_t *)event;
2377 
2378         switch (key->detail) {
2379         case 0x9: // Escape
2380             demo->quit = true;
2381             break;
2382         case 0x71: // left arrow key
2383             demo->spin_angle += demo->spin_increment;
2384             break;
2385         case 0x72: // right arrow key
2386             demo->spin_angle -= demo->spin_increment;
2387             break;
2388         case 0x41:
2389             demo->pause = !demo->pause;
2390             break;
2391         }
2392     } break;
2393     case XCB_CONFIGURE_NOTIFY: {
2394         const xcb_configure_notify_event_t *cfg =
2395             (const xcb_configure_notify_event_t *)event;
2396         if ((demo->width != cfg->width) || (demo->height != cfg->height)) {
2397             demo->width = cfg->width;
2398             demo->height = cfg->height;
2399             demo_resize(demo);
2400         }
2401     } break;
2402     default:
2403         break;
2404     }
2405 }
2406 
demo_run_xcb(struct demo * demo)2407 static void demo_run_xcb(struct demo *demo) {
2408     xcb_flush(demo->connection);
2409 
2410     while (!demo->quit) {
2411         xcb_generic_event_t *event;
2412 
2413         if (demo->pause) {
2414             event = xcb_wait_for_event(demo->connection);
2415         } else {
2416             event = xcb_poll_for_event(demo->connection);
2417             while(event) {
2418                 demo_handle_xcb_event(demo, event);
2419                 free(event);
2420                 event = xcb_poll_for_event(demo->connection);
2421             }
2422         }
2423 
2424         demo_update_data_buffer(demo);
2425         demo_draw(demo);
2426         demo->curFrame++;
2427         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
2428             demo->quit = true;
2429     }
2430 }
2431 
demo_create_xcb_window(struct demo * demo)2432 static void demo_create_xcb_window(struct demo *demo) {
2433     uint32_t value_mask, value_list[32];
2434 
2435     demo->xcb_window = xcb_generate_id(demo->connection);
2436 
2437     value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
2438     value_list[0] = demo->screen->black_pixel;
2439     value_list[1] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE |
2440                     XCB_EVENT_MASK_STRUCTURE_NOTIFY;
2441 
2442     xcb_create_window(demo->connection, XCB_COPY_FROM_PARENT, demo->xcb_window,
2443                       demo->screen->root, 0, 0, demo->width, demo->height, 0,
2444                       XCB_WINDOW_CLASS_INPUT_OUTPUT, demo->screen->root_visual,
2445                       value_mask, value_list);
2446 
2447     /* Magic code that will send notification when window is destroyed */
2448     xcb_intern_atom_cookie_t cookie =
2449         xcb_intern_atom(demo->connection, 1, 12, "WM_PROTOCOLS");
2450     xcb_intern_atom_reply_t *reply =
2451         xcb_intern_atom_reply(demo->connection, cookie, 0);
2452 
2453     xcb_intern_atom_cookie_t cookie2 =
2454         xcb_intern_atom(demo->connection, 0, 16, "WM_DELETE_WINDOW");
2455     demo->atom_wm_delete_window =
2456         xcb_intern_atom_reply(demo->connection, cookie2, 0);
2457 
2458     xcb_change_property(demo->connection, XCB_PROP_MODE_REPLACE, demo->xcb_window,
2459                         (*reply).atom, 4, 32, 1,
2460                         &(*demo->atom_wm_delete_window).atom);
2461     free(reply);
2462 
2463     xcb_map_window(demo->connection, demo->xcb_window);
2464 
2465     // Force the x/y coordinates to 100,100 results are identical in consecutive
2466     // runs
2467     const uint32_t coords[] = {100, 100};
2468     xcb_configure_window(demo->connection, demo->xcb_window,
2469                          XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, coords);
2470 }
2471 // VK_USE_PLATFORM_XCB_KHR
2472 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
demo_run(struct demo * demo)2473 static void demo_run(struct demo *demo) {
2474     while (!demo->quit) {
2475         demo_update_data_buffer(demo);
2476         demo_draw(demo);
2477         demo->curFrame++;
2478         if (demo->frameCount != INT32_MAX && demo->curFrame == demo->frameCount)
2479             demo->quit = true;
2480     }
2481 }
2482 
handle_ping(void * data UNUSED,struct wl_shell_surface * shell_surface,uint32_t serial)2483 static void handle_ping(void *data UNUSED,
2484                         struct wl_shell_surface *shell_surface,
2485                         uint32_t serial) {
2486     wl_shell_surface_pong(shell_surface, serial);
2487 }
2488 
handle_configure(void * data UNUSED,struct wl_shell_surface * shell_surface UNUSED,uint32_t edges UNUSED,int32_t width UNUSED,int32_t height UNUSED)2489 static void handle_configure(void *data UNUSED,
2490                              struct wl_shell_surface *shell_surface UNUSED,
2491                              uint32_t edges UNUSED, int32_t width UNUSED,
2492                              int32_t height UNUSED) {}
2493 
handle_popup_done(void * data UNUSED,struct wl_shell_surface * shell_surface UNUSED)2494 static void handle_popup_done(void *data UNUSED,
2495                               struct wl_shell_surface *shell_surface UNUSED) {}
2496 
2497 static const struct wl_shell_surface_listener shell_surface_listener = {
2498     handle_ping, handle_configure, handle_popup_done};
2499 
demo_create_window(struct demo * demo)2500 static void demo_create_window(struct demo *demo) {
2501     demo->window = wl_compositor_create_surface(demo->compositor);
2502     if (!demo->window) {
2503         printf("Can not create wayland_surface from compositor!\n");
2504         fflush(stdout);
2505         exit(1);
2506     }
2507 
2508     demo->shell_surface = wl_shell_get_shell_surface(demo->shell, demo->window);
2509     if (!demo->shell_surface) {
2510         printf("Can not get shell_surface from wayland_surface!\n");
2511         fflush(stdout);
2512         exit(1);
2513     }
2514     wl_shell_surface_add_listener(demo->shell_surface, &shell_surface_listener,
2515                                   demo);
2516     wl_shell_surface_set_toplevel(demo->shell_surface);
2517     wl_shell_surface_set_title(demo->shell_surface, APP_SHORT_NAME);
2518 }
2519 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
demo_run(struct demo * demo)2520 static void demo_run(struct demo *demo) {
2521     if (!demo->prepared)
2522         return;
2523 
2524     demo_update_data_buffer(demo);
2525     demo_draw(demo);
2526     demo->curFrame++;
2527 }
2528 #endif
2529 
2530 /*
2531  * Return 1 (true) if all layer names specified in check_names
2532  * can be found in given layer properties.
2533  */
demo_check_layers(uint32_t check_count,char ** check_names,uint32_t layer_count,VkLayerProperties * layers)2534 static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
2535                                   uint32_t layer_count,
2536                                   VkLayerProperties *layers) {
2537     for (uint32_t i = 0; i < check_count; i++) {
2538         VkBool32 found = 0;
2539         for (uint32_t j = 0; j < layer_count; j++) {
2540             if (!strcmp(check_names[i], layers[j].layerName)) {
2541                 found = 1;
2542                 break;
2543             }
2544         }
2545         if (!found) {
2546             fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
2547             return 0;
2548         }
2549     }
2550     return 1;
2551 }
2552 
demo_init_vk(struct demo * demo)2553 static void demo_init_vk(struct demo *demo) {
2554     VkResult err;
2555     uint32_t instance_extension_count = 0;
2556     uint32_t instance_layer_count = 0;
2557     uint32_t validation_layer_count = 0;
2558     char **instance_validation_layers = NULL;
2559     demo->enabled_extension_count = 0;
2560     demo->enabled_layer_count = 0;
2561 
2562     char *instance_validation_layers_alt1[] = {
2563         "VK_LAYER_LUNARG_standard_validation"
2564     };
2565 
2566     char *instance_validation_layers_alt2[] = {
2567         "VK_LAYER_GOOGLE_threading",       "VK_LAYER_LUNARG_parameter_validation",
2568         "VK_LAYER_LUNARG_object_tracker",  "VK_LAYER_LUNARG_image",
2569         "VK_LAYER_LUNARG_core_validation", "VK_LAYER_LUNARG_swapchain",
2570         "VK_LAYER_GOOGLE_unique_objects"
2571     };
2572 
2573     /* Look for validation layers */
2574     VkBool32 validation_found = 0;
2575     if (demo->validate) {
2576 
2577         err = vkEnumerateInstanceLayerProperties(&instance_layer_count, NULL);
2578         assert(!err);
2579 
2580         instance_validation_layers = instance_validation_layers_alt1;
2581         if (instance_layer_count > 0) {
2582             VkLayerProperties *instance_layers =
2583                     malloc(sizeof (VkLayerProperties) * instance_layer_count);
2584             err = vkEnumerateInstanceLayerProperties(&instance_layer_count,
2585                     instance_layers);
2586             assert(!err);
2587 
2588 
2589             validation_found = demo_check_layers(
2590                     ARRAY_SIZE(instance_validation_layers_alt1),
2591                     instance_validation_layers, instance_layer_count,
2592                     instance_layers);
2593             if (validation_found) {
2594                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt1);
2595                 demo->enabled_layers[0] = "VK_LAYER_LUNARG_standard_validation";
2596                 validation_layer_count = 1;
2597             } else {
2598                 // use alternative set of validation layers
2599                 instance_validation_layers = instance_validation_layers_alt2;
2600                 demo->enabled_layer_count = ARRAY_SIZE(instance_validation_layers_alt2);
2601                 validation_found = demo_check_layers(
2602                     ARRAY_SIZE(instance_validation_layers_alt2),
2603                     instance_validation_layers, instance_layer_count,
2604                     instance_layers);
2605                 validation_layer_count =
2606                     ARRAY_SIZE(instance_validation_layers_alt2);
2607                 for (uint32_t i = 0; i < validation_layer_count; i++) {
2608                     demo->enabled_layers[i] = instance_validation_layers[i];
2609                 }
2610             }
2611             free(instance_layers);
2612         }
2613 
2614         if (!validation_found) {
2615             ERR_EXIT("vkEnumerateInstanceLayerProperties failed to find "
2616                     "required validation layer.\n\n"
2617                     "Please look at the Getting Started guide for additional "
2618                     "information.\n",
2619                     "vkCreateInstance Failure");
2620         }
2621     }
2622 
2623     /* Look for instance extensions */
2624     VkBool32 surfaceExtFound = 0;
2625     VkBool32 platformSurfaceExtFound = 0;
2626 #if defined(VK_USE_PLATFORM_XLIB_KHR)
2627     VkBool32 xlibSurfaceExtFound = 0;
2628 #endif
2629     memset(demo->extension_names, 0, sizeof(demo->extension_names));
2630 
2631     err = vkEnumerateInstanceExtensionProperties(
2632         NULL, &instance_extension_count, NULL);
2633     assert(!err);
2634 
2635     if (instance_extension_count > 0) {
2636         VkExtensionProperties *instance_extensions =
2637             malloc(sizeof(VkExtensionProperties) * instance_extension_count);
2638         err = vkEnumerateInstanceExtensionProperties(
2639             NULL, &instance_extension_count, instance_extensions);
2640         assert(!err);
2641         for (uint32_t i = 0; i < instance_extension_count; i++) {
2642             if (!strcmp(VK_KHR_SURFACE_EXTENSION_NAME,
2643                         instance_extensions[i].extensionName)) {
2644                 surfaceExtFound = 1;
2645                 demo->extension_names[demo->enabled_extension_count++] =
2646                     VK_KHR_SURFACE_EXTENSION_NAME;
2647             }
2648 #if defined(VK_USE_PLATFORM_WIN32_KHR)
2649             if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
2650                         instance_extensions[i].extensionName)) {
2651                 platformSurfaceExtFound = 1;
2652                 demo->extension_names[demo->enabled_extension_count++] =
2653                     VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
2654             }
2655 #endif
2656 #if defined(VK_USE_PLATFORM_XLIB_KHR)
2657             if (!strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
2658                         instance_extensions[i].extensionName)) {
2659                 platformSurfaceExtFound = 1;
2660                 xlibSurfaceExtFound = 1;
2661                 demo->extension_names[demo->enabled_extension_count++] =
2662                     VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
2663             }
2664 #endif
2665 #if defined(VK_USE_PLATFORM_XCB_KHR)
2666             if (!strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME,
2667                         instance_extensions[i].extensionName)) {
2668                 platformSurfaceExtFound = 1;
2669                 demo->extension_names[demo->enabled_extension_count++] =
2670                     VK_KHR_XCB_SURFACE_EXTENSION_NAME;
2671             }
2672 #endif
2673 #if defined(VK_USE_PLATFORM_WAYLAND_KHR)
2674             if (!strcmp(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
2675                         instance_extensions[i].extensionName)) {
2676                 platformSurfaceExtFound = 1;
2677                 demo->extension_names[demo->enabled_extension_count++] =
2678                     VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
2679             }
2680 #endif
2681 #if defined(VK_USE_PLATFORM_ANDROID_KHR)
2682             if (!strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
2683                         instance_extensions[i].extensionName)) {
2684                 platformSurfaceExtFound = 1;
2685                 demo->extension_names[demo->enabled_extension_count++] =
2686                     VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
2687             }
2688 #endif
2689             if (!strcmp(VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
2690                         instance_extensions[i].extensionName)) {
2691                 if (demo->validate) {
2692                     demo->extension_names[demo->enabled_extension_count++] =
2693                         VK_EXT_DEBUG_REPORT_EXTENSION_NAME;
2694                 }
2695             }
2696             assert(demo->enabled_extension_count < 64);
2697         }
2698 
2699         free(instance_extensions);
2700     }
2701 
2702     if (!surfaceExtFound) {
2703         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2704                  "the " VK_KHR_SURFACE_EXTENSION_NAME
2705                  " extension.\n\nDo you have a compatible "
2706                  "Vulkan installable client driver (ICD) installed?\nPlease "
2707                  "look at the Getting Started guide for additional "
2708                  "information.\n",
2709                  "vkCreateInstance Failure");
2710     }
2711     if (!platformSurfaceExtFound) {
2712 #if defined(VK_USE_PLATFORM_WIN32_KHR)
2713         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2714                  "the " VK_KHR_WIN32_SURFACE_EXTENSION_NAME
2715                  " extension.\n\nDo you have a compatible "
2716                  "Vulkan installable client driver (ICD) installed?\nPlease "
2717                  "look at the Getting Started guide for additional "
2718                  "information.\n",
2719                  "vkCreateInstance Failure");
2720 #elif defined(VK_USE_PLATFORM_XCB_KHR)
2721         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2722                  "the " VK_KHR_XCB_SURFACE_EXTENSION_NAME
2723                  " extension.\n\nDo you have a compatible "
2724                  "Vulkan installable client driver (ICD) installed?\nPlease "
2725                  "look at the Getting Started guide for additional "
2726                  "information.\n",
2727                  "vkCreateInstance Failure");
2728 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
2729         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2730                  "the " VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
2731                  " extension.\n\nDo you have a compatible "
2732                  "Vulkan installable client driver (ICD) installed?\nPlease "
2733                  "look at the Getting Started guide for additional "
2734                  "information.\n",
2735                  "vkCreateInstance Failure");
2736 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
2737         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2738                  "the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
2739                  " extension.\n\nDo you have a compatible "
2740                  "Vulkan installable client driver (ICD) installed?\nPlease "
2741                  "look at the Getting Started guide for additional "
2742                  "information.\n",
2743                  "vkCreateInstance Failure");
2744 #endif
2745     }
2746 #if defined(VK_USE_PLATFORM_XLIB_KHR)
2747     if (demo->use_xlib && !xlibSurfaceExtFound) {
2748         ERR_EXIT("vkEnumerateInstanceExtensionProperties failed to find "
2749                  "the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME
2750                  " extension.\n\nDo you have a compatible "
2751                  "Vulkan installable client driver (ICD) installed?\nPlease "
2752                  "look at the Getting Started guide for additional "
2753                  "information.\n",
2754                  "vkCreateInstance Failure");
2755     }
2756 #endif
2757     const VkApplicationInfo app = {
2758         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
2759         .pNext = NULL,
2760         .pApplicationName = APP_SHORT_NAME,
2761         .applicationVersion = 0,
2762         .pEngineName = APP_SHORT_NAME,
2763         .engineVersion = 0,
2764         .apiVersion = VK_API_VERSION_1_0,
2765     };
2766     VkInstanceCreateInfo inst_info = {
2767         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
2768         .pNext = NULL,
2769         .pApplicationInfo = &app,
2770         .enabledLayerCount = demo->enabled_layer_count,
2771         .ppEnabledLayerNames = (const char *const *)instance_validation_layers,
2772         .enabledExtensionCount = demo->enabled_extension_count,
2773         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2774     };
2775 
2776     /*
2777      * This is info for a temp callback to use during CreateInstance.
2778      * After the instance is created, we use the instance-based
2779      * function to register the final callback.
2780      */
2781     VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2782     if (demo->validate) {
2783         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2784         dbgCreateInfo.pNext = NULL;
2785         dbgCreateInfo.pfnCallback = demo->use_break ? BreakCallback : dbgFunc;
2786         dbgCreateInfo.pUserData = demo;
2787         dbgCreateInfo.flags =
2788             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2789         inst_info.pNext = &dbgCreateInfo;
2790     }
2791 
2792     uint32_t gpu_count;
2793 
2794     err = vkCreateInstance(&inst_info, NULL, &demo->inst);
2795     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
2796         ERR_EXIT("Cannot find a compatible Vulkan installable client driver "
2797                  "(ICD).\n\nPlease look at the Getting Started guide for "
2798                  "additional information.\n",
2799                  "vkCreateInstance Failure");
2800     } else if (err == VK_ERROR_EXTENSION_NOT_PRESENT) {
2801         ERR_EXIT("Cannot find a specified extension library"
2802                  ".\nMake sure your layers path is set appropriately.\n",
2803                  "vkCreateInstance Failure");
2804     } else if (err) {
2805         ERR_EXIT("vkCreateInstance failed.\n\nDo you have a compatible Vulkan "
2806                  "installable client driver (ICD) installed?\nPlease look at "
2807                  "the Getting Started guide for additional information.\n",
2808                  "vkCreateInstance Failure");
2809     }
2810 
2811     /* Make initial call to query gpu_count, then second call for gpu info*/
2812     err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, NULL);
2813     assert(!err && gpu_count > 0);
2814 
2815     if (gpu_count > 0) {
2816         VkPhysicalDevice *physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
2817         err = vkEnumeratePhysicalDevices(demo->inst, &gpu_count, physical_devices);
2818         assert(!err);
2819         /* For cube demo we just grab the first physical device */
2820         demo->gpu = physical_devices[0];
2821         free(physical_devices);
2822     } else {
2823         ERR_EXIT("vkEnumeratePhysicalDevices reported zero accessible devices.\n\n"
2824                  "Do you have a compatible Vulkan installable client driver (ICD) "
2825                  "installed?\nPlease look at the Getting Started guide for "
2826                  "additional information.\n",
2827                  "vkEnumeratePhysicalDevices Failure");
2828     }
2829 
2830     /* Look for device extensions */
2831     uint32_t device_extension_count = 0;
2832     VkBool32 swapchainExtFound = 0;
2833     demo->enabled_extension_count = 0;
2834     memset(demo->extension_names, 0, sizeof(demo->extension_names));
2835 
2836     err = vkEnumerateDeviceExtensionProperties(demo->gpu, NULL,
2837                                                &device_extension_count, NULL);
2838     assert(!err);
2839 
2840     if (device_extension_count > 0) {
2841         VkExtensionProperties *device_extensions =
2842             malloc(sizeof(VkExtensionProperties) * device_extension_count);
2843         err = vkEnumerateDeviceExtensionProperties(
2844             demo->gpu, NULL, &device_extension_count, device_extensions);
2845         assert(!err);
2846 
2847         for (uint32_t i = 0; i < device_extension_count; i++) {
2848             if (!strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,
2849                         device_extensions[i].extensionName)) {
2850                 swapchainExtFound = 1;
2851                 demo->extension_names[demo->enabled_extension_count++] =
2852                     VK_KHR_SWAPCHAIN_EXTENSION_NAME;
2853             }
2854             assert(demo->enabled_extension_count < 64);
2855         }
2856 
2857         free(device_extensions);
2858     }
2859 
2860     if (!swapchainExtFound) {
2861         ERR_EXIT("vkEnumerateDeviceExtensionProperties failed to find "
2862                  "the " VK_KHR_SWAPCHAIN_EXTENSION_NAME
2863                  " extension.\n\nDo you have a compatible "
2864                  "Vulkan installable client driver (ICD) installed?\nPlease "
2865                  "look at the Getting Started guide for additional "
2866                  "information.\n",
2867                  "vkCreateInstance Failure");
2868     }
2869 
2870     if (demo->validate) {
2871         demo->CreateDebugReportCallback =
2872             (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(
2873                 demo->inst, "vkCreateDebugReportCallbackEXT");
2874         demo->DestroyDebugReportCallback =
2875             (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(
2876                 demo->inst, "vkDestroyDebugReportCallbackEXT");
2877         if (!demo->CreateDebugReportCallback) {
2878             ERR_EXIT(
2879                 "GetProcAddr: Unable to find vkCreateDebugReportCallbackEXT\n",
2880                 "vkGetProcAddr Failure");
2881         }
2882         if (!demo->DestroyDebugReportCallback) {
2883             ERR_EXIT(
2884                 "GetProcAddr: Unable to find vkDestroyDebugReportCallbackEXT\n",
2885                 "vkGetProcAddr Failure");
2886         }
2887         demo->DebugReportMessage =
2888             (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(
2889                 demo->inst, "vkDebugReportMessageEXT");
2890         if (!demo->DebugReportMessage) {
2891             ERR_EXIT("GetProcAddr: Unable to find vkDebugReportMessageEXT\n",
2892                      "vkGetProcAddr Failure");
2893         }
2894 
2895         VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
2896         PFN_vkDebugReportCallbackEXT callback;
2897         callback = demo->use_break ? BreakCallback : dbgFunc;
2898         dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
2899         dbgCreateInfo.pNext = NULL;
2900         dbgCreateInfo.pfnCallback = callback;
2901         dbgCreateInfo.pUserData = demo;
2902         dbgCreateInfo.flags =
2903             VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
2904         err = demo->CreateDebugReportCallback(demo->inst, &dbgCreateInfo, NULL,
2905                                               &demo->msg_callback);
2906         switch (err) {
2907         case VK_SUCCESS:
2908             break;
2909         case VK_ERROR_OUT_OF_HOST_MEMORY:
2910             ERR_EXIT("CreateDebugReportCallback: out of host memory\n",
2911                      "CreateDebugReportCallback Failure");
2912             break;
2913         default:
2914             ERR_EXIT("CreateDebugReportCallback: unknown failure\n",
2915                      "CreateDebugReportCallback Failure");
2916             break;
2917         }
2918     }
2919     vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
2920 
2921     /* Call with NULL data to get count */
2922     vkGetPhysicalDeviceQueueFamilyProperties(demo->gpu,
2923                                              &demo->queue_family_count, NULL);
2924     assert(demo->queue_family_count >= 1);
2925 
2926     demo->queue_props = (VkQueueFamilyProperties *)malloc(
2927         demo->queue_family_count * sizeof(VkQueueFamilyProperties));
2928     vkGetPhysicalDeviceQueueFamilyProperties(
2929         demo->gpu, &demo->queue_family_count, demo->queue_props);
2930 
2931     // Query fine-grained feature support for this device.
2932     //  If app has specific feature requirements it should check supported
2933     //  features based on this query
2934     VkPhysicalDeviceFeatures physDevFeatures;
2935     vkGetPhysicalDeviceFeatures(demo->gpu, &physDevFeatures);
2936 
2937     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportKHR);
2938     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceCapabilitiesKHR);
2939     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceFormatsKHR);
2940     GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfacePresentModesKHR);
2941     GET_INSTANCE_PROC_ADDR(demo->inst, GetSwapchainImagesKHR);
2942 }
2943 
demo_create_device(struct demo * demo)2944 static void demo_create_device(struct demo *demo) {
2945     VkResult U_ASSERT_ONLY err;
2946     float queue_priorities[1] = {0.0};
2947     VkDeviceQueueCreateInfo queues[2];
2948     queues[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
2949     queues[0].pNext = NULL;
2950     queues[0].queueFamilyIndex = demo->graphics_queue_family_index;
2951     queues[0].queueCount = 1;
2952     queues[0].pQueuePriorities = queue_priorities;
2953     queues[0].flags = 0;
2954 
2955     VkDeviceCreateInfo device = {
2956         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2957         .pNext = NULL,
2958         .queueCreateInfoCount = 1,
2959         .pQueueCreateInfos = queues,
2960         .enabledLayerCount = 0,
2961         .ppEnabledLayerNames = NULL,
2962         .enabledExtensionCount = demo->enabled_extension_count,
2963         .ppEnabledExtensionNames = (const char *const *)demo->extension_names,
2964         .pEnabledFeatures =
2965             NULL, // If specific features are required, pass them in here
2966     };
2967     if (demo->separate_present_queue) {
2968         queues[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
2969         queues[1].pNext = NULL;
2970         queues[1].queueFamilyIndex = demo->present_queue_family_index;
2971         queues[1].queueCount = 1;
2972         queues[1].pQueuePriorities = queue_priorities;
2973         queues[1].flags = 0;
2974         device.queueCreateInfoCount = 2;
2975     }
2976     err = vkCreateDevice(demo->gpu, &device, NULL, &demo->device);
2977     assert(!err);
2978 }
2979 
demo_init_vk_swapchain(struct demo * demo)2980 static void demo_init_vk_swapchain(struct demo *demo) {
2981     VkResult U_ASSERT_ONLY err;
2982     uint32_t i;
2983 
2984 // Create a WSI surface for the window:
2985 #if defined(VK_USE_PLATFORM_WIN32_KHR)
2986     VkWin32SurfaceCreateInfoKHR createInfo;
2987     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2988     createInfo.pNext = NULL;
2989     createInfo.flags = 0;
2990     createInfo.hinstance = demo->connection;
2991     createInfo.hwnd = demo->window;
2992 
2993     err =
2994         vkCreateWin32SurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
2995 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
2996     VkWaylandSurfaceCreateInfoKHR createInfo;
2997     createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
2998     createInfo.pNext = NULL;
2999     createInfo.flags = 0;
3000     createInfo.display = demo->display;
3001     createInfo.surface = demo->window;
3002 
3003     err = vkCreateWaylandSurfaceKHR(demo->inst, &createInfo, NULL,
3004                                     &demo->surface);
3005 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
3006     VkAndroidSurfaceCreateInfoKHR createInfo;
3007     createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
3008     createInfo.pNext = NULL;
3009     createInfo.flags = 0;
3010     createInfo.window = (ANativeWindow*)(demo->window);
3011 
3012     err = vkCreateAndroidSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
3013 #endif
3014     if (demo->use_xlib) {
3015 #if defined(VK_USE_PLATFORM_XLIB_KHR)
3016         VkXlibSurfaceCreateInfoKHR createInfo;
3017         createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
3018         createInfo.pNext = NULL;
3019         createInfo.flags = 0;
3020         createInfo.dpy = demo->display;
3021         createInfo.window = demo->xlib_window;
3022 
3023         err = vkCreateXlibSurfaceKHR(demo->inst, &createInfo, NULL,
3024                                      &demo->surface);
3025 #endif
3026     }
3027     else {
3028 #if defined(VK_USE_PLATFORM_XCB_KHR)
3029         VkXcbSurfaceCreateInfoKHR createInfo;
3030         createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
3031         createInfo.pNext = NULL;
3032         createInfo.flags = 0;
3033         createInfo.connection = demo->connection;
3034         createInfo.window = demo->xcb_window;
3035 
3036         err = vkCreateXcbSurfaceKHR(demo->inst, &createInfo, NULL, &demo->surface);
3037 #endif
3038     }
3039     assert(!err);
3040 
3041     // Iterate over each queue to learn whether it supports presenting:
3042     VkBool32 *supportsPresent =
3043         (VkBool32 *)malloc(demo->queue_family_count * sizeof(VkBool32));
3044     for (i = 0; i < demo->queue_family_count; i++) {
3045         demo->fpGetPhysicalDeviceSurfaceSupportKHR(demo->gpu, i, demo->surface,
3046                                                    &supportsPresent[i]);
3047     }
3048 
3049     // Search for a graphics and a present queue in the array of queue
3050     // families, try to find one that supports both
3051     uint32_t graphicsQueueFamilyIndex = UINT32_MAX;
3052     uint32_t presentQueueFamilyIndex = UINT32_MAX;
3053     for (i = 0; i < demo->queue_family_count; i++) {
3054         if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
3055             if (graphicsQueueFamilyIndex == UINT32_MAX) {
3056                 graphicsQueueFamilyIndex = i;
3057             }
3058 
3059             if (supportsPresent[i] == VK_TRUE) {
3060                 graphicsQueueFamilyIndex = i;
3061                 presentQueueFamilyIndex = i;
3062                 break;
3063             }
3064         }
3065     }
3066 
3067     if (presentQueueFamilyIndex == UINT32_MAX) {
3068         // If didn't find a queue that supports both graphics and present, then
3069         // find a separate present queue.
3070         for (i = 0; i < demo->queue_family_count; ++i) {
3071             if (supportsPresent[i] == VK_TRUE) {
3072                 presentQueueFamilyIndex = i;
3073                 break;
3074             }
3075         }
3076     }
3077 
3078     // Generate error if could not find both a graphics and a present queue
3079     if (graphicsQueueFamilyIndex == UINT32_MAX ||
3080         presentQueueFamilyIndex == UINT32_MAX) {
3081         ERR_EXIT("Could not find both graphics and present queues\n",
3082                  "Swapchain Initialization Failure");
3083     }
3084 
3085     demo->graphics_queue_family_index = graphicsQueueFamilyIndex;
3086     demo->present_queue_family_index = presentQueueFamilyIndex;
3087     demo->separate_present_queue =
3088         (demo->graphics_queue_family_index != demo->present_queue_family_index);
3089     free(supportsPresent);
3090 
3091     demo_create_device(demo);
3092 
3093     GET_DEVICE_PROC_ADDR(demo->device, CreateSwapchainKHR);
3094     GET_DEVICE_PROC_ADDR(demo->device, DestroySwapchainKHR);
3095     GET_DEVICE_PROC_ADDR(demo->device, GetSwapchainImagesKHR);
3096     GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageKHR);
3097     GET_DEVICE_PROC_ADDR(demo->device, QueuePresentKHR);
3098 
3099     vkGetDeviceQueue(demo->device, demo->graphics_queue_family_index, 0,
3100                      &demo->graphics_queue);
3101 
3102     if (!demo->separate_present_queue) {
3103         demo->present_queue = demo->graphics_queue;
3104     } else {
3105         vkGetDeviceQueue(demo->device, demo->present_queue_family_index, 0,
3106                          &demo->present_queue);
3107     }
3108 
3109     // Get the list of VkFormat's that are supported:
3110     uint32_t formatCount;
3111     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
3112                                                      &formatCount, NULL);
3113     assert(!err);
3114     VkSurfaceFormatKHR *surfFormats =
3115         (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
3116     err = demo->fpGetPhysicalDeviceSurfaceFormatsKHR(demo->gpu, demo->surface,
3117                                                      &formatCount, surfFormats);
3118     assert(!err);
3119     // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
3120     // the surface has no preferred format.  Otherwise, at least one
3121     // supported format will be returned.
3122     if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED) {
3123         demo->format = VK_FORMAT_B8G8R8A8_UNORM;
3124     } else {
3125         assert(formatCount >= 1);
3126         demo->format = surfFormats[0].format;
3127     }
3128     demo->color_space = surfFormats[0].colorSpace;
3129 
3130     demo->quit = false;
3131     demo->curFrame = 0;
3132 
3133     // Create semaphores to synchronize acquiring presentable buffers before
3134     // rendering and waiting for drawing to be complete before presenting
3135     VkSemaphoreCreateInfo semaphoreCreateInfo = {
3136         .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
3137         .pNext = NULL,
3138         .flags = 0,
3139     };
3140 
3141     // Create fences that we can use to throttle if we get too far
3142     // ahead of the image presents
3143     VkFenceCreateInfo fence_ci = {
3144         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
3145         .pNext = NULL,
3146         .flags = VK_FENCE_CREATE_SIGNALED_BIT
3147     };
3148     for (uint32_t i = 0; i < FRAME_LAG; i++) {
3149         vkCreateFence(demo->device, &fence_ci, NULL, &demo->fences[i]);
3150         err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
3151                                 &demo->image_acquired_semaphores[i]);
3152         assert(!err);
3153 
3154         err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
3155                                 &demo->draw_complete_semaphores[i]);
3156         assert(!err);
3157 
3158         if (demo->separate_present_queue) {
3159             err = vkCreateSemaphore(demo->device, &semaphoreCreateInfo, NULL,
3160                                     &demo->image_ownership_semaphores[i]);
3161             assert(!err);
3162         }
3163     }
3164     demo->frame_index = 0;
3165 
3166     // Get Memory information and properties
3167     vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
3168 }
3169 
3170 #if defined(VK_USE_PLATFORM_WAYLAND_KHR) && !defined(VK_USE_PLATFORM_XCB_KHR)
registry_handle_global(void * data,struct wl_registry * registry,uint32_t name,const char * interface,uint32_t version UNUSED)3171 static void registry_handle_global(void *data, struct wl_registry *registry,
3172                                    uint32_t name, const char *interface,
3173                                    uint32_t version UNUSED) {
3174     struct demo *demo = data;
3175     if (strcmp(interface, "wl_compositor") == 0) {
3176         demo->compositor =
3177             wl_registry_bind(registry, name, &wl_compositor_interface, 3);
3178         /* Todo: When xdg_shell protocol has stablized, we should move wl_shell
3179          * tp xdg_shell */
3180     } else if (strcmp(interface, "wl_shell") == 0) {
3181         demo->shell = wl_registry_bind(registry, name, &wl_shell_interface, 1);
3182     }
3183 }
3184 
registry_handle_global_remove(void * data UNUSED,struct wl_registry * registry UNUSED,uint32_t name UNUSED)3185 static void registry_handle_global_remove(void *data UNUSED,
3186                                           struct wl_registry *registry UNUSED,
3187                                           uint32_t name UNUSED) {}
3188 
3189 static const struct wl_registry_listener registry_listener = {
3190     registry_handle_global, registry_handle_global_remove};
3191 #endif
3192 
demo_init_connection(struct demo * demo)3193 static void demo_init_connection(struct demo *demo) {
3194 #if defined(VK_USE_PLATFORM_XCB_KHR)
3195     const xcb_setup_t *setup;
3196     xcb_screen_iterator_t iter;
3197     int scr;
3198 
3199     demo->connection = xcb_connect(NULL, &scr);
3200     if (xcb_connection_has_error(demo->connection) > 0) {
3201         printf("Cannot find a compatible Vulkan installable client driver "
3202                "(ICD).\nExiting ...\n");
3203         fflush(stdout);
3204         exit(1);
3205     }
3206 
3207     setup = xcb_get_setup(demo->connection);
3208     iter = xcb_setup_roots_iterator(setup);
3209     while (scr-- > 0)
3210         xcb_screen_next(&iter);
3211 
3212     demo->screen = iter.data;
3213 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
3214     demo->display = wl_display_connect(NULL);
3215 
3216     if (demo->display == NULL) {
3217         printf("Cannot find a compatible Vulkan installable client driver "
3218                "(ICD).\nExiting ...\n");
3219         fflush(stdout);
3220         exit(1);
3221     }
3222 
3223     demo->registry = wl_display_get_registry(demo->display);
3224     wl_registry_add_listener(demo->registry, &registry_listener, demo);
3225     wl_display_dispatch(demo->display);
3226 #endif
3227 }
3228 
demo_init(struct demo * demo,int argc,char ** argv)3229 static void demo_init(struct demo *demo, int argc, char **argv) {
3230     vec3 eye = {0.0f, 3.0f, 5.0f};
3231     vec3 origin = {0, 0, 0};
3232     vec3 up = {0.0f, 1.0f, 0.0};
3233 
3234     memset(demo, 0, sizeof(*demo));
3235     demo->frameCount = INT32_MAX;
3236 
3237     for (int i = 1; i < argc; i++) {
3238         if (strcmp(argv[i], "--use_staging") == 0) {
3239             demo->use_staging_buffer = true;
3240             continue;
3241         }
3242         if (strcmp(argv[i], "--break") == 0) {
3243             demo->use_break = true;
3244             continue;
3245         }
3246         if (strcmp(argv[i], "--validate") == 0) {
3247             demo->validate = true;
3248             continue;
3249         }
3250 #if defined(VK_USE_PLATFORM_XLIB_KHR)
3251         if (strcmp(argv[i], "--xlib") == 0) {
3252             demo->use_xlib = true;
3253             continue;
3254         }
3255 #endif
3256         if (strcmp(argv[i], "--c") == 0 && demo->frameCount == INT32_MAX &&
3257             i < argc - 1 && sscanf(argv[i + 1], "%d", &demo->frameCount) == 1 &&
3258             demo->frameCount >= 0) {
3259             i++;
3260             continue;
3261         }
3262         if (strcmp(argv[i], "--suppress_popups") == 0) {
3263             demo->suppress_popups = true;
3264             continue;
3265         }
3266 
3267 #if defined(ANDROID)
3268         ERR_EXIT("Usage: cube [--validate]\n", "Usage");
3269 #else
3270         fprintf(stderr, "Usage:\n  %s [--use_staging] [--validate] [--break] "
3271 #if defined(VK_USE_PLATFORM_XLIB_KHR)
3272                         "[--xlib] "
3273 #endif
3274                         "[--c <framecount>] [--suppress_popups]\n",
3275                 APP_SHORT_NAME);
3276         fflush(stderr);
3277         exit(1);
3278 #endif
3279     }
3280 
3281     if (!demo->use_xlib)
3282         demo_init_connection(demo);
3283 
3284     demo_init_vk(demo);
3285 
3286     demo->width = 500;
3287     demo->height = 500;
3288 
3289     demo->spin_angle = 4.0f;
3290     demo->spin_increment = 0.2f;
3291     demo->pause = false;
3292 
3293     mat4x4_perspective(demo->projection_matrix, (float)degreesToRadians(45.0f),
3294                        1.0f, 0.1f, 100.0f);
3295     mat4x4_look_at(demo->view_matrix, eye, origin, up);
3296     mat4x4_identity(demo->model_matrix);
3297 
3298     demo->projection_matrix[1][1]*=-1;  //Flip projection matrix from GL to Vulkan orientation.
3299 }
3300 
3301 #if defined(VK_USE_PLATFORM_WIN32_KHR)
3302 // Include header required for parsing the command line options.
3303 #include <shellapi.h>
3304 
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR pCmdLine,int nCmdShow)3305 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine,
3306                    int nCmdShow) {
3307     MSG msg;   // message
3308     bool done; // flag saying when app is complete
3309     int argc;
3310     char **argv;
3311 
3312     // Use the CommandLine functions to get the command line arguments.
3313     // Unfortunately, Microsoft outputs
3314     // this information as wide characters for Unicode, and we simply want the
3315     // Ascii version to be compatible
3316     // with the non-Windows side.  So, we have to convert the information to
3317     // Ascii character strings.
3318     LPWSTR *commandLineArgs = CommandLineToArgvW(GetCommandLineW(), &argc);
3319     if (NULL == commandLineArgs) {
3320         argc = 0;
3321     }
3322 
3323     if (argc > 0) {
3324         argv = (char **)malloc(sizeof(char *) * argc);
3325         if (argv == NULL) {
3326             argc = 0;
3327         } else {
3328             for (int iii = 0; iii < argc; iii++) {
3329                 size_t wideCharLen = wcslen(commandLineArgs[iii]);
3330                 size_t numConverted = 0;
3331 
3332                 argv[iii] = (char *)malloc(sizeof(char) * (wideCharLen + 1));
3333                 if (argv[iii] != NULL) {
3334                     wcstombs_s(&numConverted, argv[iii], wideCharLen + 1,
3335                                commandLineArgs[iii], wideCharLen + 1);
3336                 }
3337             }
3338         }
3339     } else {
3340         argv = NULL;
3341     }
3342 
3343     demo_init(&demo, argc, argv);
3344 
3345     // Free up the items we had to allocate for the command line arguments.
3346     if (argc > 0 && argv != NULL) {
3347         for (int iii = 0; iii < argc; iii++) {
3348             if (argv[iii] != NULL) {
3349                 free(argv[iii]);
3350             }
3351         }
3352         free(argv);
3353     }
3354 
3355     demo.connection = hInstance;
3356     strncpy(demo.name, "cube", APP_NAME_STR_LEN);
3357     demo_create_window(&demo);
3358     demo_init_vk_swapchain(&demo);
3359 
3360     demo_prepare(&demo);
3361 
3362     done = false; // initialize loop condition variable
3363 
3364     // main message loop
3365     while (!done) {
3366         PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
3367         if (msg.message == WM_QUIT) // check for a quit message
3368         {
3369             done = true; // if found, quit app
3370         } else {
3371             /* Translate and dispatch to event queue*/
3372             TranslateMessage(&msg);
3373             DispatchMessage(&msg);
3374         }
3375         RedrawWindow(demo.window, NULL, NULL, RDW_INTERNALPAINT);
3376     }
3377 
3378     demo_cleanup(&demo);
3379 
3380     return (int)msg.wParam;
3381 }
3382 #elif defined(VK_USE_PLATFORM_ANDROID_KHR)
3383 #include <android/log.h>
3384 #include <android_native_app_glue.h>
3385 #include "android_util.h"
3386 
3387 static bool initialized = false;
3388 static bool active = false;
3389 struct demo demo;
3390 
processInput(struct android_app * app,AInputEvent * event)3391 static int32_t processInput(struct android_app* app, AInputEvent* event) {
3392     return 0;
3393 }
3394 
processCommand(struct android_app * app,int32_t cmd)3395 static void processCommand(struct android_app* app, int32_t cmd) {
3396     switch(cmd) {
3397         case APP_CMD_INIT_WINDOW: {
3398             if (app->window) {
3399                 // We're getting a new window.  If the app is starting up, we
3400                 // need to initialize.  If the app has already been
3401                 // initialized, that means that we lost our previous window,
3402                 // which means that we have a lot of work to do.  At a minimum,
3403                 // we need to destroy the swapchain and surface associated with
3404                 // the old window, and create a new surface and swapchain.
3405                 // However, since there are a lot of other objects/state that
3406                 // is tied to the swapchain, it's easiest to simply cleanup and
3407                 // start over (i.e. use a brute-force approach of re-starting
3408                 // the app)
3409                 if (demo.prepared) {
3410                     demo_cleanup(&demo);
3411                 }
3412 
3413                 // Parse Intents into argc, argv
3414                 // Use the following key to send arguments, i.e.
3415                 // --es args "--validate"
3416                 const char key[] = "args";
3417                 char* appTag = (char*) APP_SHORT_NAME;
3418                 int argc = 0;
3419                 char** argv = get_args(app, key, appTag, &argc);
3420 
3421                 __android_log_print(ANDROID_LOG_INFO, appTag, "argc = %i", argc);
3422                 for (int i = 0; i < argc; i++)
3423                     __android_log_print(ANDROID_LOG_INFO, appTag, "argv[%i] = %s", i, argv[i]);
3424 
3425                 demo_init(&demo, argc, argv);
3426 
3427                 // Free the argv malloc'd by get_args
3428                 for (int i = 0; i < argc; i++)
3429                     free(argv[i]);
3430 
3431                 demo.window = (void*)app->window;
3432                 demo_init_vk_swapchain(&demo);
3433                 demo_prepare(&demo);
3434                 initialized = true;
3435             }
3436             break;
3437         }
3438         case APP_CMD_GAINED_FOCUS: {
3439             active = true;
3440             break;
3441         }
3442         case APP_CMD_LOST_FOCUS: {
3443             active = false;
3444             break;
3445         }
3446     }
3447 }
3448 
android_main(struct android_app * app)3449 void android_main(struct android_app *app)
3450 {
3451     app_dummy();
3452 
3453 #ifdef ANDROID
3454     int vulkanSupport = InitVulkan();
3455     if (vulkanSupport == 0)
3456         return;
3457 #endif
3458 
3459     demo.prepared = false;
3460 
3461     app->onAppCmd = processCommand;
3462     app->onInputEvent = processInput;
3463 
3464     while(1) {
3465         int events;
3466         struct android_poll_source* source;
3467         while (ALooper_pollAll(active ? 0 : -1, NULL, &events, (void**)&source) >= 0) {
3468             if (source) {
3469                 source->process(app, source);
3470             }
3471 
3472             if (app->destroyRequested != 0) {
3473                 demo_cleanup(&demo);
3474                 return;
3475             }
3476         }
3477         if (initialized && active) {
3478             demo_run(&demo);
3479         }
3480     }
3481 
3482 }
3483 #else
main(int argc,char ** argv)3484 int main(int argc, char **argv) {
3485     struct demo demo;
3486 
3487     demo_init(&demo, argc, argv);
3488 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
3489     if (demo.use_xlib)
3490         demo_create_xlib_window(&demo);
3491     else
3492         demo_create_xcb_window(&demo);
3493 #elif defined(VK_USE_PLATFORM_XCB_KHR)
3494     demo_create_xcb_window(&demo);
3495 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
3496     demo_create_xlib_window(&demo);
3497 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
3498     demo_create_window(&demo);
3499 #endif
3500 
3501     demo_init_vk_swapchain(&demo);
3502 
3503     demo_prepare(&demo);
3504 
3505 #if defined(VK_USE_PLATFORM_XLIB_KHR) && defined(VK_USE_PLATFORM_XCB_KHR)
3506     if (demo.use_xlib)
3507         demo_run_xlib(&demo);
3508     else
3509         demo_run_xcb(&demo);
3510 #elif defined(VK_USE_PLATFORM_XCB_KHR)
3511     demo_run_xcb(&demo);
3512 #elif defined(VK_USE_PLATFORM_XLIB_KHR)
3513     demo_run_xlib(&demo);
3514 #elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
3515     demo_run(&demo);
3516 #endif
3517 
3518     demo_cleanup(&demo);
3519 
3520     return validation_error;
3521 }
3522 #endif
3523