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