Guest User

Vulkan Cube (Always staging)

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