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, ©_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