aboutsummaryrefslogtreecommitdiff
path: root/libshaderc_spvc/include/spvc/spvc.hpp
blob: 1c2e7d46c2604706fb7998e28aaf61398f188ae9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
// Copyright 2018 The Shaderc Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef SHADERC_SPVC_HPP_
#define SHADERC_SPVC_HPP_

#include <functional>
#include <memory>
#include <string>
#include <vector>

#include "spvc.h"

namespace shaderc_spvc {

// A CompilationResult contains the compiler output, compilation status,
// and messages.
//
// The compiler output is stored as an array of elements and accessed
// via random access iterators provided by cbegin() and cend().  The iterators
// are contiguous in the sense of "Contiguous Iterators: A Refinement of
// Random Access Iterators", Nevin Liber, C++ Library Evolution Working
// Group Working Paper N3884.
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3884.pdf
//
// Methods begin() and end() are also provided to enable range-based for.
// They are synonyms to cbegin() and cend(), respectively.
class CompilationResult {
 public:
  // Upon creation, the CompilationResult takes ownership of the
  // shaderc_spvc_compilation_result instance. During destruction of the
  // CompilationResult, the shaderc_spvc_compilation_result will be released.
  explicit CompilationResult()
      : result_(shaderc_spvc_result_create(), shaderc_spvc_result_destroy) {}
  ~CompilationResult() {}

  CompilationResult(CompilationResult&& other)
      : result_(nullptr, shaderc_spvc_result_destroy) {
    *this = std::move(other);
  }

  CompilationResult& operator=(CompilationResult&& other) {
    result_.reset(other.result_.release());
    return *this;
  }

  shaderc_spvc_status GetStringOutput(std::string* str) const {
    if (!str) return shaderc_spvc_status_invalid_out_param;
    const char* inner_str;
    shaderc_spvc_status status =
        shaderc_spvc_result_get_string_output(result_.get(), &inner_str);
    if (status != shaderc_spvc_status_success) {
      return status;
    }
    *str = std::string(inner_str);
    return shaderc_spvc_status_success;
  }

  shaderc_spvc_status GetBinaryOutput(std::vector<uint32_t>* data) const {
    if (!data) return shaderc_spvc_status_invalid_out_param;
    const uint32_t* binary_output;
    shaderc_spvc_status status =
        shaderc_spvc_result_get_binary_output(result_.get(), &binary_output);
    if (status != shaderc_spvc_status_success) {
      return status;
    }
    uint32_t binary_length;
    status =
        shaderc_spvc_result_get_binary_length(result_.get(), &binary_length);
    if (!binary_output || !binary_length) {
      *data = std::vector<uint32_t>();
    } else {
      *data =
          std::vector<uint32_t>(binary_output, binary_output + binary_length);
    }
    return shaderc_spvc_status_success;
  }

 private:
  friend class Context;

  CompilationResult(const CompilationResult& other) = delete;
  CompilationResult& operator=(const CompilationResult& other) = delete;

  std::unique_ptr<shaderc_spvc_compilation_result,
                  void (*)(shaderc_spvc_compilation_result_t)>
      result_;
};

// Contains any options that can have default values for a compilation.
class CompileOptions {
 public:
  CompileOptions(shaderc_spvc_spv_env source_env,
                 shaderc_spvc_spv_env target_env)
      : options_(shaderc_spvc_compile_options_create(source_env, target_env),
                 shaderc_spvc_compile_options_destroy) {}
  // DEPRECATED
  CompileOptions()
      : CompileOptions(shaderc_spvc_spv_env_universal_1_0,
                       shaderc_spvc_spv_env_universal_1_0) {}
  CompileOptions(const CompileOptions& other)
      : options_(nullptr, shaderc_spvc_compile_options_destroy) {
    options_.reset(shaderc_spvc_compile_options_clone(other.options_.get()));
  }

  CompileOptions(CompileOptions&& other)
      : options_(nullptr, shaderc_spvc_compile_options_destroy) {
    options_.reset(other.options_.release());
  }

  // DEPRECATED
  // Set the environment for the input SPIR-V.  Default is Vulkan 1.0.
  shaderc_spvc_status SetSourceEnvironment(shaderc_target_env env,
                                           shaderc_env_version version) {
    return shaderc_spvc_compile_options_set_source_env(options_.get(), env,
                                                       version);
  }

  // DEPRECATED
  // Set the target environment for the SPIR-V to be cross-compiled. If this is
  // different then the source a transformation will need to be applied.
  // Currently only Vulkan 1.1 <-> WebGPU transforms are defined. Default is
  // Vulkan 1.0.
  shaderc_spvc_status SetTargetEnvironment(shaderc_target_env env,
                                           shaderc_env_version version) {
    return shaderc_spvc_compile_options_set_target_env(options_.get(), env,
                                                       version);
  }

  // Set the entry point.
  shaderc_spvc_status SetEntryPoint(const std::string& entry_point) {
    return shaderc_spvc_compile_options_set_entry_point(options_.get(),
                                                        entry_point.c_str());
  }

  // If true, unused variables will not appear in the output.
  shaderc_spvc_status SetRemoveUnusedVariables(bool b) {
    return shaderc_spvc_compile_options_set_remove_unused_variables(
        options_.get(), b);
  }

  // If true, enable robust buffer access pass in the spirv-opt, meaning:
  // Inject code to clamp indexed accesses to buffers and internal
  // arrays, providing guarantees satisfying Vulkan's robustBufferAccess rules.
  // This is useful when an implementation does not support robust-buffer access
  // as a driver option.
  shaderc_spvc_status SetRobustBufferAccessPass(bool b) {
    return shaderc_spvc_compile_options_set_robust_buffer_access_pass(
        options_.get(), b);
  }

  shaderc_spvc_status SetEmitLineDirectives(bool b) {
    return shaderc_spvc_compile_options_set_emit_line_directives(options_.get(),
                                                                 b);
  }
  // If true, Vulkan GLSL features are used instead of GL-compatible features.
  shaderc_spvc_status SetVulkanSemantics(bool b) {
    return shaderc_spvc_compile_options_set_vulkan_semantics(options_.get(), b);
  }

  // If true, gl_PerVertex is explicitly redeclared in vertex, geometry and
  // tessellation shaders. The members of gl_PerVertex is determined by which
  // built-ins are declared by the shader.
  shaderc_spvc_status SetSeparateShaderObjects(bool b) {
    return shaderc_spvc_compile_options_set_separate_shader_objects(
        options_.get(), b);
  }

  // Flatten uniform or push constant variable into (i|u)vec4 array.
  shaderc_spvc_status SetFlattenUbo(bool b) {
    return shaderc_spvc_compile_options_set_flatten_ubo(options_.get(), b);
  }

  // Which GLSL version should be produced.  Default is 450 (i.e. 4.5).
  shaderc_spvc_status SetGLSLLanguageVersion(uint32_t version) {
    return shaderc_spvc_compile_options_set_glsl_language_version(
        options_.get(), version);
  }

  // If true, flatten multidimensional arrays, e.g. foo[a][b][c] -> foo[a*b*c].
  // Default is false.
  shaderc_spvc_status SetFlattenMultidimensionalArrays(bool b) {
    return shaderc_spvc_compile_options_set_flatten_multidimensional_arrays(
        options_.get(), b);
  }

  // If true, initialize new variables from cross-compile to 0 if possible.
  // Default is false.
  shaderc_spvc_status SetForceZeroInitializedVariables(bool b) {
    return shaderc_spvc_compile_options_set_force_zero_initialized_variables(
        options_.get(), b);
  }

  // Force interpretion as ES, or not.  Default is to detect from source.
  shaderc_spvc_status SetES(bool b) {
    return shaderc_spvc_compile_options_set_es(options_.get(), b);
  }

  // If true, emit push constants as uniform buffer objects.  Default is false.
  shaderc_spvc_status SetGLSLEmitPushConstantAsUBO(bool b) {
    return shaderc_spvc_compile_options_set_glsl_emit_push_constant_as_ubo(
        options_.get(), b);
  }

  // Which MSL version should be produced.  Default is 10200 (i.e. 1.2).
  shaderc_spvc_status SetMSLLanguageVersion(uint32_t version) {
    return shaderc_spvc_compile_options_set_msl_language_version(options_.get(),
                                                                 version);
  }

  // If true, swizzle MSL texture samples.  Default is false.
  shaderc_spvc_status SetMSLSwizzleTextureSamples(bool b) {
    return shaderc_spvc_compile_options_set_msl_swizzle_texture_samples(
        options_.get(), b);
  }

  // Choose MSL platform.  Default is MacOS.
  shaderc_spvc_status SetMSLPlatform(shaderc_spvc_msl_platform platform) {
    return shaderc_spvc_compile_options_set_msl_platform(options_.get(),
                                                         platform);
  }

  // If true, pad MSL fragment output.  Default is false.
  shaderc_spvc_status SetMSLPadFragmentOutput(bool b) {
    return shaderc_spvc_compile_options_set_msl_pad_fragment_output(
        options_.get(), b);
  }

  // If true, capture MSL output to buffer.  Default is false.
  shaderc_spvc_status SetMSLCapture(bool b) {
    return shaderc_spvc_compile_options_set_msl_capture(options_.get(), b);
  }

  // If true, flip the Y-coord of the built-in "TessCoord."  Default is top
  // left.
  shaderc_spvc_status SetMSLDomainLowerLeft(bool b) {
    return shaderc_spvc_compile_options_set_msl_domain_lower_left(
        options_.get(), b);
  }

  // Enable use of MSL 2.0 indirect argument buffers.  Default is not to use
  // them.
  shaderc_spvc_status SetMSLArgumentBuffers(bool b) {
    return shaderc_spvc_compile_options_set_msl_argument_buffers(options_.get(),
                                                                 b);
  }

  // When using MSL argument buffers, force "classic" MSL 1.0 binding for the
  // given descriptor sets. This corresponds to VK_KHR_push_descriptor in
  // Vulkan.
  shaderc_spvc_status SetMSLDiscreteDescriptorSets(
      const std::vector<uint32_t> descriptors) {
    return shaderc_spvc_compile_options_set_msl_discrete_descriptor_sets(
        options_.get(), descriptors.data(), descriptors.size());
  }

  // Set whether or not PointSize builtin is used for MSL shaders
  shaderc_spvc_status SetMSLEnablePointSizeBuiltIn(bool b) {
    return shaderc_spvc_compile_options_set_msl_enable_point_size_builtin(
        options_.get(), b);
  }

  // Set the index in the buffer size in the buffer for MSL
  shaderc_spvc_status SetMSLBufferSizeBufferIndex(uint32_t index) {
    return shaderc_spvc_compile_options_set_msl_buffer_size_buffer_index(
        options_.get(), index);
  }

  // Which HLSL shader model should be used.  Default is 30.
  shaderc_spvc_status SetHLSLShaderModel(uint32_t model) {
    return shaderc_spvc_compile_options_set_hlsl_shader_model(options_.get(),
                                                              model);
  }

  // If true, ignore PointSize.  Default is false.
  shaderc_spvc_status SetHLSLPointSizeCompat(bool b) {
    return shaderc_spvc_compile_options_set_hlsl_point_size_compat(
        options_.get(), b);
  }

  // If true, ignore PointCoord.  Default is false.
  shaderc_spvc_status SetHLSLPointCoordCompat(bool b) {
    return shaderc_spvc_compile_options_set_hlsl_point_coord_compat(
        options_.get(), b);
  }

  // If true, enable 16-bit types.  Default is false.
  shaderc_spvc_status SetHLSLEnable16BitTypes(bool b) {
    return shaderc_spvc_compile_options_set_hlsl_enable_16bit_types(
        options_.get(), b);
  }

  // If true, set non-writable storage images to be SRV, see spirv_hlsl.hpp in
  // SPIRV-Cross for more details.
  shaderc_spvc_status SetHLSLNonWritableUAVTextureAsSRV(bool b) {
    return shaderc_spvc_compile_options_set_hlsl_nonwritable_uav_texture_as_srv(
        options_.get(), b);
  }

  // If true (default is false):
  //   GLSL: map depth from Vulkan/D3D style to GL style, i.e. [ 0,w] -> [-w,w]
  //   MSL : map depth from GL style to Vulkan/D3D style, i.e. [-w,w] -> [ 0,w]
  //   HLSL: map depth from GL style to Vulkan/D3D style, i.e. [-w,w] -> [ 0,w]
  shaderc_spvc_status SetFixupClipspace(bool b) {
    return shaderc_spvc_compile_options_set_fixup_clipspace(options_.get(), b);
  }

  // If true invert gl_Position.y or equivalent.  Default is false.
  shaderc_spvc_status SetFlipVertY(bool b) {
    return shaderc_spvc_compile_options_set_flip_vert_y(options_.get(), b);
  }

  // If true validate input and intermediate source. Default is true.
  shaderc_spvc_status SetValidate(bool b) {
    return shaderc_spvc_compile_options_set_validate(options_.get(), b);
  }

  // If true optimize input and intermediate source. Default is true.
  shaderc_spvc_status SetOptimize(bool b) {
    return shaderc_spvc_compile_options_set_optimize(options_.get(), b);
  }

  // Fill options with given data.  Return amount of data used, or zero
  // if not enough data was given.
  size_t SetForFuzzing(const uint8_t* data, size_t size) {
    return shaderc_spvc_compile_options_set_for_fuzzing(options_.get(), data,
                                                        size);
  }

 private:
  CompileOptions& operator=(const CompileOptions& other) = delete;
  std::unique_ptr<shaderc_spvc_compile_options,
                  void (*)(shaderc_spvc_compile_options_t)>
      options_;

  friend class Context;
};

// The compilation context for compiling SPIR-V.
class Context {
 public:
  Context()
      : context_(shaderc_spvc_context_create(), shaderc_spvc_context_destroy) {}

  Context(Context&& other) : context_(nullptr, shaderc_spvc_context_destroy) {
    context_.reset(other.context_.release());
  }

  bool IsValid() const { return context_ != nullptr; }

  // Returns logged messages from operations
  const std::string GetMessages() const {
    return shaderc_spvc_context_get_messages(context_.get());
  }

  // EXPERIMENTAL
  // Returns the internal spirv_cross compiler reference, does NOT transfer
  // ownership.
  // This is being exposed temporarily to ease integration of spvc into Dawn,
  // but this is will be removed in the future without warning.
  shaderc_spvc_status GetCompiler(void** compiler) {
    return shaderc_spvc_context_get_compiler(context_.get(), compiler);
  }

  shaderc_spvc_status SetUseSpvcParser(bool b) {
    return shaderc_spvc_context_set_use_spvc_parser(context_.get(), b);
  }

  // Initializes state for compiling SPIR-V to GLSL.
  shaderc_spvc_status InitializeForGlsl(const uint32_t* source,
                                        size_t source_len,
                                        const CompileOptions& options) const {
    return shaderc_spvc_initialize_for_glsl(context_.get(), source, source_len,
                                            options.options_.get());
  }

  // Initializes state for compiling SPIR-V to HLSL.
  shaderc_spvc_status InitializeForHlsl(const uint32_t* source,
                                        size_t source_len,
                                        const CompileOptions& options) const {
    return shaderc_spvc_initialize_for_hlsl(context_.get(), source, source_len,
                                            options.options_.get());
  }

  // Initializes state for compiling SPIR-V to MSL.
  shaderc_spvc_status InitializeForMsl(const uint32_t* source,
                                       size_t source_len,
                                       const CompileOptions& options) const {
    return shaderc_spvc_initialize_for_msl(context_.get(), source, source_len,
                                           options.options_.get());
  }

  // Initializes state for compiling SPIR-V to Vulkan.
  shaderc_spvc_status InitializeForVulkan(const uint32_t* source,
                                          size_t source_len,
                                          const CompileOptions& options) const {
    return shaderc_spvc_initialize_for_vulkan(
        context_.get(), source, source_len, options.options_.get());
  }

  // After initialization compile the shader to desired language.
  shaderc_spvc_status CompileShader(CompilationResult* result) {
    return shaderc_spvc_compile_shader(context_.get(), result->result_.get());
  }

  // Set spirv_cross decoration (added for HLSL support in Dawn)
  // Given an id, decoration and argument, the decoration flag on the id is set,
  // assuming id is valid.
  shaderc_spvc_status SetDecoration(uint32_t id,
                                    shaderc_spvc_decoration decoration,
                                    uint32_t argument) {
    return shaderc_spvc_set_decoration(context_.get(), id, decoration, argument);
  }

  // Get spirv_cross decoration (added for GLSL API support in Dawn).
  // Given an id and a decoration, result is sent out through |argument|
  // if |id| does not exist, returns an error.
  shaderc_spvc_status GetDecoration(uint32_t id,
                                    shaderc_spvc_decoration decoration,
                                    uint32_t* argument) {
    return shaderc_spvc_get_decoration(context_.get(), id, decoration, argument);
  }

  // Unset spirv_cross decoration (added for GLSL API support in Dawn).
  // Given an id and a decoration. Assuming id is valid.
  shaderc_spvc_status UnsetDecoration(uint32_t id,
                                      shaderc_spvc_decoration decoration) {
    return shaderc_spvc_unset_decoration(context_.get(), id, decoration);
  }

  // spirv-cross comment:
  // Analyzes all separate image and samplers used from the currently selected
  // entry point, and re-routes them all to a combined image sampler instead.
  // (added for GLSL API support in Dawn)
  shaderc_spvc_status BuildCombinedImageSamplers(void) {
    return shaderc_spvc_build_combined_image_samplers(context_.get());
  }

  // After call to BuildCombinedImageSamplers, fetch the ids associated with the
  // combined image samplers.
  shaderc_spvc_status GetCombinedImageSamplers(
      std::vector<shaderc_spvc_combined_image_sampler>* samplers) {
    size_t count;
    shaderc_spvc_status status = shaderc_spvc_get_combined_image_samplers(
        context_.get(), nullptr, &count);
    if (status != shaderc_spvc_status_success) return status;
    samplers->resize(count);
    return shaderc_spvc_get_combined_image_samplers(context_.get(),
                                                    samplers->data(), &count);
  }

  // set |name| on a given |id| (added for GLSL support in Dawn).
  // Assuming id is valid.
  shaderc_spvc_status SetName(uint32_t id, const std::string& name) {
    return shaderc_spvc_set_name(context_.get(), id, name.c_str());
  }

  // Adds a binding to indicate the MSL buffer, texture or sampler index to use
  // for a particular SPIR-V description set and binding.
  shaderc_spvc_status AddMSLResourceBinding(
      const shaderc_spvc_msl_resource_binding binding) {
    return shaderc_spvc_add_msl_resource_binding(context_.get(), binding);
  }

  // Gets workgroup size for an entry point defined by a given execution model
  // and function name.
  shaderc_spvc_status GetWorkgroupSize(
      const std::string& function_name,
      shaderc_spvc_execution_model execution_model,
      shaderc_spvc_workgroup_size* workgroup_size) {
    return shaderc_spvc_get_workgroup_size(
        context_.get(), function_name.c_str(), execution_model, workgroup_size);
  }

  // Gets whether or not the shader needes a buffer of buffer sizes.
  shaderc_spvc_status NeedsBufferSizeBuffer(bool* b) {
    return shaderc_spvc_needs_buffer_size_buffer(context_.get(), b);
  }

  // Gets the execution model for the shader.
  shaderc_spvc_status GetExecutionModel(shaderc_spvc_execution_model* model) {
    return shaderc_spvc_get_execution_model(context_.get(), model);
  }

  // Gets the number of push constant buffers used by the shader.
  shaderc_spvc_status GetPushConstantBufferCount(size_t* count) {
    return shaderc_spvc_get_push_constant_buffer_count(context_.get(), count);
  }

  // Gets all of the binding info for a given shader resource.
  shaderc_spvc_status GetBindingInfo(
      shaderc_spvc_shader_resource resource,
      shaderc_spvc_binding_type binding_type,
      std::vector<shaderc_spvc_binding_info>* bindings) {
    if (!bindings) {
      return shaderc_spvc_status_invalid_out_param;
    }

    size_t binding_count;
    shaderc_spvc_status status = shaderc_spvc_get_binding_info(
        context_.get(), resource, binding_type, nullptr, &binding_count);
    if (status != shaderc_spvc_status_success) {
      return status;
    }

    bindings->resize(binding_count);
    return shaderc_spvc_get_binding_info(context_.get(), resource, binding_type,
                                         bindings->data(), &binding_count);
  }

  // Gets the Location decoration information for the stage inputs.
  shaderc_spvc_status GetInputStageLocationInfo(
      std::vector<shaderc_spvc_resource_location_info>* locations) {
    if (!locations) {
      return shaderc_spvc_status_invalid_out_param;
    }

    size_t location_count;
    shaderc_spvc_status status = shaderc_spvc_get_input_stage_location_info(
        context_.get(), nullptr, &location_count);
    if (status != shaderc_spvc_status_success) {
      return status;
    }

    locations->resize(location_count);
    return shaderc_spvc_get_input_stage_location_info(
        context_.get(), locations->data(), &location_count);
  }

  // Gets the Location decoration information for the stage output.
  shaderc_spvc_status GetOutputStageLocationInfo(
      std::vector<shaderc_spvc_resource_location_info>* locations) {
    if (!locations) {
      return shaderc_spvc_status_invalid_out_param;
    }

    size_t location_count;
    shaderc_spvc_status status = shaderc_spvc_get_output_stage_location_info(
        context_.get(), nullptr, &location_count);
    if (status != shaderc_spvc_status_success) {
      return status;
    }

    locations->resize(location_count);
    return shaderc_spvc_get_output_stage_location_info(
        context_.get(), locations->data(), &location_count);
  }

  // Gets the type information for the stage output.
  shaderc_spvc_status GetOutputStageTypeInfo(
      std::vector<shaderc_spvc_resource_type_info>* types) {
    if (!types) {
      return shaderc_spvc_status_invalid_out_param;
    }

    size_t type_count;
    shaderc_spvc_status status = shaderc_spvc_get_output_stage_type_info(
        context_.get(), nullptr, &type_count);
    if (status != shaderc_spvc_status_success) {
      return status;
    }

    types->resize(type_count);
    return shaderc_spvc_get_output_stage_type_info(context_.get(),
                                                   types->data(), &type_count);
  }

  // Set storage buffers to be always declared as UAV, even if the read-only 
  // declaration is used, see spirv_hlsl.hpp in SPIRV-Cross for more details.
  shaderc_spvc_status SetHLSLForceStorageBufferAsUAV(uint32_t desc_set, uint32_t binding) {
    return shaderc_spvc_set_hlsl_force_storage_buffer_as_uav(context_.get(), desc_set, binding);
  }

 private:
  Context(const Context&) = delete;
  Context& operator=(const Context& other) = delete;

  std::unique_ptr<shaderc_spvc_context, void (*)(shaderc_spvc_context_t)>
      context_;
};

}  // namespace shaderc_spvc

#endif  // SHADERC_SPVC_HPP_