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 #ifndef SHADERC_SPVC_HPP_
16 #define SHADERC_SPVC_HPP_
17 
18 #include <functional>
19 #include <memory>
20 #include <string>
21 #include <vector>
22 
23 #include "spvc.h"
24 
25 namespace shaderc_spvc {
26 
27 // A CompilationResult contains the compiler output, compilation status,
28 // and messages.
29 //
30 // The compiler output is stored as an array of elements and accessed
31 // via random access iterators provided by cbegin() and cend().  The iterators
32 // are contiguous in the sense of "Contiguous Iterators: A Refinement of
33 // Random Access Iterators", Nevin Liber, C++ Library Evolution Working
34 // Group Working Paper N3884.
35 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf
36 //
37 // Methods begin() and end() are also provided to enable range-based for.
38 // They are synonyms to cbegin() and cend(), respectively.
39 class CompilationResult {
40  public:
41   // Upon creation, the CompilationResult takes ownership of the
42   // shaderc_spvc_compilation_result instance. During destruction of the
43   // CompilationResult, the shaderc_spvc_compilation_result will be released.
CompilationResult()44   explicit CompilationResult()
45       : result_(shaderc_spvc_result_create(), shaderc_spvc_result_destroy) {}
~CompilationResult()46   ~CompilationResult() {}
47 
CompilationResult(CompilationResult && other)48   CompilationResult(CompilationResult&& other)
49       : result_(nullptr, shaderc_spvc_result_destroy) {
50     *this = std::move(other);
51   }
52 
operator =(CompilationResult && other)53   CompilationResult& operator=(CompilationResult&& other) {
54     result_.reset(other.result_.release());
55     return *this;
56   }
57 
GetStringOutput(std::string * str) const58   shaderc_spvc_status GetStringOutput(std::string* str) const {
59     if (!str) return shaderc_spvc_status_invalid_out_param;
60     const char* inner_str;
61     shaderc_spvc_status status =
62         shaderc_spvc_result_get_string_output(result_.get(), &inner_str);
63     if (status != shaderc_spvc_status_success) {
64       return status;
65     }
66     *str = std::string(inner_str);
67     return shaderc_spvc_status_success;
68   }
69 
GetBinaryOutput(std::vector<uint32_t> * data) const70   shaderc_spvc_status GetBinaryOutput(std::vector<uint32_t>* data) const {
71     if (!data) return shaderc_spvc_status_invalid_out_param;
72     const uint32_t* binary_output;
73     shaderc_spvc_status status =
74         shaderc_spvc_result_get_binary_output(result_.get(), &binary_output);
75     if (status != shaderc_spvc_status_success) {
76       return status;
77     }
78     uint32_t binary_length;
79     status =
80         shaderc_spvc_result_get_binary_length(result_.get(), &binary_length);
81     if (!binary_output || !binary_length) {
82       *data = std::vector<uint32_t>();
83     } else {
84       *data =
85           std::vector<uint32_t>(binary_output, binary_output + binary_length);
86     }
87     return shaderc_spvc_status_success;
88   }
89 
90  private:
91   friend class Context;
92 
93   CompilationResult(const CompilationResult& other) = delete;
94   CompilationResult& operator=(const CompilationResult& other) = delete;
95 
96   std::unique_ptr<shaderc_spvc_compilation_result,
97                   void (*)(shaderc_spvc_compilation_result_t)>
98       result_;
99 };
100 
101 // Contains any options that can have default values for a compilation.
102 class CompileOptions {
103  public:
CompileOptions(shaderc_spvc_spv_env source_env,shaderc_spvc_spv_env target_env)104   CompileOptions(shaderc_spvc_spv_env source_env,
105                  shaderc_spvc_spv_env target_env)
106       : options_(shaderc_spvc_compile_options_create(source_env, target_env),
107                  shaderc_spvc_compile_options_destroy) {}
108   // DEPRECATED
CompileOptions()109   CompileOptions()
110       : CompileOptions(shaderc_spvc_spv_env_universal_1_0,
111                        shaderc_spvc_spv_env_universal_1_0) {}
CompileOptions(const CompileOptions & other)112   CompileOptions(const CompileOptions& other)
113       : options_(nullptr, shaderc_spvc_compile_options_destroy) {
114     options_.reset(shaderc_spvc_compile_options_clone(other.options_.get()));
115   }
116 
CompileOptions(CompileOptions && other)117   CompileOptions(CompileOptions&& other)
118       : options_(nullptr, shaderc_spvc_compile_options_destroy) {
119     options_.reset(other.options_.release());
120   }
121 
122   // DEPRECATED
123   // Set the environment for the input SPIR-V.  Default is Vulkan 1.0.
SetSourceEnvironment(shaderc_target_env env,shaderc_env_version version)124   shaderc_spvc_status SetSourceEnvironment(shaderc_target_env env,
125                                            shaderc_env_version version) {
126     return shaderc_spvc_compile_options_set_source_env(options_.get(), env,
127                                                        version);
128   }
129 
130   // DEPRECATED
131   // Set the target environment for the SPIR-V to be cross-compiled. If this is
132   // different then the source a transformation will need to be applied.
133   // Currently only Vulkan 1.1 <-> WebGPU transforms are defined. Default is
134   // Vulkan 1.0.
SetTargetEnvironment(shaderc_target_env env,shaderc_env_version version)135   shaderc_spvc_status SetTargetEnvironment(shaderc_target_env env,
136                                            shaderc_env_version version) {
137     return shaderc_spvc_compile_options_set_target_env(options_.get(), env,
138                                                        version);
139   }
140 
141   // Set the entry point.
SetEntryPoint(const std::string & entry_point)142   shaderc_spvc_status SetEntryPoint(const std::string& entry_point) {
143     return shaderc_spvc_compile_options_set_entry_point(options_.get(),
144                                                         entry_point.c_str());
145   }
146 
147   // If true, unused variables will not appear in the output.
SetRemoveUnusedVariables(bool b)148   shaderc_spvc_status SetRemoveUnusedVariables(bool b) {
149     return shaderc_spvc_compile_options_set_remove_unused_variables(
150         options_.get(), b);
151   }
152 
153   // If true, enable robust buffer access pass in the spirv-opt, meaning:
154   // Inject code to clamp indexed accesses to buffers and internal
155   // arrays, providing guarantees satisfying Vulkan's robustBufferAccess rules.
156   // This is useful when an implementation does not support robust-buffer access
157   // as a driver option.
SetRobustBufferAccessPass(bool b)158   shaderc_spvc_status SetRobustBufferAccessPass(bool b) {
159     return shaderc_spvc_compile_options_set_robust_buffer_access_pass(
160         options_.get(), b);
161   }
162 
SetEmitLineDirectives(bool b)163   shaderc_spvc_status SetEmitLineDirectives(bool b) {
164     return shaderc_spvc_compile_options_set_emit_line_directives(options_.get(),
165                                                                  b);
166   }
167   // If true, Vulkan GLSL features are used instead of GL-compatible features.
SetVulkanSemantics(bool b)168   shaderc_spvc_status SetVulkanSemantics(bool b) {
169     return shaderc_spvc_compile_options_set_vulkan_semantics(options_.get(), b);
170   }
171 
172   // If true, gl_PerVertex is explicitly redeclared in vertex, geometry and
173   // tessellation shaders. The members of gl_PerVertex is determined by which
174   // built-ins are declared by the shader.
SetSeparateShaderObjects(bool b)175   shaderc_spvc_status SetSeparateShaderObjects(bool b) {
176     return shaderc_spvc_compile_options_set_separate_shader_objects(
177         options_.get(), b);
178   }
179 
180   // Flatten uniform or push constant variable into (i|u)vec4 array.
SetFlattenUbo(bool b)181   shaderc_spvc_status SetFlattenUbo(bool b) {
182     return shaderc_spvc_compile_options_set_flatten_ubo(options_.get(), b);
183   }
184 
185   // Which GLSL version should be produced.  Default is 450 (i.e. 4.5).
SetGLSLLanguageVersion(uint32_t version)186   shaderc_spvc_status SetGLSLLanguageVersion(uint32_t version) {
187     return shaderc_spvc_compile_options_set_glsl_language_version(
188         options_.get(), version);
189   }
190 
191   // If true, flatten multidimensional arrays, e.g. foo[a][b][c] -> foo[a*b*c].
192   // Default is false.
SetFlattenMultidimensionalArrays(bool b)193   shaderc_spvc_status SetFlattenMultidimensionalArrays(bool b) {
194     return shaderc_spvc_compile_options_set_flatten_multidimensional_arrays(
195         options_.get(), b);
196   }
197 
198   // If true, initialize new variables from cross-compile to 0 if possible.
199   // Default is false.
SetForceZeroInitializedVariables(bool b)200   shaderc_spvc_status SetForceZeroInitializedVariables(bool b) {
201     return shaderc_spvc_compile_options_set_force_zero_initialized_variables(
202         options_.get(), b);
203   }
204 
205   // Force interpretion as ES, or not.  Default is to detect from source.
SetES(bool b)206   shaderc_spvc_status SetES(bool b) {
207     return shaderc_spvc_compile_options_set_es(options_.get(), b);
208   }
209 
210   // If true, emit push constants as uniform buffer objects.  Default is false.
SetGLSLEmitPushConstantAsUBO(bool b)211   shaderc_spvc_status SetGLSLEmitPushConstantAsUBO(bool b) {
212     return shaderc_spvc_compile_options_set_glsl_emit_push_constant_as_ubo(
213         options_.get(), b);
214   }
215 
216   // Which MSL version should be produced.  Default is 10200 (i.e. 1.2).
SetMSLLanguageVersion(uint32_t version)217   shaderc_spvc_status SetMSLLanguageVersion(uint32_t version) {
218     return shaderc_spvc_compile_options_set_msl_language_version(options_.get(),
219                                                                  version);
220   }
221 
222   // If true, swizzle MSL texture samples.  Default is false.
SetMSLSwizzleTextureSamples(bool b)223   shaderc_spvc_status SetMSLSwizzleTextureSamples(bool b) {
224     return shaderc_spvc_compile_options_set_msl_swizzle_texture_samples(
225         options_.get(), b);
226   }
227 
228   // Choose MSL platform.  Default is MacOS.
SetMSLPlatform(shaderc_spvc_msl_platform platform)229   shaderc_spvc_status SetMSLPlatform(shaderc_spvc_msl_platform platform) {
230     return shaderc_spvc_compile_options_set_msl_platform(options_.get(),
231                                                          platform);
232   }
233 
234   // If true, pad MSL fragment output.  Default is false.
SetMSLPadFragmentOutput(bool b)235   shaderc_spvc_status SetMSLPadFragmentOutput(bool b) {
236     return shaderc_spvc_compile_options_set_msl_pad_fragment_output(
237         options_.get(), b);
238   }
239 
240   // If true, capture MSL output to buffer.  Default is false.
SetMSLCapture(bool b)241   shaderc_spvc_status SetMSLCapture(bool b) {
242     return shaderc_spvc_compile_options_set_msl_capture(options_.get(), b);
243   }
244 
245   // If true, flip the Y-coord of the built-in "TessCoord."  Default is top
246   // left.
SetMSLDomainLowerLeft(bool b)247   shaderc_spvc_status SetMSLDomainLowerLeft(bool b) {
248     return shaderc_spvc_compile_options_set_msl_domain_lower_left(
249         options_.get(), b);
250   }
251 
252   // Enable use of MSL 2.0 indirect argument buffers.  Default is not to use
253   // them.
SetMSLArgumentBuffers(bool b)254   shaderc_spvc_status SetMSLArgumentBuffers(bool b) {
255     return shaderc_spvc_compile_options_set_msl_argument_buffers(options_.get(),
256                                                                  b);
257   }
258 
259   // When using MSL argument buffers, force "classic" MSL 1.0 binding for the
260   // given descriptor sets. This corresponds to VK_KHR_push_descriptor in
261   // Vulkan.
SetMSLDiscreteDescriptorSets(const std::vector<uint32_t> descriptors)262   shaderc_spvc_status SetMSLDiscreteDescriptorSets(
263       const std::vector<uint32_t> descriptors) {
264     return shaderc_spvc_compile_options_set_msl_discrete_descriptor_sets(
265         options_.get(), descriptors.data(), descriptors.size());
266   }
267 
268   // Set whether or not PointSize builtin is used for MSL shaders
SetMSLEnablePointSizeBuiltIn(bool b)269   shaderc_spvc_status SetMSLEnablePointSizeBuiltIn(bool b) {
270     return shaderc_spvc_compile_options_set_msl_enable_point_size_builtin(
271         options_.get(), b);
272   }
273 
274   // Set the index in the buffer size in the buffer for MSL
SetMSLBufferSizeBufferIndex(uint32_t index)275   shaderc_spvc_status SetMSLBufferSizeBufferIndex(uint32_t index) {
276     return shaderc_spvc_compile_options_set_msl_buffer_size_buffer_index(
277         options_.get(), index);
278   }
279 
280   // Which HLSL shader model should be used.  Default is 30.
SetHLSLShaderModel(uint32_t model)281   shaderc_spvc_status SetHLSLShaderModel(uint32_t model) {
282     return shaderc_spvc_compile_options_set_hlsl_shader_model(options_.get(),
283                                                               model);
284   }
285 
286   // If true, ignore PointSize.  Default is false.
SetHLSLPointSizeCompat(bool b)287   shaderc_spvc_status SetHLSLPointSizeCompat(bool b) {
288     return shaderc_spvc_compile_options_set_hlsl_point_size_compat(
289         options_.get(), b);
290   }
291 
292   // If true, ignore PointCoord.  Default is false.
SetHLSLPointCoordCompat(bool b)293   shaderc_spvc_status SetHLSLPointCoordCompat(bool b) {
294     return shaderc_spvc_compile_options_set_hlsl_point_coord_compat(
295         options_.get(), b);
296   }
297 
298   // If true (default is false):
299   //   GLSL: map depth from Vulkan/D3D style to GL style, i.e. [ 0,w] -> [-w,w]
300   //   MSL : map depth from GL style to Vulkan/D3D style, i.e. [-w,w] -> [ 0,w]
301   //   HLSL: map depth from GL style to Vulkan/D3D style, i.e. [-w,w] -> [ 0,w]
SetFixupClipspace(bool b)302   shaderc_spvc_status SetFixupClipspace(bool b) {
303     return shaderc_spvc_compile_options_set_fixup_clipspace(options_.get(), b);
304   }
305 
306   // If true invert gl_Position.y or equivalent.  Default is false.
SetFlipVertY(bool b)307   shaderc_spvc_status SetFlipVertY(bool b) {
308     return shaderc_spvc_compile_options_set_flip_vert_y(options_.get(), b);
309   }
310 
311   // If true validate input and intermediate source. Default is true.
SetValidate(bool b)312   shaderc_spvc_status SetValidate(bool b) {
313     return shaderc_spvc_compile_options_set_validate(options_.get(), b);
314   }
315 
316   // If true optimize input and intermediate source. Default is true.
SetOptimize(bool b)317   shaderc_spvc_status SetOptimize(bool b) {
318     return shaderc_spvc_compile_options_set_optimize(options_.get(), b);
319   }
320 
321   // Fill options with given data.  Return amount of data used, or zero
322   // if not enough data was given.
SetForFuzzing(const uint8_t * data,size_t size)323   size_t SetForFuzzing(const uint8_t* data, size_t size) {
324     return shaderc_spvc_compile_options_set_for_fuzzing(options_.get(), data,
325                                                         size);
326   }
327 
328  private:
329   CompileOptions& operator=(const CompileOptions& other) = delete;
330   std::unique_ptr<shaderc_spvc_compile_options,
331                   void (*)(shaderc_spvc_compile_options_t)>
332       options_;
333 
334   friend class Context;
335 };
336 
337 // The compilation context for compiling SPIR-V.
338 class Context {
339  public:
Context()340   Context()
341       : context_(shaderc_spvc_context_create(), shaderc_spvc_context_destroy) {}
342 
Context(Context && other)343   Context(Context&& other) : context_(nullptr, shaderc_spvc_context_destroy) {
344     context_.reset(other.context_.release());
345   }
346 
IsValid() const347   bool IsValid() const { return context_ != nullptr; }
348 
349   // Returns logged messages from operations
GetMessages() const350   const std::string GetMessages() const {
351     return shaderc_spvc_context_get_messages(context_.get());
352   }
353 
354   // EXPERIMENTAL
355   // Returns the internal spirv_cross compiler reference, does NOT transfer
356   // ownership.
357   // This is being exposed temporarily to ease integration of spvc into Dawn,
358   // but this is will be removed in the future without warning.
GetCompiler(void ** compiler)359   shaderc_spvc_status GetCompiler(void** compiler) {
360     return shaderc_spvc_context_get_compiler(context_.get(), compiler);
361   }
362 
SetUseSpvcParser(bool b)363   shaderc_spvc_status SetUseSpvcParser(bool b) {
364     return shaderc_spvc_context_set_use_spvc_parser(context_.get(), b);
365   }
366 
367   // Initializes state for compiling SPIR-V to GLSL.
InitializeForGlsl(const uint32_t * source,size_t source_len,const CompileOptions & options) const368   shaderc_spvc_status InitializeForGlsl(const uint32_t* source,
369                                         size_t source_len,
370                                         const CompileOptions& options) const {
371     return shaderc_spvc_initialize_for_glsl(context_.get(), source, source_len,
372                                             options.options_.get());
373   }
374 
375   // Initializes state for compiling SPIR-V to HLSL.
InitializeForHlsl(const uint32_t * source,size_t source_len,const CompileOptions & options) const376   shaderc_spvc_status InitializeForHlsl(const uint32_t* source,
377                                         size_t source_len,
378                                         const CompileOptions& options) const {
379     return shaderc_spvc_initialize_for_hlsl(context_.get(), source, source_len,
380                                             options.options_.get());
381   }
382 
383   // Initializes state for compiling SPIR-V to MSL.
InitializeForMsl(const uint32_t * source,size_t source_len,const CompileOptions & options) const384   shaderc_spvc_status InitializeForMsl(const uint32_t* source,
385                                        size_t source_len,
386                                        const CompileOptions& options) const {
387     return shaderc_spvc_initialize_for_msl(context_.get(), source, source_len,
388                                            options.options_.get());
389   }
390 
391   // Initializes state for compiling SPIR-V to Vulkan.
InitializeForVulkan(const uint32_t * source,size_t source_len,const CompileOptions & options) const392   shaderc_spvc_status InitializeForVulkan(const uint32_t* source,
393                                           size_t source_len,
394                                           const CompileOptions& options) const {
395     return shaderc_spvc_initialize_for_vulkan(
396         context_.get(), source, source_len, options.options_.get());
397   }
398 
399   // After initialization compile the shader to desired language.
CompileShader(CompilationResult * result)400   shaderc_spvc_status CompileShader(CompilationResult* result) {
401     return shaderc_spvc_compile_shader(context_.get(), result->result_.get());
402   }
403 
404   // Set spirv_cross decoration (added for HLSL support in Dawn)
405   // Given an id, decoration and argument, the decoration flag on the id is set,
406   // assuming id is valid.
SetDecoration(uint32_t id,shaderc_spvc_decoration decoration,uint32_t argument)407   shaderc_spvc_status SetDecoration(uint32_t id,
408                                     shaderc_spvc_decoration decoration,
409                                     uint32_t argument) {
410     return shaderc_spvc_set_decoration(context_.get(), id, decoration, argument);
411   }
412 
413   // Get spirv_cross decoration (added for GLSL API support in Dawn).
414   // Given an id and a decoration, result is sent out through |argument|
415   // if |id| does not exist, returns an error.
GetDecoration(uint32_t id,shaderc_spvc_decoration decoration,uint32_t * argument)416   shaderc_spvc_status GetDecoration(uint32_t id,
417                                     shaderc_spvc_decoration decoration,
418                                     uint32_t* argument) {
419     return shaderc_spvc_get_decoration(context_.get(), id, decoration, argument);
420   }
421 
422   // Unset spirv_cross decoration (added for GLSL API support in Dawn).
423   // Given an id and a decoration. Assuming id is valid.
UnsetDecoration(uint32_t id,shaderc_spvc_decoration decoration)424   shaderc_spvc_status UnsetDecoration(uint32_t id,
425                                       shaderc_spvc_decoration decoration) {
426     return shaderc_spvc_unset_decoration(context_.get(), id, decoration);
427   }
428 
429   // spirv-cross comment:
430   // Analyzes all separate image and samplers used from the currently selected
431   // entry point, and re-routes them all to a combined image sampler instead.
432   // (added for GLSL API support in Dawn)
BuildCombinedImageSamplers(void)433   shaderc_spvc_status BuildCombinedImageSamplers(void) {
434     return shaderc_spvc_build_combined_image_samplers(context_.get());
435   }
436 
437   // After call to BuildCombinedImageSamplers, fetch the ids associated with the
438   // combined image samplers.
GetCombinedImageSamplers(std::vector<shaderc_spvc_combined_image_sampler> * samplers)439   shaderc_spvc_status GetCombinedImageSamplers(
440       std::vector<shaderc_spvc_combined_image_sampler>* samplers) {
441     size_t count;
442     shaderc_spvc_status status = shaderc_spvc_get_combined_image_samplers(
443         context_.get(), nullptr, &count);
444     if (status != shaderc_spvc_status_success) return status;
445     samplers->resize(count);
446     return shaderc_spvc_get_combined_image_samplers(context_.get(),
447                                                     samplers->data(), &count);
448   }
449 
450   // set |name| on a given |id| (added for GLSL support in Dawn).
451   // Assuming id is valid.
SetName(uint32_t id,const std::string & name)452   shaderc_spvc_status SetName(uint32_t id, const std::string& name) {
453     return shaderc_spvc_set_name(context_.get(), id, name.c_str());
454   }
455 
456   // Adds a binding to indicate the MSL buffer, texture or sampler index to use
457   // for a particular SPIR-V description set and binding.
AddMSLResourceBinding(const shaderc_spvc_msl_resource_binding binding)458   shaderc_spvc_status AddMSLResourceBinding(
459       const shaderc_spvc_msl_resource_binding binding) {
460     return shaderc_spvc_add_msl_resource_binding(context_.get(), binding);
461   }
462 
463   // Gets workgroup size for an entry point defined by a given execution model
464   // and function name.
GetWorkgroupSize(const std::string & function_name,shaderc_spvc_execution_model execution_model,shaderc_spvc_workgroup_size * workgroup_size)465   shaderc_spvc_status GetWorkgroupSize(
466       const std::string& function_name,
467       shaderc_spvc_execution_model execution_model,
468       shaderc_spvc_workgroup_size* workgroup_size) {
469     return shaderc_spvc_get_workgroup_size(
470         context_.get(), function_name.c_str(), execution_model, workgroup_size);
471   }
472 
473   // Gets whether or not the shader needes a buffer of buffer sizes.
NeedsBufferSizeBuffer(bool * b)474   shaderc_spvc_status NeedsBufferSizeBuffer(bool* b) {
475     return shaderc_spvc_needs_buffer_size_buffer(context_.get(), b);
476   }
477 
478   // Gets the execution model for the shader.
GetExecutionModel(shaderc_spvc_execution_model * model)479   shaderc_spvc_status GetExecutionModel(shaderc_spvc_execution_model* model) {
480     return shaderc_spvc_get_execution_model(context_.get(), model);
481   }
482 
483   // Gets the number of push constant buffers used by the shader.
GetPushConstantBufferCount(size_t * count)484   shaderc_spvc_status GetPushConstantBufferCount(size_t* count) {
485     return shaderc_spvc_get_push_constant_buffer_count(context_.get(), count);
486   }
487 
488   // Gets all of the binding info for a given shader resource.
GetBindingInfo(shaderc_spvc_shader_resource resource,shaderc_spvc_binding_type binding_type,std::vector<shaderc_spvc_binding_info> * bindings)489   shaderc_spvc_status GetBindingInfo(
490       shaderc_spvc_shader_resource resource,
491       shaderc_spvc_binding_type binding_type,
492       std::vector<shaderc_spvc_binding_info>* bindings) {
493     if (!bindings) {
494       return shaderc_spvc_status_invalid_out_param;
495     }
496 
497     size_t binding_count;
498     shaderc_spvc_status status = shaderc_spvc_get_binding_info(
499         context_.get(), resource, binding_type, nullptr, &binding_count);
500     if (status != shaderc_spvc_status_success) {
501       return status;
502     }
503 
504     bindings->resize(binding_count);
505     return shaderc_spvc_get_binding_info(context_.get(), resource, binding_type,
506                                          bindings->data(), &binding_count);
507   }
508 
509   // Gets the Location decoration information for the stage inputs.
GetInputStageLocationInfo(std::vector<shaderc_spvc_resource_location_info> * locations)510   shaderc_spvc_status GetInputStageLocationInfo(
511       std::vector<shaderc_spvc_resource_location_info>* locations) {
512     if (!locations) {
513       return shaderc_spvc_status_invalid_out_param;
514     }
515 
516     size_t location_count;
517     shaderc_spvc_status status = shaderc_spvc_get_input_stage_location_info(
518         context_.get(), nullptr, &location_count);
519     if (status != shaderc_spvc_status_success) {
520       return status;
521     }
522 
523     locations->resize(location_count);
524     return shaderc_spvc_get_input_stage_location_info(
525         context_.get(), locations->data(), &location_count);
526   }
527 
528   // Gets the Location decoration information for the stage output.
GetOutputStageLocationInfo(std::vector<shaderc_spvc_resource_location_info> * locations)529   shaderc_spvc_status GetOutputStageLocationInfo(
530       std::vector<shaderc_spvc_resource_location_info>* locations) {
531     if (!locations) {
532       return shaderc_spvc_status_invalid_out_param;
533     }
534 
535     size_t location_count;
536     shaderc_spvc_status status = shaderc_spvc_get_output_stage_location_info(
537         context_.get(), nullptr, &location_count);
538     if (status != shaderc_spvc_status_success) {
539       return status;
540     }
541 
542     locations->resize(location_count);
543     return shaderc_spvc_get_output_stage_location_info(
544         context_.get(), locations->data(), &location_count);
545   }
546 
547   // Gets the type information for the stage output.
GetOutputStageTypeInfo(std::vector<shaderc_spvc_resource_type_info> * types)548   shaderc_spvc_status GetOutputStageTypeInfo(
549       std::vector<shaderc_spvc_resource_type_info>* types) {
550     if (!types) {
551       return shaderc_spvc_status_invalid_out_param;
552     }
553 
554     size_t type_count;
555     shaderc_spvc_status status = shaderc_spvc_get_output_stage_type_info(
556         context_.get(), nullptr, &type_count);
557     if (status != shaderc_spvc_status_success) {
558       return status;
559     }
560 
561     types->resize(type_count);
562     return shaderc_spvc_get_output_stage_type_info(context_.get(),
563                                                    types->data(), &type_count);
564   }
565 
566  private:
567   Context(const Context&) = delete;
568   Context& operator=(const Context& other) = delete;
569 
570   std::unique_ptr<shaderc_spvc_context, void (*)(shaderc_spvc_context_t)>
571       context_;
572 };
573 
574 }  // namespace shaderc_spvc
575 
576 #endif  // SHADERC_SPVC_HPP_
577