1 // Copyright 2018 The Shaderc Authors. All rights reserved.
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 <spvc/spvc.hpp>
16 
17 #include "spvc_log.h"
18 #include "spvc_private.h"
19 
20 // MSVC 2013 doesn't define __func__
21 #ifndef __func__
22 #define __func__ __FUNCTION__
23 #endif
24 
25 #define CHECK_CONTEXT(context)                                            \
26   do {                                                                    \
27     if (!context) {                                                       \
28       shaderc_spvc::ErrorLog(nullptr)                                     \
29           << "Invoked " << __func__ << " without an initialized context"; \
30       return shaderc_spvc_status_missing_context_error;                   \
31     }                                                                     \
32   } while (0)
33 
34 #define CHECK_CROSS_COMPILER(context, cross_compiler)          \
35   do {                                                         \
36     if (!cross_compiler) {                                     \
37       shaderc_spvc::ErrorLog(context)                          \
38           << "Invoked " << __func__                            \
39           << " without an initialized cross compiler";         \
40       return shaderc_spvc_status_uninitialized_compiler_error; \
41     }                                                          \
42   } while (0)
43 
44 #define CHECK_OPTIONS(context, options)                                   \
45   do {                                                                    \
46     if (!options) {                                                       \
47       shaderc_spvc::ErrorLog(context)                                     \
48           << "Invoked " << __func__ << " without an initialized options"; \
49       return shaderc_spvc_status_missing_options_error;                   \
50     }                                                                     \
51   } while (0)
52 
53 #define CHECK_RESULT(context, result)                                    \
54   do {                                                                   \
55     if (!result) {                                                       \
56       shaderc_spvc::ErrorLog(context)                                    \
57           << "Invoked " << __func__ << " without an initialized result"; \
58       return shaderc_spvc_status_missing_result_error;                   \
59     }                                                                    \
60   } while (0)
61 
62 #define CHECK_OUT_PARAM(context, param, param_str)                 \
63   do {                                                             \
64     if (!param) {                                                  \
65       shaderc_spvc::ErrorLog(context)                              \
66           << "Invoked " << __func__ << " with invalid out param, " \
67           << param_str;                                            \
68       return shaderc_spvc_status_invalid_out_param;                \
69     }                                                              \
70   } while (0)
71 
72 #define CHECK_IN_PARAM(context, param, param_str)                 \
73   do {                                                            \
74     if (!param) {                                                 \
75       shaderc_spvc::ErrorLog(context)                             \
76           << "Invoked " << __func__ << " with invalid in param, " \
77           << param_str;                                           \
78       return shaderc_spvc_status_invalid_in_param;                \
79     }                                                             \
80   } while (0)
81 
82 namespace {
83 
spvc_model_to_spv_model(shaderc_spvc_execution_model model)84 spv::ExecutionModel spvc_model_to_spv_model(
85     shaderc_spvc_execution_model model) {
86   switch (model) {
87     case shaderc_spvc_execution_model_vertex:
88       return spv::ExecutionModel::ExecutionModelVertex;
89     case shaderc_spvc_execution_model_fragment:
90       return spv::ExecutionModel::ExecutionModelFragment;
91     case shaderc_spvc_execution_model_glcompute:
92       return spv::ExecutionModel::ExecutionModelGLCompute;
93     case shaderc_spvc_execution_model_invalid:
94       return spv::ExecutionModel::ExecutionModelMax;
95   }
96 
97   // Older gcc doesn't recognize that all of the possible cases are covered
98   // above.
99   assert(false);
100   return spv::ExecutionModel::ExecutionModelMax;
101 }
102 
spv_model_to_spvc_model(spv::ExecutionModel model)103 shaderc_spvc_execution_model spv_model_to_spvc_model(
104     spv::ExecutionModel model) {
105   switch (model) {
106     case spv::ExecutionModel::ExecutionModelVertex:
107       return shaderc_spvc_execution_model_vertex;
108     case spv::ExecutionModel::ExecutionModelFragment:
109       return shaderc_spvc_execution_model_fragment;
110     case spv::ExecutionModel::ExecutionModelGLCompute:
111       return shaderc_spvc_execution_model_glcompute;
112     default:
113       return shaderc_spvc_execution_model_invalid;
114   }
115 }
116 
get_shader_resources(const spirv_cross::ShaderResources & resources,shaderc_spvc_shader_resource resource)117 const spirv_cross::SmallVector<spirv_cross::Resource>* get_shader_resources(
118     const spirv_cross::ShaderResources& resources,
119     shaderc_spvc_shader_resource resource) {
120   switch (resource) {
121     case shaderc_spvc_shader_resource_uniform_buffers:
122       return &(resources.uniform_buffers);
123     case shaderc_spvc_shader_resource_separate_images:
124       return &(resources.separate_images);
125     case shaderc_spvc_shader_resource_separate_samplers:
126       return &(resources.separate_samplers);
127     case shaderc_spvc_shader_resource_storage_buffers:
128       return &(resources.storage_buffers);
129     case shaderc_spvc_shader_resource_storage_images:
130       return &(resources.storage_images);
131   }
132 
133   // Older gcc doesn't recognize that all of the possible cases are covered
134   // above.
135   assert(false);
136   return nullptr;
137 }
138 
spirv_dim_to_texture_view_dimension(spv::Dim dim,bool arrayed)139 shaderc_spvc_texture_view_dimension spirv_dim_to_texture_view_dimension(
140     spv::Dim dim, bool arrayed) {
141   switch (dim) {
142     case spv::Dim::Dim1D:
143       return shaderc_spvc_texture_view_dimension_e1D;
144     case spv::Dim::Dim2D:
145       if (arrayed) {
146         return shaderc_spvc_texture_view_dimension_e2D_array;
147       } else {
148         return shaderc_spvc_texture_view_dimension_e2D;
149       }
150     case spv::Dim::Dim3D:
151       return shaderc_spvc_texture_view_dimension_e3D;
152     case spv::Dim::DimCube:
153       if (arrayed) {
154         return shaderc_spvc_texture_view_dimension_cube_array;
155       } else {
156         return shaderc_spvc_texture_view_dimension_cube;
157       }
158     default:
159       return shaderc_spvc_texture_view_dimension_undefined;
160   }
161 }
162 
spirv_cross_base_type_to_texture_format_type(spirv_cross::SPIRType::BaseType type)163 shaderc_spvc_texture_format_type spirv_cross_base_type_to_texture_format_type(
164     spirv_cross::SPIRType::BaseType type) {
165   switch (type) {
166     case spirv_cross::SPIRType::Float:
167       return shaderc_spvc_texture_format_type_float;
168     case spirv_cross::SPIRType::Int:
169       return shaderc_spvc_texture_format_type_sint;
170     case spirv_cross::SPIRType::UInt:
171       return shaderc_spvc_texture_format_type_uint;
172     default:
173       return shaderc_spvc_texture_format_type_other;
174   }
175 }
176 
spv_image_format_to_storage_texture_format(spv::ImageFormat format)177 shaderc_spvc_storage_texture_format spv_image_format_to_storage_texture_format(
178     spv::ImageFormat format) {
179   switch (format) {
180     case spv::ImageFormatR8:
181       return shaderc_spvc_storage_texture_format_r8unorm;
182     case spv::ImageFormatR8Snorm:
183       return shaderc_spvc_storage_texture_format_r8snorm;
184     case spv::ImageFormatR8ui:
185       return shaderc_spvc_storage_texture_format_r8uint;
186     case spv::ImageFormatR8i:
187       return shaderc_spvc_storage_texture_format_r8sint;
188     case spv::ImageFormatR16ui:
189       return shaderc_spvc_storage_texture_format_r16uint;
190     case spv::ImageFormatR16i:
191       return shaderc_spvc_storage_texture_format_r16sint;
192     case spv::ImageFormatR16f:
193       return shaderc_spvc_storage_texture_format_r16float;
194     case spv::ImageFormatRg8:
195       return shaderc_spvc_storage_texture_format_rg8unorm;
196     case spv::ImageFormatRg8Snorm:
197       return shaderc_spvc_storage_texture_format_rg8snorm;
198     case spv::ImageFormatRg8ui:
199       return shaderc_spvc_storage_texture_format_rg8uint;
200     case spv::ImageFormatRg8i:
201       return shaderc_spvc_storage_texture_format_rg8sint;
202     case spv::ImageFormatR32f:
203       return shaderc_spvc_storage_texture_format_r32float;
204     case spv::ImageFormatR32ui:
205       return shaderc_spvc_storage_texture_format_r32uint;
206     case spv::ImageFormatR32i:
207       return shaderc_spvc_storage_texture_format_r32sint;
208     case spv::ImageFormatRg16ui:
209       return shaderc_spvc_storage_texture_format_rg16uint;
210     case spv::ImageFormatRg16i:
211       return shaderc_spvc_storage_texture_format_rg16sint;
212     case spv::ImageFormatRg16f:
213       return shaderc_spvc_storage_texture_format_rg16float;
214     case spv::ImageFormatRgba8:
215       return shaderc_spvc_storage_texture_format_rgba8unorm;
216     case spv::ImageFormatRgba8Snorm:
217       return shaderc_spvc_storage_texture_format_rgba8snorm;
218     case spv::ImageFormatRgba8ui:
219       return shaderc_spvc_storage_texture_format_rgba8uint;
220     case spv::ImageFormatRgba8i:
221       return shaderc_spvc_storage_texture_format_rgba8sint;
222     case spv::ImageFormatRgb10A2:
223       return shaderc_spvc_storage_texture_format_rgb10a2unorm;
224     case spv::ImageFormatR11fG11fB10f:
225       return shaderc_spvc_storage_texture_format_rg11b10float;
226     case spv::ImageFormatRg32f:
227       return shaderc_spvc_storage_texture_format_rg32float;
228     case spv::ImageFormatRg32ui:
229       return shaderc_spvc_storage_texture_format_rg32uint;
230     case spv::ImageFormatRg32i:
231       return shaderc_spvc_storage_texture_format_rg32sint;
232     case spv::ImageFormatRgba16ui:
233       return shaderc_spvc_storage_texture_format_rgba16uint;
234     case spv::ImageFormatRgba16i:
235       return shaderc_spvc_storage_texture_format_rgba16sint;
236     case spv::ImageFormatRgba16f:
237       return shaderc_spvc_storage_texture_format_rgba16float;
238     case spv::ImageFormatRgba32f:
239       return shaderc_spvc_storage_texture_format_rgba32float;
240     case spv::ImageFormatRgba32ui:
241       return shaderc_spvc_storage_texture_format_rgba32uint;
242     case spv::ImageFormatRgba32i:
243       return shaderc_spvc_storage_texture_format_rgba32sint;
244     default:
245       return shaderc_spvc_storage_texture_format_undefined;
246   }
247 }
248 
shaderc_spvc_spv_env_to_spv_target_env(shaderc_spvc_spv_env env)249 spv_target_env shaderc_spvc_spv_env_to_spv_target_env(
250     shaderc_spvc_spv_env env) {
251   switch (env) {
252     case shaderc_spvc_spv_env_universal_1_0:
253       return SPV_ENV_UNIVERSAL_1_0;
254     case shaderc_spvc_spv_env_vulkan_1_0:
255       return SPV_ENV_VULKAN_1_0;
256     case shaderc_spvc_spv_env_universal_1_1:
257       return SPV_ENV_UNIVERSAL_1_1;
258     case shaderc_spvc_spv_env_opencl_2_1:
259       return SPV_ENV_OPENCL_2_1;
260     case shaderc_spvc_spv_env_opencl_2_2:
261       return SPV_ENV_OPENCL_2_2;
262     case shaderc_spvc_spv_env_opengl_4_0:
263       return SPV_ENV_OPENGL_4_0;
264     case shaderc_spvc_spv_env_opengl_4_1:
265       return SPV_ENV_OPENGL_4_1;
266     case shaderc_spvc_spv_env_opengl_4_2:
267       return SPV_ENV_OPENGL_4_2;
268     case shaderc_spvc_spv_env_opengl_4_3:
269       return SPV_ENV_OPENGL_4_3;
270     case shaderc_spvc_spv_env_opengl_4_5:
271       return SPV_ENV_OPENGL_4_5;
272     case shaderc_spvc_spv_env_universal_1_2:
273       return SPV_ENV_UNIVERSAL_1_2;
274     case shaderc_spvc_spv_env_opencl_1_2:
275       return SPV_ENV_OPENCL_1_2;
276     case shaderc_spvc_spv_env_opencl_embedded_1_2:
277       return SPV_ENV_OPENCL_EMBEDDED_1_2;
278     case shaderc_spvc_spv_env_opencl_2_0:
279       return SPV_ENV_OPENCL_2_0;
280     case shaderc_spvc_spv_env_opencl_embedded_2_0:
281       return SPV_ENV_OPENCL_EMBEDDED_2_0;
282     case shaderc_spvc_spv_env_opencl_embedded_2_1:
283       return SPV_ENV_OPENCL_EMBEDDED_2_1;
284     case shaderc_spvc_spv_env_opencl_embedded_2_2:
285       return SPV_ENV_OPENCL_EMBEDDED_2_2;
286     case shaderc_spvc_spv_env_universal_1_3:
287       return SPV_ENV_UNIVERSAL_1_3;
288     case shaderc_spvc_spv_env_vulkan_1_1:
289       return SPV_ENV_VULKAN_1_1;
290     case shaderc_spvc_spv_env_webgpu_0:
291       return SPV_ENV_WEBGPU_0;
292     case shaderc_spvc_spv_env_universal_1_4:
293       return SPV_ENV_UNIVERSAL_1_4;
294     case shaderc_spvc_spv_env_vulkan_1_1_spirv_1_4:
295       return SPV_ENV_VULKAN_1_1_SPIRV_1_4;
296     case shaderc_spvc_spv_env_universal_1_5:
297       return SPV_ENV_UNIVERSAL_1_5;
298     case shaderc_spvc_spv_env_vulkan_1_2:
299       return SPV_ENV_VULKAN_1_2;
300   }
301   shaderc_spvc::ErrorLog(nullptr)
302       << "Attempted to convert unknown shaderc_spvc_spv_env value, " << env;
303   assert(false);
304   return SPV_ENV_UNIVERSAL_1_0;
305 }
306 
get_location_info_impl(spirv_cross::Compiler * compiler,const spirv_cross::SmallVector<spirv_cross::Resource> & resources,shaderc_spvc_resource_location_info * locations,size_t * location_count)307 shaderc_spvc_status get_location_info_impl(
308     spirv_cross::Compiler* compiler,
309     const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
310     shaderc_spvc_resource_location_info* locations, size_t* location_count) {
311   *location_count = resources.size();
312   if (!locations) return shaderc_spvc_status_success;
313 
314   for (const auto& resource : resources) {
315     if (!compiler->get_decoration_bitset(resource.id)
316              .get(spv::DecorationLocation)) {
317       return shaderc_spvc_status_internal_error;
318     }
319     locations->id = resource.id;
320     if (compiler->get_decoration_bitset(resource.id)
321             .get(spv::DecorationLocation)) {
322       locations->location =
323           compiler->get_decoration(resource.id, spv::DecorationLocation);
324       locations->has_location = true;
325     } else {
326       locations->has_location = false;
327     }
328     locations++;
329   }
330   return shaderc_spvc_status_success;
331 }
332 
333 }  // namespace
334 
shaderc_spvc_context_create()335 shaderc_spvc_context_t shaderc_spvc_context_create() {
336   return new (std::nothrow) shaderc_spvc_context;
337 }
338 
shaderc_spvc_context_destroy(shaderc_spvc_context_t context)339 void shaderc_spvc_context_destroy(shaderc_spvc_context_t context) {
340   if (context) delete context;
341 }
342 
shaderc_spvc_context_get_messages(const shaderc_spvc_context_t context)343 const char* shaderc_spvc_context_get_messages(
344     const shaderc_spvc_context_t context) {
345   for (const auto& message : context->messages) {
346     context->messages_string += message;
347   }
348   context->messages.clear();
349   return context->messages_string.c_str();
350 }
351 
shaderc_spvc_context_get_compiler(const shaderc_spvc_context_t context,void ** compiler)352 shaderc_spvc_status shaderc_spvc_context_get_compiler(
353     const shaderc_spvc_context_t context, void** compiler) {
354   CHECK_CONTEXT(context);
355   CHECK_CROSS_COMPILER(context, context->cross_compiler);
356   CHECK_OUT_PARAM(context, compiler, "compiler");
357 
358   *compiler = context->cross_compiler.get();
359   return shaderc_spvc_status_success;
360 }
361 
shaderc_spvc_context_set_use_spvc_parser(shaderc_spvc_context_t context,bool b)362 shaderc_spvc_status shaderc_spvc_context_set_use_spvc_parser(
363     shaderc_spvc_context_t context, bool b) {
364   CHECK_CONTEXT(context);
365 
366   context->use_spvc_parser = b;
367   return shaderc_spvc_status_success;
368 }
369 
shaderc_spvc_compile_options_create(shaderc_spvc_spv_env source_env,shaderc_spvc_spv_env target_env)370 shaderc_spvc_compile_options_t shaderc_spvc_compile_options_create(
371     shaderc_spvc_spv_env source_env, shaderc_spvc_spv_env target_env) {
372   shaderc_spvc_compile_options_t options =
373       new (std::nothrow) shaderc_spvc_compile_options;
374   if (options) {
375     options->glsl.version = 0;
376     options->source_env = shaderc_spvc_spv_env_to_spv_target_env(source_env);
377     options->target_env = shaderc_spvc_spv_env_to_spv_target_env(target_env);
378   }
379   return options;
380 }
381 
shaderc_spvc_compile_options_clone(shaderc_spvc_compile_options_t options)382 shaderc_spvc_compile_options_t shaderc_spvc_compile_options_clone(
383     shaderc_spvc_compile_options_t options) {
384   if (options) return new (std::nothrow) shaderc_spvc_compile_options(*options);
385   return nullptr;
386 }
387 
shaderc_spvc_compile_options_destroy(shaderc_spvc_compile_options_t options)388 void shaderc_spvc_compile_options_destroy(
389     shaderc_spvc_compile_options_t options) {
390   if (options) delete options;
391 }
392 
393 // DEPRECATED
shaderc_spvc_compile_options_set_source_env(shaderc_spvc_compile_options_t options,shaderc_target_env env,shaderc_env_version version)394 shaderc_spvc_status shaderc_spvc_compile_options_set_source_env(
395     shaderc_spvc_compile_options_t options, shaderc_target_env env,
396     shaderc_env_version version) {
397   CHECK_OPTIONS(nullptr, options);
398 
399   options->source_env = spvc_private::get_spv_target_env(env, version);
400   return shaderc_spvc_status_success;
401 }
402 
403 // DEPRECATED
shaderc_spvc_compile_options_set_target_env(shaderc_spvc_compile_options_t options,shaderc_target_env env,shaderc_env_version version)404 shaderc_spvc_status shaderc_spvc_compile_options_set_target_env(
405     shaderc_spvc_compile_options_t options, shaderc_target_env env,
406     shaderc_env_version version) {
407   CHECK_OPTIONS(nullptr, options);
408 
409   options->target_env = spvc_private::get_spv_target_env(env, version);
410   return shaderc_spvc_status_success;
411 }
412 
shaderc_spvc_compile_options_set_entry_point(shaderc_spvc_compile_options_t options,const char * entry_point)413 shaderc_spvc_status shaderc_spvc_compile_options_set_entry_point(
414     shaderc_spvc_compile_options_t options, const char* entry_point) {
415   CHECK_OPTIONS(nullptr, options);
416   CHECK_IN_PARAM(nullptr, entry_point, "entry_point");
417 
418   options->entry_point = entry_point;
419   return shaderc_spvc_status_success;
420 }
421 
shaderc_spvc_compile_options_set_remove_unused_variables(shaderc_spvc_compile_options_t options,bool b)422 shaderc_spvc_status shaderc_spvc_compile_options_set_remove_unused_variables(
423     shaderc_spvc_compile_options_t options, bool b) {
424   CHECK_OPTIONS(nullptr, options);
425 
426   options->remove_unused_variables = b;
427   return shaderc_spvc_status_success;
428 }
429 
shaderc_spvc_compile_options_set_robust_buffer_access_pass(shaderc_spvc_compile_options_t options,bool b)430 shaderc_spvc_status shaderc_spvc_compile_options_set_robust_buffer_access_pass(
431     shaderc_spvc_compile_options_t options, bool b) {
432   CHECK_OPTIONS(nullptr, options);
433 
434   options->robust_buffer_access_pass = b;
435   return shaderc_spvc_status_success;
436 }
437 
shaderc_spvc_compile_options_set_emit_line_directives(shaderc_spvc_compile_options_t options,bool b)438 shaderc_spvc_status shaderc_spvc_compile_options_set_emit_line_directives(
439     shaderc_spvc_compile_options_t options, bool b) {
440   CHECK_OPTIONS(nullptr, options);
441 
442   options->glsl.emit_line_directives = b;
443   return shaderc_spvc_status_success;
444 }
445 
shaderc_spvc_compile_options_set_vulkan_semantics(shaderc_spvc_compile_options_t options,bool b)446 shaderc_spvc_status shaderc_spvc_compile_options_set_vulkan_semantics(
447     shaderc_spvc_compile_options_t options, bool b) {
448   CHECK_OPTIONS(nullptr, options);
449 
450   options->glsl.vulkan_semantics = b;
451   return shaderc_spvc_status_success;
452 }
453 
shaderc_spvc_compile_options_set_separate_shader_objects(shaderc_spvc_compile_options_t options,bool b)454 shaderc_spvc_status shaderc_spvc_compile_options_set_separate_shader_objects(
455     shaderc_spvc_compile_options_t options, bool b) {
456   CHECK_OPTIONS(nullptr, options);
457 
458   options->glsl.separate_shader_objects = b;
459   return shaderc_spvc_status_success;
460 }
461 
shaderc_spvc_compile_options_set_flatten_ubo(shaderc_spvc_compile_options_t options,bool b)462 shaderc_spvc_status shaderc_spvc_compile_options_set_flatten_ubo(
463     shaderc_spvc_compile_options_t options, bool b) {
464   CHECK_OPTIONS(nullptr, options);
465 
466   options->flatten_ubo = b;
467   return shaderc_spvc_status_success;
468 }
469 
shaderc_spvc_compile_options_set_glsl_language_version(shaderc_spvc_compile_options_t options,uint32_t version)470 shaderc_spvc_status shaderc_spvc_compile_options_set_glsl_language_version(
471     shaderc_spvc_compile_options_t options, uint32_t version) {
472   CHECK_OPTIONS(nullptr, options);
473 
474   options->glsl.version = version;
475   return shaderc_spvc_status_success;
476 }
477 
478 shaderc_spvc_status
shaderc_spvc_compile_options_set_flatten_multidimensional_arrays(shaderc_spvc_compile_options_t options,bool b)479 shaderc_spvc_compile_options_set_flatten_multidimensional_arrays(
480     shaderc_spvc_compile_options_t options, bool b) {
481   CHECK_OPTIONS(nullptr, options);
482 
483   options->glsl.flatten_multidimensional_arrays = b;
484   return shaderc_spvc_status_success;
485 }
486 
487 shaderc_spvc_status
shaderc_spvc_compile_options_set_force_zero_initialized_variables(shaderc_spvc_compile_options_t options,bool b)488 shaderc_spvc_compile_options_set_force_zero_initialized_variables(
489     shaderc_spvc_compile_options_t options, bool b) {
490   CHECK_OPTIONS(nullptr, options);
491 
492   options->glsl.force_zero_initialized_variables = b;
493   return shaderc_spvc_status_success;
494 }
495 
shaderc_spvc_compile_options_set_es(shaderc_spvc_compile_options_t options,bool b)496 shaderc_spvc_status shaderc_spvc_compile_options_set_es(
497     shaderc_spvc_compile_options_t options, bool b) {
498   CHECK_OPTIONS(nullptr, options);
499 
500   options->forced_es_setting = b;
501   options->force_es = true;
502   return shaderc_spvc_status_success;
503 }
504 
505 shaderc_spvc_status
shaderc_spvc_compile_options_set_glsl_emit_push_constant_as_ubo(shaderc_spvc_compile_options_t options,bool b)506 shaderc_spvc_compile_options_set_glsl_emit_push_constant_as_ubo(
507     shaderc_spvc_compile_options_t options, bool b) {
508   CHECK_OPTIONS(nullptr, options);
509 
510   options->glsl.emit_push_constant_as_uniform_buffer = b;
511   return shaderc_spvc_status_success;
512 }
513 
shaderc_spvc_compile_options_set_msl_language_version(shaderc_spvc_compile_options_t options,uint32_t version)514 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_language_version(
515     shaderc_spvc_compile_options_t options, uint32_t version) {
516   CHECK_OPTIONS(nullptr, options);
517 
518   options->msl.msl_version = version;
519   return shaderc_spvc_status_success;
520 }
521 
522 shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_swizzle_texture_samples(shaderc_spvc_compile_options_t options,bool b)523 shaderc_spvc_compile_options_set_msl_swizzle_texture_samples(
524     shaderc_spvc_compile_options_t options, bool b) {
525   CHECK_OPTIONS(nullptr, options);
526 
527   options->msl.swizzle_texture_samples = b;
528   return shaderc_spvc_status_success;
529 }
530 
shaderc_spvc_compile_options_set_msl_platform(shaderc_spvc_compile_options_t options,shaderc_spvc_msl_platform platform)531 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_platform(
532     shaderc_spvc_compile_options_t options,
533     shaderc_spvc_msl_platform platform) {
534   CHECK_OPTIONS(nullptr, options);
535 
536   switch (platform) {
537     case shaderc_spvc_msl_platform_ios:
538       options->msl.platform = spirv_cross::CompilerMSL::Options::iOS;
539       break;
540     case shaderc_spvc_msl_platform_macos:
541       options->msl.platform = spirv_cross::CompilerMSL::Options::macOS;
542       break;
543   }
544   return shaderc_spvc_status_success;
545 }
546 
shaderc_spvc_compile_options_set_msl_pad_fragment_output(shaderc_spvc_compile_options_t options,bool b)547 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_pad_fragment_output(
548     shaderc_spvc_compile_options_t options, bool b) {
549   CHECK_OPTIONS(nullptr, options);
550 
551   options->msl.pad_fragment_output_components = b;
552   return shaderc_spvc_status_success;
553 }
554 
shaderc_spvc_compile_options_set_msl_capture(shaderc_spvc_compile_options_t options,bool b)555 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_capture(
556     shaderc_spvc_compile_options_t options, bool b) {
557   CHECK_OPTIONS(nullptr, options);
558 
559   options->msl.capture_output_to_buffer = b;
560   return shaderc_spvc_status_success;
561 }
562 
shaderc_spvc_compile_options_set_msl_domain_lower_left(shaderc_spvc_compile_options_t options,bool b)563 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_domain_lower_left(
564     shaderc_spvc_compile_options_t options, bool b) {
565   CHECK_OPTIONS(nullptr, options);
566 
567   options->msl.tess_domain_origin_lower_left = b;
568   return shaderc_spvc_status_success;
569 }
570 
shaderc_spvc_compile_options_set_msl_argument_buffers(shaderc_spvc_compile_options_t options,bool b)571 shaderc_spvc_status shaderc_spvc_compile_options_set_msl_argument_buffers(
572     shaderc_spvc_compile_options_t options, bool b) {
573   CHECK_OPTIONS(nullptr, options);
574 
575   options->msl.argument_buffers = b;
576   return shaderc_spvc_status_success;
577 }
578 
579 shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_discrete_descriptor_sets(shaderc_spvc_compile_options_t options,const uint32_t * descriptors,size_t num_descriptors)580 shaderc_spvc_compile_options_set_msl_discrete_descriptor_sets(
581     shaderc_spvc_compile_options_t options, const uint32_t* descriptors,
582     size_t num_descriptors) {
583   CHECK_OPTIONS(nullptr, options);
584 
585   options->msl_discrete_descriptor_sets.resize(num_descriptors);
586   std::copy_n(descriptors, num_descriptors,
587               options->msl_discrete_descriptor_sets.begin());
588   return shaderc_spvc_status_success;
589 }
590 
591 shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_enable_point_size_builtin(shaderc_spvc_compile_options_t options,bool b)592 shaderc_spvc_compile_options_set_msl_enable_point_size_builtin(
593     shaderc_spvc_compile_options_t options, bool b) {
594   CHECK_OPTIONS(nullptr, options);
595 
596   options->msl.enable_point_size_builtin = b;
597   return shaderc_spvc_status_success;
598 }
599 
600 shaderc_spvc_status
shaderc_spvc_compile_options_set_msl_buffer_size_buffer_index(shaderc_spvc_compile_options_t options,uint32_t index)601 shaderc_spvc_compile_options_set_msl_buffer_size_buffer_index(
602     shaderc_spvc_compile_options_t options, uint32_t index) {
603   CHECK_OPTIONS(nullptr, options);
604 
605   options->msl.buffer_size_buffer_index = index;
606   return shaderc_spvc_status_success;
607 }
608 
shaderc_spvc_compile_options_set_hlsl_shader_model(shaderc_spvc_compile_options_t options,uint32_t model)609 shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_shader_model(
610     shaderc_spvc_compile_options_t options, uint32_t model) {
611   CHECK_OPTIONS(nullptr, options);
612 
613   options->hlsl.shader_model = model;
614   return shaderc_spvc_status_success;
615 }
616 
shaderc_spvc_compile_options_set_hlsl_point_size_compat(shaderc_spvc_compile_options_t options,bool b)617 shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_point_size_compat(
618     shaderc_spvc_compile_options_t options, bool b) {
619   CHECK_OPTIONS(nullptr, options);
620 
621   options->hlsl.point_size_compat = b;
622   return shaderc_spvc_status_success;
623 }
624 
shaderc_spvc_compile_options_set_hlsl_point_coord_compat(shaderc_spvc_compile_options_t options,bool b)625 shaderc_spvc_status shaderc_spvc_compile_options_set_hlsl_point_coord_compat(
626     shaderc_spvc_compile_options_t options, bool b) {
627   CHECK_OPTIONS(nullptr, options);
628 
629   options->hlsl.point_coord_compat = b;
630   return shaderc_spvc_status_success;
631 }
632 
shaderc_spvc_compile_options_set_fixup_clipspace(shaderc_spvc_compile_options_t options,bool b)633 shaderc_spvc_status shaderc_spvc_compile_options_set_fixup_clipspace(
634     shaderc_spvc_compile_options_t options, bool b) {
635   CHECK_OPTIONS(nullptr, options);
636 
637   options->glsl.vertex.fixup_clipspace = b;
638   return shaderc_spvc_status_success;
639 }
640 
shaderc_spvc_compile_options_set_flip_vert_y(shaderc_spvc_compile_options_t options,bool b)641 shaderc_spvc_status shaderc_spvc_compile_options_set_flip_vert_y(
642     shaderc_spvc_compile_options_t options, bool b) {
643   CHECK_OPTIONS(nullptr, options);
644 
645   options->glsl.vertex.flip_vert_y = b;
646   return shaderc_spvc_status_success;
647 }
648 
shaderc_spvc_compile_options_set_validate(shaderc_spvc_compile_options_t options,bool b)649 shaderc_spvc_status shaderc_spvc_compile_options_set_validate(
650     shaderc_spvc_compile_options_t options, bool b) {
651   CHECK_OPTIONS(nullptr, options);
652 
653   options->validate = b;
654   return shaderc_spvc_status_success;
655 }
656 
shaderc_spvc_compile_options_set_optimize(shaderc_spvc_compile_options_t options,bool b)657 shaderc_spvc_status shaderc_spvc_compile_options_set_optimize(
658     shaderc_spvc_compile_options_t options, bool b) {
659   CHECK_OPTIONS(nullptr, options);
660 
661   options->optimize = b;
662   return shaderc_spvc_status_success;
663 }
664 
shaderc_spvc_compile_options_set_for_fuzzing(shaderc_spvc_compile_options_t options,const uint8_t * data,size_t size)665 size_t shaderc_spvc_compile_options_set_for_fuzzing(
666     shaderc_spvc_compile_options_t options, const uint8_t* data, size_t size) {
667   if (!options || !data || size < sizeof(*options)) return 0;
668 
669   memcpy(static_cast<void*>(options), data, sizeof(*options));
670   return sizeof(*options);
671 }
672 
shaderc_spvc_initialize_impl(const shaderc_spvc_context_t context,const uint32_t * source,size_t source_len,shaderc_spvc_compile_options_t options,shaderc_spvc_status (* generator)(const shaderc_spvc_context_t,const uint32_t *,size_t,shaderc_spvc_compile_options_t))673 shaderc_spvc_status shaderc_spvc_initialize_impl(
674     const shaderc_spvc_context_t context, const uint32_t* source,
675     size_t source_len, shaderc_spvc_compile_options_t options,
676     shaderc_spvc_status (*generator)(const shaderc_spvc_context_t,
677                                      const uint32_t*, size_t,
678                                      shaderc_spvc_compile_options_t)) {
679   shaderc_spvc_status status = spvc_private::validate_and_translate_spirv(
680       context, source, source_len, options, &context->intermediate_shader);
681   if (status != shaderc_spvc_status_success) return status;
682 
683   status = generator(context, context->intermediate_shader.data(),
684                      context->intermediate_shader.size(), options);
685   if (status != shaderc_spvc_status_success) return status;
686 
687   return shaderc_spvc_status_success;
688 }
689 
shaderc_spvc_initialize_for_glsl(const shaderc_spvc_context_t context,const uint32_t * source,size_t source_len,shaderc_spvc_compile_options_t options)690 shaderc_spvc_status shaderc_spvc_initialize_for_glsl(
691     const shaderc_spvc_context_t context, const uint32_t* source,
692     size_t source_len, shaderc_spvc_compile_options_t options) {
693   CHECK_CONTEXT(context);
694   CHECK_OPTIONS(context, options);
695   CHECK_IN_PARAM(context, source, "source");
696 
697   context->target_lang = SPVC_TARGET_LANG_GLSL;
698   return shaderc_spvc_initialize_impl(context, source, source_len, options,
699                                       spvc_private::generate_glsl_compiler);
700 }
701 
shaderc_spvc_initialize_for_hlsl(const shaderc_spvc_context_t context,const uint32_t * source,size_t source_len,shaderc_spvc_compile_options_t options)702 shaderc_spvc_status shaderc_spvc_initialize_for_hlsl(
703     const shaderc_spvc_context_t context, const uint32_t* source,
704     size_t source_len, shaderc_spvc_compile_options_t options) {
705   CHECK_CONTEXT(context);
706   CHECK_OPTIONS(context, options);
707   CHECK_IN_PARAM(context, source, "source");
708 
709   context->target_lang = SPVC_TARGET_LANG_HLSL;
710   return shaderc_spvc_initialize_impl(context, source, source_len, options,
711                                       spvc_private::generate_hlsl_compiler);
712 }
713 
shaderc_spvc_initialize_for_msl(const shaderc_spvc_context_t context,const uint32_t * source,size_t source_len,shaderc_spvc_compile_options_t options)714 shaderc_spvc_status shaderc_spvc_initialize_for_msl(
715     const shaderc_spvc_context_t context, const uint32_t* source,
716     size_t source_len, shaderc_spvc_compile_options_t options) {
717   CHECK_CONTEXT(context);
718   CHECK_OPTIONS(context, options);
719   CHECK_IN_PARAM(context, source, "source");
720 
721   context->target_lang = SPVC_TARGET_LANG_MSL;
722   return shaderc_spvc_initialize_impl(context, source, source_len, options,
723                                       spvc_private::generate_msl_compiler);
724 }
725 
shaderc_spvc_initialize_for_vulkan(const shaderc_spvc_context_t context,const uint32_t * source,size_t source_len,shaderc_spvc_compile_options_t options)726 shaderc_spvc_status shaderc_spvc_initialize_for_vulkan(
727     const shaderc_spvc_context_t context, const uint32_t* source,
728     size_t source_len, shaderc_spvc_compile_options_t options) {
729   CHECK_CONTEXT(context);
730   CHECK_OPTIONS(context, options);
731   CHECK_IN_PARAM(context, source, "source");
732 
733   context->target_lang = SPVC_TARGET_LANG_VULKAN;
734   return shaderc_spvc_initialize_impl(context, source, source_len, options,
735                                       spvc_private::generate_vulkan_compiler);
736 }
737 
shaderc_spvc_compile_shader(const shaderc_spvc_context_t context,shaderc_spvc_compilation_result_t result)738 shaderc_spvc_status shaderc_spvc_compile_shader(
739     const shaderc_spvc_context_t context,
740     shaderc_spvc_compilation_result_t result) {
741   CHECK_CONTEXT(context);
742   CHECK_CROSS_COMPILER(context, context->cross_compiler);
743 
744   if (context->target_lang == SPVC_TARGET_LANG_UNKNOWN) {
745     shaderc_spvc::ErrorLog(context)
746         << "Invoked compile_shader with unknown language";
747     return shaderc_spvc_status_configuration_error;
748   }
749 
750   if (context->target_lang == SPVC_TARGET_LANG_VULKAN) {
751     // No actual cross compilation is needed, since the intermediate shader is
752     // already in Vulkan SPIR->V.
753     result->binary_output = context->intermediate_shader;
754     return shaderc_spvc_status_success;
755   } else {
756     shaderc_spvc_status status =
757         spvc_private::generate_shader(context->cross_compiler.get(), result);
758     if (status != shaderc_spvc_status_success) {
759       shaderc_spvc::ErrorLog(context) << "Compilation failed.  Partial source:";
760       if (context->target_lang == SPVC_TARGET_LANG_GLSL) {
761         spirv_cross::CompilerGLSL* cast_compiler =
762             reinterpret_cast<spirv_cross::CompilerGLSL*>(
763                 context->cross_compiler.get());
764         shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
765       } else if (context->target_lang == SPVC_TARGET_LANG_HLSL) {
766         spirv_cross::CompilerHLSL* cast_compiler =
767             reinterpret_cast<spirv_cross::CompilerHLSL*>(
768                 context->cross_compiler.get());
769         shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
770       } else if (context->target_lang == SPVC_TARGET_LANG_MSL) {
771         spirv_cross::CompilerMSL* cast_compiler =
772             reinterpret_cast<spirv_cross::CompilerMSL*>(
773                 context->cross_compiler.get());
774         shaderc_spvc::ErrorLog(context) << cast_compiler->get_partial_source();
775       } else {
776         shaderc_spvc::ErrorLog(context)
777             << "Unexpected target language in context";
778       }
779       context->cross_compiler.reset();
780     }
781     return status;
782   }
783 }
784 
shaderc_spvc_set_decoration(const shaderc_spvc_context_t context,uint32_t id,shaderc_spvc_decoration decoration,uint32_t argument)785 shaderc_spvc_status shaderc_spvc_set_decoration(
786     const shaderc_spvc_context_t context, uint32_t id,
787     shaderc_spvc_decoration decoration, uint32_t argument) {
788   CHECK_CONTEXT(context);
789   CHECK_CROSS_COMPILER(context, context->cross_compiler);
790 
791   spv::Decoration spirv_cross_decoration;
792   shaderc_spvc_status status =
793       spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
794           decoration, &spirv_cross_decoration);
795   if (status == shaderc_spvc_status_success) {
796     context->cross_compiler->set_decoration(static_cast<spirv_cross::ID>(id),
797                                             spirv_cross_decoration, argument);
798   } else {
799     shaderc_spvc::ErrorLog(context) << "Decoration Conversion failed. "
800                                        "shaderc_spvc_decoration not supported.";
801   }
802   return status;
803 }
804 
shaderc_spvc_get_decoration(const shaderc_spvc_context_t context,uint32_t id,shaderc_spvc_decoration decoration,uint32_t * value)805 shaderc_spvc_status shaderc_spvc_get_decoration(
806     const shaderc_spvc_context_t context, uint32_t id,
807     shaderc_spvc_decoration decoration, uint32_t* value) {
808   CHECK_CONTEXT(context);
809   CHECK_CROSS_COMPILER(context, context->cross_compiler);
810   CHECK_OUT_PARAM(context, value, "value");
811 
812   spv::Decoration spirv_cross_decoration;
813   shaderc_spvc_status status =
814       spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
815           decoration, &spirv_cross_decoration);
816   if (status != shaderc_spvc_status_success) {
817     shaderc_spvc::ErrorLog(context) << "Decoration conversion failed. "
818                                        "shaderc_spvc_decoration not supported.";
819 
820     return status;
821   }
822 
823   *value = context->cross_compiler->get_decoration(
824       static_cast<spirv_cross::ID>(id), spirv_cross_decoration);
825   if (*value == 0) {
826     shaderc_spvc::ErrorLog(context)
827         << "Getting decoration failed. id not found.";
828     return shaderc_spvc_status_compilation_error;
829   }
830 
831   return shaderc_spvc_status_success;
832 }
833 
shaderc_spvc_unset_decoration(const shaderc_spvc_context_t context,uint32_t id,shaderc_spvc_decoration decoration)834 shaderc_spvc_status shaderc_spvc_unset_decoration(
835     const shaderc_spvc_context_t context, uint32_t id,
836     shaderc_spvc_decoration decoration) {
837   CHECK_CONTEXT(context);
838   CHECK_CROSS_COMPILER(context, context->cross_compiler);
839 
840   spv::Decoration spirv_cross_decoration;
841   shaderc_spvc_status status =
842       spvc_private::shaderc_spvc_decoration_to_spirv_cross_decoration(
843           decoration, &spirv_cross_decoration);
844   if (status == shaderc_spvc_status_success) {
845     context->cross_compiler->unset_decoration(static_cast<spirv_cross::ID>(id),
846                                               spirv_cross_decoration);
847   } else {
848     shaderc_spvc::ErrorLog(context) << "Decoration conversion failed. "
849                                        "shaderc_spvc_decoration not supported.";
850   }
851 
852   return status;
853 }
854 
shaderc_spvc_get_combined_image_samplers(const shaderc_spvc_context_t context,shaderc_spvc_combined_image_sampler * samplers,size_t * num_samplers)855 shaderc_spvc_status shaderc_spvc_get_combined_image_samplers(
856     const shaderc_spvc_context_t context,
857     shaderc_spvc_combined_image_sampler* samplers, size_t* num_samplers) {
858   CHECK_CONTEXT(context);
859   CHECK_CROSS_COMPILER(context, context->cross_compiler);
860   CHECK_OUT_PARAM(context, num_samplers, "num_samplers");
861 
862   *num_samplers = context->cross_compiler->get_combined_image_samplers().size();
863   if (!samplers) return shaderc_spvc_status_success;
864 
865   for (const auto& combined :
866        context->cross_compiler->get_combined_image_samplers()) {
867     samplers->combined_id = combined.combined_id;
868     samplers->image_id = combined.image_id;
869     samplers->sampler_id = combined.sampler_id;
870     samplers++;
871   }
872   return shaderc_spvc_status_success;
873 }
874 
shaderc_spvc_set_name(const shaderc_spvc_context_t context,uint32_t id,const char * name)875 shaderc_spvc_status shaderc_spvc_set_name(const shaderc_spvc_context_t context,
876                                           uint32_t id, const char* name) {
877   CHECK_CONTEXT(context);
878   CHECK_CROSS_COMPILER(context, context->cross_compiler);
879   CHECK_IN_PARAM(context, name, "name");
880 
881   context->cross_compiler->set_name(id, name);
882   return shaderc_spvc_status_success;
883 }
884 
shaderc_spvc_add_msl_resource_binding(const shaderc_spvc_context_t context,const shaderc_spvc_msl_resource_binding binding)885 shaderc_spvc_status shaderc_spvc_add_msl_resource_binding(
886     const shaderc_spvc_context_t context,
887     const shaderc_spvc_msl_resource_binding binding) {
888   CHECK_CONTEXT(context);
889   CHECK_CROSS_COMPILER(context, context->cross_compiler);
890   if (context->target_lang != SPVC_TARGET_LANG_MSL) {
891     shaderc_spvc::ErrorLog(context)
892         << "Invoked add_msl_resource_binding when target language was not MSL";
893     return shaderc_spvc_status_configuration_error;
894   }
895 
896   spirv_cross::MSLResourceBinding cross_binding;
897   cross_binding.stage = spvc_model_to_spv_model(binding.stage);
898   cross_binding.binding = binding.binding;
899   cross_binding.desc_set = binding.desc_set;
900   cross_binding.msl_buffer = binding.msl_buffer;
901   cross_binding.msl_texture = binding.msl_texture;
902   cross_binding.msl_sampler = binding.msl_sampler;
903   reinterpret_cast<spirv_cross::CompilerMSL*>(context->cross_compiler.get())
904       ->add_msl_resource_binding(cross_binding);
905 
906   return shaderc_spvc_status_success;
907 }
908 
shaderc_spvc_get_workgroup_size(const shaderc_spvc_context_t context,const char * function_name,shaderc_spvc_execution_model execution_model,shaderc_spvc_workgroup_size * workgroup_size)909 shaderc_spvc_status shaderc_spvc_get_workgroup_size(
910     const shaderc_spvc_context_t context, const char* function_name,
911     shaderc_spvc_execution_model execution_model,
912     shaderc_spvc_workgroup_size* workgroup_size) {
913   CHECK_CONTEXT(context);
914   CHECK_CROSS_COMPILER(context, context->cross_compiler);
915   CHECK_IN_PARAM(context, function_name, "function_name");
916   CHECK_OUT_PARAM(context, workgroup_size, "workgroup_size");
917 
918   const auto& cross_size =
919       context->cross_compiler
920           ->get_entry_point(function_name,
921                             spvc_model_to_spv_model(execution_model))
922           .workgroup_size;
923   workgroup_size->x = cross_size.x;
924   workgroup_size->y = cross_size.y;
925   workgroup_size->z = cross_size.z;
926   workgroup_size->constant = cross_size.constant;
927 
928   return shaderc_spvc_status_success;
929 }
930 
shaderc_spvc_needs_buffer_size_buffer(const shaderc_spvc_context_t context,bool * b)931 shaderc_spvc_status shaderc_spvc_needs_buffer_size_buffer(
932     const shaderc_spvc_context_t context, bool* b) {
933   CHECK_CONTEXT(context);
934   CHECK_CROSS_COMPILER(context, context->cross_compiler);
935   CHECK_OUT_PARAM(context, b, "b");
936   if (context->target_lang != SPVC_TARGET_LANG_MSL) {
937     shaderc_spvc::ErrorLog(context)
938         << "Invoked needs_buffer_size_buffer when target language was not MSL";
939     return shaderc_spvc_status_configuration_error;
940   }
941 
942   *b =
943       reinterpret_cast<spirv_cross::CompilerMSL*>(context->cross_compiler.get())
944           ->needs_buffer_size_buffer();
945   return shaderc_spvc_status_success;
946 }
947 
shaderc_spvc_build_combined_image_samplers(const shaderc_spvc_context_t context)948 shaderc_spvc_status shaderc_spvc_build_combined_image_samplers(
949     const shaderc_spvc_context_t context) {
950   CHECK_CONTEXT(context);
951   CHECK_CROSS_COMPILER(context, context->cross_compiler);
952 
953   context->cross_compiler->build_combined_image_samplers();
954   return shaderc_spvc_status_success;
955 }
956 
shaderc_spvc_get_execution_model(const shaderc_spvc_context_t context,shaderc_spvc_execution_model * execution_model)957 shaderc_spvc_status shaderc_spvc_get_execution_model(
958     const shaderc_spvc_context_t context,
959     shaderc_spvc_execution_model* execution_model) {
960   CHECK_CONTEXT(context);
961   CHECK_CROSS_COMPILER(context, context->cross_compiler);
962   CHECK_OUT_PARAM(context, execution_model, "execution_model");
963 
964   auto spirv_model = context->cross_compiler->get_execution_model();
965   *execution_model = spv_model_to_spvc_model(spirv_model);
966   if (*execution_model == shaderc_spvc_execution_model_invalid) {
967     shaderc_spvc::ErrorLog(context)
968         << "Shader execution model appears to be of an unsupported type";
969     return shaderc_spvc_status_internal_error;
970   }
971 
972   return shaderc_spvc_status_success;
973 }
974 
shaderc_spvc_get_push_constant_buffer_count(const shaderc_spvc_context_t context,size_t * count)975 shaderc_spvc_status shaderc_spvc_get_push_constant_buffer_count(
976     const shaderc_spvc_context_t context, size_t* count) {
977   CHECK_CONTEXT(context);
978   CHECK_CROSS_COMPILER(context, context->cross_compiler);
979   CHECK_OUT_PARAM(context, count, "count");
980 
981   *count = context->cross_compiler->get_shader_resources()
982                .push_constant_buffers.size();
983   return shaderc_spvc_status_success;
984 }
985 
shaderc_spvc_get_binding_info(const shaderc_spvc_context_t context,shaderc_spvc_shader_resource resource,shaderc_spvc_binding_type binding_type,shaderc_spvc_binding_info * bindings,size_t * binding_count)986 shaderc_spvc_status shaderc_spvc_get_binding_info(
987     const shaderc_spvc_context_t context, shaderc_spvc_shader_resource resource,
988     shaderc_spvc_binding_type binding_type, shaderc_spvc_binding_info* bindings,
989     size_t* binding_count) {
990   CHECK_CONTEXT(context);
991   CHECK_CROSS_COMPILER(context, context->cross_compiler);
992   CHECK_OUT_PARAM(context, binding_count, "binding_count");
993 
994   auto* compiler = context->cross_compiler.get();
995   const auto& resources = compiler->get_shader_resources();
996   const auto* shader_resources = get_shader_resources(resources, resource);
997   *binding_count = shader_resources->size();
998   if (!bindings) return shaderc_spvc_status_success;
999 
1000   for (const auto& shader_resource : *shader_resources) {
1001     bindings->texture_dimension = shaderc_spvc_texture_view_dimension_undefined;
1002     bindings->texture_component_type = shaderc_spvc_texture_format_type_float;
1003 
1004     if (!compiler->get_decoration_bitset(shader_resource.id)
1005              .get(spv::DecorationBinding)) {
1006       shaderc_spvc::ErrorLog(context)
1007           << "Unable to get binding decoration for shader resource";
1008       return shaderc_spvc_status_internal_error;
1009     }
1010     uint32_t binding_decoration =
1011         compiler->get_decoration(shader_resource.id, spv::DecorationBinding);
1012     bindings->binding = binding_decoration;
1013 
1014     if (!compiler->get_decoration_bitset(shader_resource.id)
1015              .get(spv::DecorationDescriptorSet)) {
1016       shaderc_spvc::ErrorLog(context)
1017           << "Unable to get descriptor set decoration for shader resource";
1018       return shaderc_spvc_status_internal_error;
1019     }
1020     uint32_t descriptor_set_decoration = compiler->get_decoration(
1021         shader_resource.id, spv::DecorationDescriptorSet);
1022     bindings->set = descriptor_set_decoration;
1023 
1024     bindings->id = shader_resource.id;
1025     bindings->base_type_id = shader_resource.base_type_id;
1026 
1027     switch (binding_type) {
1028       case shaderc_spvc_binding_type_sampled_texture: {
1029         spirv_cross::SPIRType::ImageType imageType =
1030             compiler->get_type(bindings->base_type_id).image;
1031         spirv_cross::SPIRType::BaseType textureComponentType =
1032             compiler->get_type(imageType.type).basetype;
1033         bindings->multisampled = imageType.ms;
1034         bindings->texture_dimension = spirv_dim_to_texture_view_dimension(
1035             imageType.dim, imageType.arrayed);
1036         bindings->texture_component_type =
1037             spirv_cross_base_type_to_texture_format_type(textureComponentType);
1038         bindings->binding_type = binding_type;
1039       } break;
1040       case shaderc_spvc_binding_type_storage_buffer: {
1041         // Differentiate between readonly storage bindings and writable ones
1042         // based on the NonWritable decoration
1043         spirv_cross::Bitset flags =
1044             compiler->get_buffer_block_flags(shader_resource.id);
1045         if (flags.get(spv::DecorationNonWritable)) {
1046           bindings->binding_type =
1047               shaderc_spvc_binding_type_readonly_storage_buffer;
1048         } else {
1049           bindings->binding_type = shaderc_spvc_binding_type_storage_buffer;
1050         }
1051       } break;
1052       case shaderc_spvc_binding_type_storage_texture: {
1053         spirv_cross::Bitset flags = compiler->get_decoration_bitset(shader_resource.id);
1054         if (flags.get(spv::DecorationNonReadable)) {
1055           bindings->binding_type = shaderc_spvc_binding_type_writeonly_storage_texture;
1056         } else if (flags.get(spv::DecorationNonWritable)) {
1057             bindings->binding_type = shaderc_spvc_binding_type_readonly_storage_texture;
1058         } else {
1059             bindings->binding_type = shaderc_spvc_binding_type_storage_texture;
1060         }
1061         spirv_cross::SPIRType::ImageType imageType =
1062             compiler->get_type(bindings->base_type_id).image;
1063         bindings->storage_texture_format =
1064             spv_image_format_to_storage_texture_format(imageType.format);
1065         bindings->texture_dimension = spirv_dim_to_texture_view_dimension(
1066             imageType.dim, imageType.arrayed);
1067         bindings->multisampled = imageType.ms;
1068       } break;
1069       default:
1070         bindings->binding_type = binding_type;
1071     }
1072     bindings++;
1073   }
1074 
1075   return shaderc_spvc_status_success;
1076 }
1077 
shaderc_spvc_get_input_stage_location_info(const shaderc_spvc_context_t context,shaderc_spvc_resource_location_info * locations,size_t * location_count)1078 shaderc_spvc_status shaderc_spvc_get_input_stage_location_info(
1079     const shaderc_spvc_context_t context,
1080     shaderc_spvc_resource_location_info* locations, size_t* location_count) {
1081   CHECK_CONTEXT(context);
1082   CHECK_CROSS_COMPILER(context, context->cross_compiler);
1083   CHECK_OUT_PARAM(context, location_count, "location_count");
1084 
1085   auto* compiler = context->cross_compiler.get();
1086   shaderc_spvc_status status = get_location_info_impl(
1087       compiler, compiler->get_shader_resources().stage_inputs, locations,
1088       location_count);
1089   if (status != shaderc_spvc_status_success) {
1090     shaderc_spvc::ErrorLog(context)
1091         << "Unable to get location decoration for stage input";
1092   }
1093 
1094   return status;
1095 }
1096 
shaderc_spvc_get_output_stage_location_info(const shaderc_spvc_context_t context,shaderc_spvc_resource_location_info * locations,size_t * location_count)1097 shaderc_spvc_status shaderc_spvc_get_output_stage_location_info(
1098     const shaderc_spvc_context_t context,
1099     shaderc_spvc_resource_location_info* locations, size_t* location_count) {
1100   CHECK_CONTEXT(context);
1101   CHECK_CROSS_COMPILER(context, context->cross_compiler);
1102   CHECK_OUT_PARAM(context, location_count, "location_count");
1103 
1104   auto* compiler = context->cross_compiler.get();
1105   shaderc_spvc_status status = get_location_info_impl(
1106       compiler, compiler->get_shader_resources().stage_outputs, locations,
1107       location_count);
1108   if (status != shaderc_spvc_status_success) {
1109     shaderc_spvc::ErrorLog(context)
1110         << "Unable to get location decoration for stage output";
1111   }
1112 
1113   return status;
1114 }
1115 
shaderc_spvc_get_output_stage_type_info(const shaderc_spvc_context_t context,shaderc_spvc_resource_type_info * types,size_t * type_count)1116 shaderc_spvc_status shaderc_spvc_get_output_stage_type_info(
1117     const shaderc_spvc_context_t context,
1118     shaderc_spvc_resource_type_info* types, size_t* type_count) {
1119   CHECK_CONTEXT(context);
1120   CHECK_CROSS_COMPILER(context, context->cross_compiler);
1121   CHECK_OUT_PARAM(context, type_count, "type_count");
1122 
1123   auto* compiler = context->cross_compiler.get();
1124   const auto& resources = compiler->get_shader_resources().stage_outputs;
1125 
1126   *type_count = resources.size();
1127   if (!types) return shaderc_spvc_status_success;
1128 
1129   for (const auto& resource : resources) {
1130     if (!compiler->get_decoration_bitset(resource.id)
1131              .get(spv::DecorationLocation)) {
1132       shaderc_spvc::ErrorLog(context)
1133           << "Unable to get location decoration for stage output";
1134       return shaderc_spvc_status_internal_error;
1135     }
1136 
1137     types->location =
1138         compiler->get_decoration(resource.id, spv::DecorationLocation);
1139     spirv_cross::SPIRType::BaseType base_type =
1140         compiler->get_type(resource.base_type_id).basetype;
1141     types->type = spirv_cross_base_type_to_texture_format_type(base_type);
1142     types++;
1143   }
1144 
1145   return shaderc_spvc_status_success;
1146 }
1147 
shaderc_spvc_result_create()1148 shaderc_spvc_compilation_result_t shaderc_spvc_result_create() {
1149   return new (std::nothrow) shaderc_spvc_compilation_result;
1150 }
1151 
shaderc_spvc_result_destroy(shaderc_spvc_compilation_result_t result)1152 void shaderc_spvc_result_destroy(shaderc_spvc_compilation_result_t result) {
1153   if (result) delete result;
1154 }
1155 
shaderc_spvc_result_get_string_output(const shaderc_spvc_compilation_result_t result,const char ** str)1156 shaderc_spvc_status shaderc_spvc_result_get_string_output(
1157     const shaderc_spvc_compilation_result_t result, const char** str) {
1158   CHECK_RESULT(nullptr, result);
1159   CHECK_OUT_PARAM(nullptr, str, "str");
1160 
1161   *str = result->string_output.c_str();
1162   return shaderc_spvc_status_success;
1163 }
1164 
shaderc_spvc_result_get_binary_output(const shaderc_spvc_compilation_result_t result,const uint32_t ** binary_output)1165 shaderc_spvc_status shaderc_spvc_result_get_binary_output(
1166     const shaderc_spvc_compilation_result_t result,
1167     const uint32_t** binary_output) {
1168   CHECK_RESULT(nullptr, result);
1169   CHECK_OUT_PARAM(nullptr, binary_output, "binary_output");
1170 
1171   *binary_output = result->binary_output.data();
1172   return shaderc_spvc_status_success;
1173 }
1174 
shaderc_spvc_result_get_binary_length(const shaderc_spvc_compilation_result_t result,uint32_t * len)1175 shaderc_spvc_status shaderc_spvc_result_get_binary_length(
1176     const shaderc_spvc_compilation_result_t result, uint32_t* len) {
1177   CHECK_RESULT(nullptr, result);
1178   CHECK_OUT_PARAM(nullptr, len, "len");
1179 
1180   *len = result->binary_output.size();
1181   return shaderc_spvc_status_success;
1182 }
1183