1 | // Copyright (c) 2015-2016 The Khronos Group Inc. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #include "source/spirv_target_env.h" |
16 | |
17 | #include <cstring> |
18 | #include <string> |
19 | |
20 | #include "source/spirv_constant.h" |
21 | #include "spirv-tools/libspirv.h" |
22 | |
23 | const char* spvTargetEnvDescription(spv_target_env env) { |
24 | switch (env) { |
25 | case SPV_ENV_UNIVERSAL_1_0: |
26 | return "SPIR-V 1.0" ; |
27 | case SPV_ENV_VULKAN_1_0: |
28 | return "SPIR-V 1.0 (under Vulkan 1.0 semantics)" ; |
29 | case SPV_ENV_UNIVERSAL_1_1: |
30 | return "SPIR-V 1.1" ; |
31 | case SPV_ENV_OPENCL_1_2: |
32 | return "SPIR-V 1.0 (under OpenCL 1.2 Full Profile semantics)" ; |
33 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
34 | return "SPIR-V 1.0 (under OpenCL 1.2 Embedded Profile semantics)" ; |
35 | case SPV_ENV_OPENCL_2_0: |
36 | return "SPIR-V 1.0 (under OpenCL 2.0 Full Profile semantics)" ; |
37 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
38 | return "SPIR-V 1.0 (under OpenCL 2.0 Embedded Profile semantics)" ; |
39 | case SPV_ENV_OPENCL_2_1: |
40 | return "SPIR-V 1.0 (under OpenCL 2.1 Full Profile semantics)" ; |
41 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
42 | return "SPIR-V 1.0 (under OpenCL 2.1 Embedded Profile semantics)" ; |
43 | case SPV_ENV_OPENCL_2_2: |
44 | return "SPIR-V 1.2 (under OpenCL 2.2 Full Profile semantics)" ; |
45 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
46 | return "SPIR-V 1.2 (under OpenCL 2.2 Embedded Profile semantics)" ; |
47 | case SPV_ENV_OPENGL_4_0: |
48 | return "SPIR-V 1.0 (under OpenGL 4.0 semantics)" ; |
49 | case SPV_ENV_OPENGL_4_1: |
50 | return "SPIR-V 1.0 (under OpenGL 4.1 semantics)" ; |
51 | case SPV_ENV_OPENGL_4_2: |
52 | return "SPIR-V 1.0 (under OpenGL 4.2 semantics)" ; |
53 | case SPV_ENV_OPENGL_4_3: |
54 | return "SPIR-V 1.0 (under OpenGL 4.3 semantics)" ; |
55 | case SPV_ENV_OPENGL_4_5: |
56 | return "SPIR-V 1.0 (under OpenGL 4.5 semantics)" ; |
57 | case SPV_ENV_UNIVERSAL_1_2: |
58 | return "SPIR-V 1.2" ; |
59 | case SPV_ENV_UNIVERSAL_1_3: |
60 | return "SPIR-V 1.3" ; |
61 | case SPV_ENV_VULKAN_1_1: |
62 | return "SPIR-V 1.3 (under Vulkan 1.1 semantics)" ; |
63 | case SPV_ENV_WEBGPU_0: |
64 | return "SPIR-V 1.3 (under WIP WebGPU semantics)" ; |
65 | case SPV_ENV_UNIVERSAL_1_4: |
66 | return "SPIR-V 1.4" ; |
67 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
68 | return "SPIR-V 1.4 (under Vulkan 1.1 semantics)" ; |
69 | case SPV_ENV_UNIVERSAL_1_5: |
70 | return "SPIR-V 1.5" ; |
71 | case SPV_ENV_VULKAN_1_2: |
72 | return "SPIR-V 1.5 (under Vulkan 1.2 semantics)" ; |
73 | } |
74 | return "" ; |
75 | } |
76 | |
77 | uint32_t spvVersionForTargetEnv(spv_target_env env) { |
78 | switch (env) { |
79 | case SPV_ENV_UNIVERSAL_1_0: |
80 | case SPV_ENV_VULKAN_1_0: |
81 | case SPV_ENV_OPENCL_1_2: |
82 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
83 | case SPV_ENV_OPENCL_2_0: |
84 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
85 | case SPV_ENV_OPENCL_2_1: |
86 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
87 | case SPV_ENV_OPENGL_4_0: |
88 | case SPV_ENV_OPENGL_4_1: |
89 | case SPV_ENV_OPENGL_4_2: |
90 | case SPV_ENV_OPENGL_4_3: |
91 | case SPV_ENV_OPENGL_4_5: |
92 | return SPV_SPIRV_VERSION_WORD(1, 0); |
93 | case SPV_ENV_UNIVERSAL_1_1: |
94 | return SPV_SPIRV_VERSION_WORD(1, 1); |
95 | case SPV_ENV_UNIVERSAL_1_2: |
96 | case SPV_ENV_OPENCL_2_2: |
97 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
98 | return SPV_SPIRV_VERSION_WORD(1, 2); |
99 | case SPV_ENV_UNIVERSAL_1_3: |
100 | case SPV_ENV_VULKAN_1_1: |
101 | case SPV_ENV_WEBGPU_0: |
102 | return SPV_SPIRV_VERSION_WORD(1, 3); |
103 | case SPV_ENV_UNIVERSAL_1_4: |
104 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
105 | return SPV_SPIRV_VERSION_WORD(1, 4); |
106 | case SPV_ENV_UNIVERSAL_1_5: |
107 | case SPV_ENV_VULKAN_1_2: |
108 | return SPV_SPIRV_VERSION_WORD(1, 5); |
109 | } |
110 | return SPV_SPIRV_VERSION_WORD(0, 0); |
111 | } |
112 | |
113 | static const std::pair<const char*, spv_target_env> spvTargetEnvNameMap[] = { |
114 | {"vulkan1.1spv1.4" , SPV_ENV_VULKAN_1_1_SPIRV_1_4}, |
115 | {"vulkan1.0" , SPV_ENV_VULKAN_1_0}, |
116 | {"vulkan1.1" , SPV_ENV_VULKAN_1_1}, |
117 | {"vulkan1.2" , SPV_ENV_VULKAN_1_2}, |
118 | {"spv1.0" , SPV_ENV_UNIVERSAL_1_0}, |
119 | {"spv1.1" , SPV_ENV_UNIVERSAL_1_1}, |
120 | {"spv1.2" , SPV_ENV_UNIVERSAL_1_2}, |
121 | {"spv1.3" , SPV_ENV_UNIVERSAL_1_3}, |
122 | {"spv1.4" , SPV_ENV_UNIVERSAL_1_4}, |
123 | {"spv1.5" , SPV_ENV_UNIVERSAL_1_5}, |
124 | {"opencl1.2embedded" , SPV_ENV_OPENCL_EMBEDDED_1_2}, |
125 | {"opencl1.2" , SPV_ENV_OPENCL_1_2}, |
126 | {"opencl2.0embedded" , SPV_ENV_OPENCL_EMBEDDED_2_0}, |
127 | {"opencl2.0" , SPV_ENV_OPENCL_2_0}, |
128 | {"opencl2.1embedded" , SPV_ENV_OPENCL_EMBEDDED_2_1}, |
129 | {"opencl2.1" , SPV_ENV_OPENCL_2_1}, |
130 | {"opencl2.2embedded" , SPV_ENV_OPENCL_EMBEDDED_2_2}, |
131 | {"opencl2.2" , SPV_ENV_OPENCL_2_2}, |
132 | {"opengl4.0" , SPV_ENV_OPENGL_4_0}, |
133 | {"opengl4.1" , SPV_ENV_OPENGL_4_1}, |
134 | {"opengl4.2" , SPV_ENV_OPENGL_4_2}, |
135 | {"opengl4.3" , SPV_ENV_OPENGL_4_3}, |
136 | {"opengl4.5" , SPV_ENV_OPENGL_4_5}, |
137 | {"webgpu0" , SPV_ENV_WEBGPU_0}, |
138 | }; |
139 | |
140 | bool spvParseTargetEnv(const char* s, spv_target_env* env) { |
141 | auto match = [s](const char* b) { |
142 | return s && (0 == strncmp(s, b, strlen(b))); |
143 | }; |
144 | for (auto& name_env : spvTargetEnvNameMap) { |
145 | if (match(name_env.first)) { |
146 | if (env) { |
147 | *env = name_env.second; |
148 | } |
149 | return true; |
150 | } |
151 | } |
152 | if (env) *env = SPV_ENV_UNIVERSAL_1_0; |
153 | return false; |
154 | } |
155 | |
156 | #define VULKAN_VER(MAJOR, MINOR) ((MAJOR << 22) | (MINOR << 12)) |
157 | #define SPIRV_VER(MAJOR, MINOR) ((MAJOR << 16) | (MINOR << 8)) |
158 | |
159 | struct VulkanEnv { |
160 | spv_target_env vulkan_env; |
161 | uint32_t vulkan_ver; |
162 | uint32_t spirv_ver; |
163 | }; |
164 | // Maps each Vulkan target environment enum to the Vulkan version, and the |
165 | // maximum supported SPIR-V version for that Vulkan environment. |
166 | // Keep this ordered from least capable to most capable. |
167 | static const VulkanEnv ordered_vulkan_envs[] = { |
168 | {SPV_ENV_VULKAN_1_0, VULKAN_VER(1, 0), SPIRV_VER(1, 0)}, |
169 | {SPV_ENV_VULKAN_1_1, VULKAN_VER(1, 1), SPIRV_VER(1, 3)}, |
170 | {SPV_ENV_VULKAN_1_1_SPIRV_1_4, VULKAN_VER(1, 1), SPIRV_VER(1, 4)}, |
171 | {SPV_ENV_VULKAN_1_2, VULKAN_VER(1, 2), SPIRV_VER(1, 5)}}; |
172 | |
173 | bool spvParseVulkanEnv(uint32_t vulkan_ver, uint32_t spirv_ver, |
174 | spv_target_env* env) { |
175 | for (auto triple : ordered_vulkan_envs) { |
176 | if (triple.vulkan_ver >= vulkan_ver && triple.spirv_ver >= spirv_ver) { |
177 | *env = triple.vulkan_env; |
178 | return true; |
179 | } |
180 | } |
181 | return false; |
182 | } |
183 | |
184 | bool spvIsVulkanEnv(spv_target_env env) { |
185 | switch (env) { |
186 | case SPV_ENV_UNIVERSAL_1_0: |
187 | case SPV_ENV_OPENCL_1_2: |
188 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
189 | case SPV_ENV_OPENCL_2_0: |
190 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
191 | case SPV_ENV_OPENCL_2_1: |
192 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
193 | case SPV_ENV_OPENGL_4_0: |
194 | case SPV_ENV_OPENGL_4_1: |
195 | case SPV_ENV_OPENGL_4_2: |
196 | case SPV_ENV_OPENGL_4_3: |
197 | case SPV_ENV_OPENGL_4_5: |
198 | case SPV_ENV_UNIVERSAL_1_1: |
199 | case SPV_ENV_UNIVERSAL_1_2: |
200 | case SPV_ENV_OPENCL_2_2: |
201 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
202 | case SPV_ENV_UNIVERSAL_1_3: |
203 | case SPV_ENV_WEBGPU_0: |
204 | case SPV_ENV_UNIVERSAL_1_4: |
205 | case SPV_ENV_UNIVERSAL_1_5: |
206 | return false; |
207 | case SPV_ENV_VULKAN_1_0: |
208 | case SPV_ENV_VULKAN_1_1: |
209 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
210 | case SPV_ENV_VULKAN_1_2: |
211 | return true; |
212 | } |
213 | return false; |
214 | } |
215 | |
216 | bool spvIsOpenCLEnv(spv_target_env env) { |
217 | switch (env) { |
218 | case SPV_ENV_UNIVERSAL_1_0: |
219 | case SPV_ENV_VULKAN_1_0: |
220 | case SPV_ENV_UNIVERSAL_1_1: |
221 | case SPV_ENV_OPENGL_4_0: |
222 | case SPV_ENV_OPENGL_4_1: |
223 | case SPV_ENV_OPENGL_4_2: |
224 | case SPV_ENV_OPENGL_4_3: |
225 | case SPV_ENV_OPENGL_4_5: |
226 | case SPV_ENV_UNIVERSAL_1_2: |
227 | case SPV_ENV_UNIVERSAL_1_3: |
228 | case SPV_ENV_VULKAN_1_1: |
229 | case SPV_ENV_WEBGPU_0: |
230 | case SPV_ENV_UNIVERSAL_1_4: |
231 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
232 | case SPV_ENV_UNIVERSAL_1_5: |
233 | case SPV_ENV_VULKAN_1_2: |
234 | return false; |
235 | case SPV_ENV_OPENCL_1_2: |
236 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
237 | case SPV_ENV_OPENCL_2_0: |
238 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
239 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
240 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
241 | case SPV_ENV_OPENCL_2_1: |
242 | case SPV_ENV_OPENCL_2_2: |
243 | return true; |
244 | } |
245 | return false; |
246 | } |
247 | |
248 | bool spvIsWebGPUEnv(spv_target_env env) { |
249 | switch (env) { |
250 | case SPV_ENV_UNIVERSAL_1_0: |
251 | case SPV_ENV_VULKAN_1_0: |
252 | case SPV_ENV_UNIVERSAL_1_1: |
253 | case SPV_ENV_OPENGL_4_0: |
254 | case SPV_ENV_OPENGL_4_1: |
255 | case SPV_ENV_OPENGL_4_2: |
256 | case SPV_ENV_OPENGL_4_3: |
257 | case SPV_ENV_OPENGL_4_5: |
258 | case SPV_ENV_UNIVERSAL_1_2: |
259 | case SPV_ENV_UNIVERSAL_1_3: |
260 | case SPV_ENV_VULKAN_1_1: |
261 | case SPV_ENV_OPENCL_1_2: |
262 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
263 | case SPV_ENV_OPENCL_2_0: |
264 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
265 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
266 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
267 | case SPV_ENV_OPENCL_2_1: |
268 | case SPV_ENV_OPENCL_2_2: |
269 | case SPV_ENV_UNIVERSAL_1_4: |
270 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
271 | case SPV_ENV_UNIVERSAL_1_5: |
272 | case SPV_ENV_VULKAN_1_2: |
273 | return false; |
274 | case SPV_ENV_WEBGPU_0: |
275 | return true; |
276 | } |
277 | return false; |
278 | } |
279 | |
280 | bool spvIsOpenGLEnv(spv_target_env env) { |
281 | switch (env) { |
282 | case SPV_ENV_UNIVERSAL_1_0: |
283 | case SPV_ENV_VULKAN_1_0: |
284 | case SPV_ENV_UNIVERSAL_1_1: |
285 | case SPV_ENV_UNIVERSAL_1_2: |
286 | case SPV_ENV_UNIVERSAL_1_3: |
287 | case SPV_ENV_VULKAN_1_1: |
288 | case SPV_ENV_OPENCL_1_2: |
289 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
290 | case SPV_ENV_OPENCL_2_0: |
291 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
292 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
293 | case SPV_ENV_OPENCL_EMBEDDED_2_2: |
294 | case SPV_ENV_OPENCL_2_1: |
295 | case SPV_ENV_OPENCL_2_2: |
296 | case SPV_ENV_WEBGPU_0: |
297 | case SPV_ENV_UNIVERSAL_1_4: |
298 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: |
299 | case SPV_ENV_UNIVERSAL_1_5: |
300 | case SPV_ENV_VULKAN_1_2: |
301 | return false; |
302 | case SPV_ENV_OPENGL_4_0: |
303 | case SPV_ENV_OPENGL_4_1: |
304 | case SPV_ENV_OPENGL_4_2: |
305 | case SPV_ENV_OPENGL_4_3: |
306 | case SPV_ENV_OPENGL_4_5: |
307 | return true; |
308 | } |
309 | return false; |
310 | } |
311 | |
312 | bool spvIsVulkanOrWebGPUEnv(spv_target_env env) { |
313 | return spvIsVulkanEnv(env) || spvIsWebGPUEnv(env); |
314 | } |
315 | |
316 | std::string spvLogStringForEnv(spv_target_env env) { |
317 | switch (env) { |
318 | case SPV_ENV_OPENCL_1_2: |
319 | case SPV_ENV_OPENCL_2_0: |
320 | case SPV_ENV_OPENCL_2_1: |
321 | case SPV_ENV_OPENCL_2_2: |
322 | case SPV_ENV_OPENCL_EMBEDDED_1_2: |
323 | case SPV_ENV_OPENCL_EMBEDDED_2_0: |
324 | case SPV_ENV_OPENCL_EMBEDDED_2_1: |
325 | case SPV_ENV_OPENCL_EMBEDDED_2_2: { |
326 | return "OpenCL" ; |
327 | } |
328 | case SPV_ENV_OPENGL_4_0: |
329 | case SPV_ENV_OPENGL_4_1: |
330 | case SPV_ENV_OPENGL_4_2: |
331 | case SPV_ENV_OPENGL_4_3: |
332 | case SPV_ENV_OPENGL_4_5: { |
333 | return "OpenGL" ; |
334 | } |
335 | case SPV_ENV_VULKAN_1_0: |
336 | case SPV_ENV_VULKAN_1_1: |
337 | case SPV_ENV_VULKAN_1_1_SPIRV_1_4: { |
338 | case SPV_ENV_VULKAN_1_2: |
339 | return "Vulkan" ; |
340 | } |
341 | case SPV_ENV_WEBGPU_0: { |
342 | return "WebGPU" ; |
343 | } |
344 | case SPV_ENV_UNIVERSAL_1_0: |
345 | case SPV_ENV_UNIVERSAL_1_1: |
346 | case SPV_ENV_UNIVERSAL_1_2: |
347 | case SPV_ENV_UNIVERSAL_1_3: |
348 | case SPV_ENV_UNIVERSAL_1_4: |
349 | case SPV_ENV_UNIVERSAL_1_5: { |
350 | return "Universal" ; |
351 | } |
352 | } |
353 | return "Unknown" ; |
354 | } |
355 | |
356 | std::string spvTargetEnvList(const int pad, const int wrap) { |
357 | std::string ret; |
358 | size_t max_line_len = wrap - pad; // The first line isn't padded |
359 | std::string line; |
360 | std::string sep = "" ; |
361 | |
362 | for (auto& name_env : spvTargetEnvNameMap) { |
363 | std::string word = sep + name_env.first; |
364 | if (line.length() + word.length() > max_line_len) { |
365 | // Adding one word wouldn't fit, commit the line in progress and |
366 | // start a new one. |
367 | ret += line + "\n" ; |
368 | line.assign(pad, ' '); |
369 | // The first line is done. The max length now comprises the |
370 | // padding. |
371 | max_line_len = wrap; |
372 | } |
373 | line += word; |
374 | sep = "|" ; |
375 | } |
376 | |
377 | ret += line; |
378 | |
379 | return ret; |
380 | } |
381 | |