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