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