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