• Home
Name Date Size #Lines LOC

..--

.reuse/12-May-2024-129

LICENSES/12-May-2024-554414

cmake/12-May-2024-104

gn/12-May-2024-6962

include/spirv_cross/12-May-2024-1,100813

pkg-config/12-May-2024-1713

reference/12-May-2024-106,78991,030

samples/cpp/12-May-2024-407230

shaders/12-May-2024-14,61013,024

shaders-hlsl/12-May-2024-5,1964,621

shaders-hlsl-no-opt/12-May-2024-3,7683,516

shaders-msl/12-May-2024-14,29212,624

shaders-msl-no-opt/12-May-2024-13,40112,256

shaders-no-opt/12-May-2024-8,6918,290

shaders-other/12-May-2024-6663

shaders-reflection/12-May-2024-1,1511,049

shaders-ue4/asm/12-May-2024-20,95020,915

shaders-ue4-no-opt/asm/12-May-2024-3,1063,102

tests-other/12-May-2024-955748

.clang-formatD12-May-20245.9 KiB171115

.gitignoreD12-May-2024261 2522

.travis.ymlD12-May-20242.7 KiB7666

CMakeLists.txtD12-May-202425.5 KiB618535

CODE_OF_CONDUCT.adocD12-May-2024390 129

GLSL.std.450.hD12-May-20243 KiB11590

LICENSED12-May-202411.1 KiB203169

MakefileD12-May-2024908 4527

README.mdD12-May-202420.9 KiB522365

appveyor.ymlD12-May-2024767 3422

build_glslang_spirv_tools.shD12-May-2024689 2919

checkout_glslang_spirv_tools.shD12-May-20241.4 KiB5846

format_all.shD12-May-2024307 115

main.cppD12-May-202470.9 KiB1,7581,543

spirv.hD12-May-2024110 KiB2,1932,090

spirv.hppD12-May-2024104.1 KiB2,2042,102

spirv_cfg.cppD12-May-202413.4 KiB405271

spirv_cfg.hppD12-May-20243.7 KiB164115

spirv_common.hppD12-May-202444.5 KiB1,8491,318

spirv_cpp.cppD12-May-202415.7 KiB559422

spirv_cpp.hppD12-May-20242.6 KiB9452

spirv_cross.cppD12-May-2024144.6 KiB5,0453,839

spirv_cross.hppD12-May-202447.8 KiB1,129609

spirv_cross_c.cppD12-May-202482.6 KiB2,6342,262

spirv_cross_c.hD12-May-202447.5 KiB1,022673

spirv_cross_containers.hppD12-May-202417.3 KiB748579

spirv_cross_error_handling.hppD12-May-20242.6 KiB9560

spirv_cross_parsed_ir.cppD12-May-202424.2 KiB1,065850

spirv_cross_parsed_ir.hppD12-May-20248.7 KiB250146

spirv_cross_util.cppD12-May-20242.6 KiB7844

spirv_cross_util.hppD12-May-20241.4 KiB3811

spirv_glsl.cppD12-May-2024512.3 KiB16,20012,848

spirv_glsl.hppD12-May-202443.1 KiB946670

spirv_hlsl.cppD12-May-2024171.5 KiB5,8874,857

spirv_hlsl.hppD12-May-202415.1 KiB380227

spirv_msl.cppD12-May-2024565.3 KiB15,98612,930

spirv_msl.hppD12-May-202452.4 KiB1,158763

spirv_parser.cppD12-May-202430.5 KiB1,202909

spirv_parser.hppD12-May-20242.5 KiB10263

spirv_reflect.cppD12-May-202421.2 KiB707575

spirv_reflect.hppD12-May-20242.4 KiB9253

test_shaders.pyD12-May-202435.9 KiB936778

test_shaders.shD12-May-20241.6 KiB3223

update_test_shaders.shD12-May-2024124 71

README.md

1<!--
2    Copyright 2020-2021 The Khronos Group, Inc.
3    SPDX-License-Identifier: CC-BY-4.0
4-->
5
6# SPIRV-Cross
7
8SPIRV-Cross is a tool designed for parsing and converting SPIR-V to other shader languages.
9
10[![CI](https://github.com/KhronosGroup/SPIRV-Cross/actions/workflows/main.yml/badge.svg)](https://github.com/KhronosGroup/SPIRV-Cross/actions/workflows/main.yml)
11[![Build Status](https://ci.appveyor.com/api/projects/status/github/KhronosGroup/SPIRV-Cross?svg=true&branch=master)](https://ci.appveyor.com/project/HansKristian-Work/SPIRV-Cross)
12
13## Features
14
15  - Convert SPIR-V to readable, usable and efficient GLSL
16  - Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
17  - Convert SPIR-V to readable, usable and efficient HLSL
18  - Convert SPIR-V to a JSON reflection format
19  - Convert SPIR-V to debuggable C++ [DEPRECATED]
20  - Reflection API to simplify the creation of Vulkan pipeline layouts
21  - Reflection API to modify and tweak OpDecorations
22  - Supports "all" of vertex, fragment, tessellation, geometry and compute shaders.
23
24SPIRV-Cross tries hard to emit readable and clean output from the SPIR-V.
25The goal is to emit GLSL or MSL that looks like it was written by a human and not awkward IR/assembly-like code.
26
27NOTE: Individual features are expected to be mostly complete, but it is possible that certain obscure GLSL features are not yet supported.
28However, most missing features are expected to be "trivial" improvements at this stage.
29
30## Building
31
32SPIRV-Cross has been tested on Linux, iOS/OSX, Windows and Android. CMake is the main build system.
33
34### Linux and macOS
35
36Building with CMake is recommended, as it is the only build system which is tested in continuous integration.
37It is also the only build system which has install commands and other useful build system features.
38
39However, you can just run `make` on the command line as a fallback if you only care about the CLI tool.
40
41A non-ancient GCC (4.8+) or Clang (3.x+) compiler is required as SPIRV-Cross uses C++11 extensively.
42
43### Windows
44
45Building with CMake is recommended, which is the only way to target MSVC.
46MinGW-w64 based compilation works with `make` as a fallback.
47
48### Android
49
50SPIRV-Cross is only useful as a library here. Use the CMake build to link SPIRV-Cross to your project.
51
52### C++ exceptions
53
54The make and CMake build flavors offer the option to treat exceptions as assertions. To disable exceptions for make just append `SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=1` to the command line. For CMake append `-DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS=ON`. By default exceptions are enabled.
55
56### Static, shared and CLI
57
58You can use `-DSPIRV_CROSS_STATIC=ON/OFF` `-DSPIRV_CROSS_SHARED=ON/OFF` `-DSPIRV_CROSS_CLI=ON/OFF` to control which modules are built (and installed).
59
60## Usage
61
62### Using the C++ API
63
64The C++ API is the main API for SPIRV-Cross. For more in-depth documentation than what's provided in this README,
65please have a look at the [Wiki](https://github.com/KhronosGroup/SPIRV-Cross/wiki).
66**NOTE**: This API is not guaranteed to be ABI-stable, and it is highly recommended to link against this API statically.
67The API is generally quite stable, but it can change over time, see the C API for more stability.
68
69To perform reflection and convert to other shader languages you can use the SPIRV-Cross API.
70For example:
71
72```c++
73#include "spirv_glsl.hpp"
74#include <vector>
75#include <utility>
76
77extern std::vector<uint32_t> load_spirv_file();
78
79int main()
80{
81	// Read SPIR-V from disk or similar.
82	std::vector<uint32_t> spirv_binary = load_spirv_file();
83
84	spirv_cross::CompilerGLSL glsl(std::move(spirv_binary));
85
86	// The SPIR-V is now parsed, and we can perform reflection on it.
87	spirv_cross::ShaderResources resources = glsl.get_shader_resources();
88
89	// Get all sampled images in the shader.
90	for (auto &resource : resources.sampled_images)
91	{
92		unsigned set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet);
93		unsigned binding = glsl.get_decoration(resource.id, spv::DecorationBinding);
94		printf("Image %s at set = %u, binding = %u\n", resource.name.c_str(), set, binding);
95
96		// Modify the decoration to prepare it for GLSL.
97		glsl.unset_decoration(resource.id, spv::DecorationDescriptorSet);
98
99		// Some arbitrary remapping if we want.
100		glsl.set_decoration(resource.id, spv::DecorationBinding, set * 16 + binding);
101	}
102
103	// Set some options.
104	spirv_cross::CompilerGLSL::Options options;
105	options.version = 310;
106	options.es = true;
107	glsl.set_options(options);
108
109	// Compile to GLSL, ready to give to GL driver.
110	std::string source = glsl.compile();
111}
112```
113
114### Using the C API wrapper
115
116To facilitate C compatibility and compatibility with foreign programming languages, a C89-compatible API wrapper is provided. Unlike the C++ API,
117the goal of this wrapper is to be fully stable, both API and ABI-wise.
118This is the only interface which is supported when building SPIRV-Cross as a shared library.
119
120An important point of the wrapper is that all memory allocations are contained in the `spvc_context`.
121This simplifies the use of the API greatly. However, you should destroy the context as soon as reasonable,
122or use `spvc_context_release_allocations()` if you intend to reuse the `spvc_context` object again soon.
123
124Most functions return a `spvc_result`, where `SPVC_SUCCESS` is the only success code.
125For brevity, the code below does not do any error checking.
126
127```c
128#include <spirv_cross_c.h>
129
130const SpvId *spirv = get_spirv_data();
131size_t word_count = get_spirv_word_count();
132
133spvc_context context = NULL;
134spvc_parsed_ir ir = NULL;
135spvc_compiler compiler_glsl = NULL;
136spvc_compiler_options options = NULL;
137spvc_resources resources = NULL;
138const spvc_reflected_resource *list = NULL;
139const char *result = NULL;
140size_t count;
141size_t i;
142
143// Create context.
144spvc_context_create(&context);
145
146// Set debug callback.
147spvc_context_set_error_callback(context, error_callback, userdata);
148
149// Parse the SPIR-V.
150spvc_context_parse_spirv(context, spirv, word_count, &ir);
151
152// Hand it off to a compiler instance and give it ownership of the IR.
153spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl);
154
155// Do some basic reflection.
156spvc_compiler_create_shader_resources(compiler_glsl, &resources);
157spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);
158
159for (i = 0; i < count; i++)
160{
161    printf("ID: %u, BaseTypeID: %u, TypeID: %u, Name: %s\n", list[i].id, list[i].base_type_id, list[i].type_id,
162           list[i].name);
163    printf("  Set: %u, Binding: %u\n",
164           spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationDescriptorSet),
165           spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationBinding));
166}
167
168// Modify options.
169spvc_compiler_create_compiler_options(compiler_glsl, &options);
170spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 330);
171spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE);
172spvc_compiler_install_compiler_options(compiler_glsl, options);
173
174spvc_compiler_compile(compiler_glsl, &result);
175printf("Cross-compiled source: %s\n", result);
176
177// Frees all memory we allocated so far.
178spvc_context_destroy(context);
179```
180
181### Linking
182
183#### CMake add_subdirectory()
184
185This is the recommended way if you are using CMake and want to link against SPIRV-Cross statically.
186
187#### Integrating SPIRV-Cross in a custom build system
188
189To add SPIRV-Cross to your own codebase, just copy the source and header files from root directory
190and build the relevant .cpp files you need. Make sure to build with C++11 support, e.g. `-std=c++11` in GCC and Clang.
191Alternatively, the Makefile generates a libspirv-cross.a static library during build that can be linked in.
192
193#### Linking against SPIRV-Cross as a system library
194
195It is possible to link against SPIRV-Cross when it is installed as a system library,
196which would be mostly relevant for Unix-like platforms.
197
198##### pkg-config
199
200For Unix-based systems, a pkg-config is installed for the C API, e.g.:
201
202```
203$ pkg-config spirv-cross-c-shared --libs --cflags
204-I/usr/local/include/spirv_cross -L/usr/local/lib -lspirv-cross-c-shared
205```
206
207##### CMake
208
209If the project is installed, it can be found with `find_package()`, e.g.:
210
211```
212cmake_minimum_required(VERSION 3.5)
213set(CMAKE_C_STANDARD 99)
214project(Test LANGUAGES C)
215
216find_package(spirv_cross_c_shared)
217if (spirv_cross_c_shared_FOUND)
218        message(STATUS "Found SPIRV-Cross C API! :)")
219else()
220        message(STATUS "Could not find SPIRV-Cross C API! :(")
221endif()
222
223add_executable(test test.c)
224target_link_libraries(test spirv-cross-c-shared)
225```
226
227test.c:
228```c
229#include <spirv_cross_c.h>
230
231int main(void)
232{
233        spvc_context context;
234        spvc_context_create(&context);
235        spvc_context_destroy(context);
236}
237```
238
239### CLI
240
241The CLI is suitable for basic cross-compilation tasks, but it cannot support the full flexibility that the API can.
242Some examples below.
243
244#### Creating a SPIR-V file from GLSL with glslang
245
246```
247glslangValidator -H -V -o test.spv test.frag
248```
249
250#### Converting a SPIR-V file to GLSL ES
251
252```
253glslangValidator -H -V -o test.spv shaders/comp/basic.comp
254./spirv-cross --version 310 --es test.spv
255```
256
257#### Converting to desktop GLSL
258
259```
260glslangValidator -H -V -o test.spv shaders/comp/basic.comp
261./spirv-cross --version 330 --no-es test.spv --output test.comp
262```
263
264#### Disable prettifying optimizations
265
266```
267glslangValidator -H -V -o test.spv shaders/comp/basic.comp
268./spirv-cross --version 310 --es test.spv --output test.comp --force-temporary
269```
270
271### Using shaders generated from C++ backend
272
273Please see `samples/cpp` where some GLSL shaders are compiled to SPIR-V, decompiled to C++ and run with test data.
274Reading through the samples should explain how to use the C++ interface.
275A simple Makefile is included to build all shaders in the directory.
276
277### Implementation notes
278
279When using SPIR-V and SPIRV-Cross as an intermediate step for cross-compiling between high level languages there are some considerations to take into account,
280as not all features used by one high-level language are necessarily supported natively by the target shader language.
281SPIRV-Cross aims to provide the tools needed to handle these scenarios in a clean and robust way, but some manual action is required to maintain compatibility.
282
283#### HLSL source to GLSL
284
285##### HLSL entry points
286
287When using SPIR-V shaders compiled from HLSL, there are some extra things you need to take care of.
288First make sure that the entry point is used correctly.
289If you forget to set the entry point correctly in glslangValidator (-e MyFancyEntryPoint),
290you will likely encounter this error message:
291
292```
293Cannot end a function before ending the current block.
294Likely cause: If this SPIR-V was created from glslang HLSL, make sure the entry point is valid.
295```
296
297##### Vertex/Fragment interface linking
298
299HLSL relies on semantics in order to effectively link together shader stages. In the SPIR-V generated by glslang, the transformation from HLSL to GLSL ends up looking like
300
301```c++
302struct VSOutput {
303   // SV_Position is rerouted to gl_Position
304   float4 position : SV_Position;
305   float4 coord : TEXCOORD0;
306};
307
308VSOutput main(...) {}
309```
310
311```c++
312struct VSOutput {
313   float4 coord;
314}
315layout(location = 0) out VSOutput _magicNameGeneratedByGlslang;
316```
317
318While this works, be aware of the type of the struct which is used in the vertex stage and the fragment stage.
319There may be issues if the structure type name differs in vertex stage and fragment stage.
320
321You can make use of the reflection interface to force the name of the struct type.
322
323```
324// Something like this for both vertex outputs and fragment inputs.
325compiler.set_name(varying_resource.base_type_id, "VertexFragmentLinkage");
326```
327
328Some platform may require identical variable name for both vertex outputs and fragment inputs. (for example MacOSX)
329to rename variable base on location, please add
330```
331--rename-interface-variable <in|out> <location> <new_variable_name>
332```
333
334#### HLSL source to legacy GLSL/ESSL
335
336HLSL tends to emit varying struct types to pass data between vertex and fragment.
337This is not supported in legacy GL/GLES targets, so to support this, varying structs are flattened.
338This is done automatically, but the API user might need to be aware that this is happening in order to support all cases.
339
340Modern GLES code like this:
341```c++
342struct Output {
343   vec4 a;
344   vec2 b;
345};
346out Output vout;
347```
348
349Is transformed into:
350```c++
351struct Output {
352   vec4 a;
353   vec2 b;
354};
355varying vec4 Output_a;
356varying vec2 Output_b;
357```
358
359Note that now, both the struct name and the member names will participate in the linking interface between vertex and fragment, so
360API users might want to ensure that both the struct names and member names match so that vertex outputs and fragment inputs can link properly.
361
362
363#### Separate image samplers (HLSL/Vulkan) for backends which do not support it (GLSL)
364
365Another thing you need to remember is when using samplers and textures in HLSL these are separable, and not directly compatible with GLSL. If you need to use this with desktop GL/GLES, you need to call `Compiler::build_combined_image_samplers` first before calling `Compiler::compile`, or you will get an exception.
366
367```c++
368// From main.cpp
369// Builds a mapping for all combinations of images and samplers.
370compiler->build_combined_image_samplers();
371
372// Give the remapped combined samplers new names.
373// Here you can also set up decorations if you want (binding = #N).
374for (auto &remap : compiler->get_combined_image_samplers())
375{
376   compiler->set_name(remap.combined_id, join("SPIRV_Cross_Combined", compiler->get_name(remap.image_id),
377            compiler->get_name(remap.sampler_id)));
378}
379```
380
381If your target is Vulkan GLSL, `--vulkan-semantics` will emit separate image samplers as you'd expect.
382The command line client calls `Compiler::build_combined_image_samplers` automatically, but if you're calling the library, you'll need to do this yourself.
383
384#### Descriptor sets (Vulkan GLSL) for backends which do not support them (HLSL/GLSL/Metal)
385
386Descriptor sets are unique to Vulkan, so make sure that descriptor set + binding is remapped to a flat binding scheme (set always 0), so that other APIs can make sense of the bindings.
387This can be done with `Compiler::set_decoration(id, spv::DecorationDescriptorSet)`.
388
389#### Linking by name for targets which do not support explicit locations (legacy GLSL/ESSL)
390
391Modern GLSL and HLSL sources (and SPIR-V) relies on explicit layout(location) qualifiers to guide the linking process between shader stages,
392but older GLSL relies on symbol names to perform the linking. When emitting shaders with older versions, these layout statements will be removed,
393so it is important that the API user ensures that the names of I/O variables are sanitized so that linking will work properly.
394The reflection API can rename variables, struct types and struct members to deal with these scenarios using `Compiler::set_name` and friends.
395
396#### Clip-space conventions
397
398SPIRV-Cross can perform some common clip space conversions on gl_Position/SV_Position by enabling `CompilerGLSL::Options.vertex.fixup_clipspace`.
399While this can be convenient, it is recommended to modify the projection matrices instead as that can achieve the same result.
400
401For GLSL targets, enabling this will convert a shader which assumes `[0, w]` depth range (Vulkan / D3D / Metal) into `[-w, w]` range.
402For MSL and HLSL targets, enabling this will convert a shader in `[-w, w]` depth range (OpenGL) to `[0, w]` depth range.
403
404By default, the CLI will not enable `fixup_clipspace`, but in the API you might want to set an explicit value using `CompilerGLSL::set_options()`.
405
406Y-flipping of gl_Position and similar is also supported.
407The use of this is discouraged, because relying on vertex shader Y-flipping tends to get quite messy.
408To enable this, set `CompilerGLSL::Options.vertex.flip_vert_y` or `--flip-vert-y` in CLI.
409
410#### Reserved identifiers
411
412When cross-compiling, certain identifiers are considered to be reserved by the implementation.
413Code generated by SPIRV-Cross cannot emit these identifiers as they are reserved and used for various internal purposes,
414and such variables will typically show up as `_RESERVED_IDENTIFIER_FIXUP_`
415or some similar name to make it more obvious that an identifier has been renamed.
416
417Reflection output will follow the exact name specified in the SPIR-V module. It might not be a valid identifier in the C sense,
418as it may contain non-alphanumeric/non-underscore characters.
419
420Reserved identifiers currently assumed by the implementation are (in pseudo-regex):
421
422- _$digit+, e.g. `_100`, `_2`
423- _$digit+_.+, e.g. `_100_tmp`, `_2_foobar`. `_2Bar` is **not** reserved.
424- gl_- prefix
425- spv- prefix
426- SPIRV_Cross prefix. This prefix is generally used for interface variables where app needs to provide data for workaround purposes.
427  This identifier will not be rewritten, but be aware of potential collisions.
428- Double underscores (reserved by all target languages).
429
430Members of structs also have a reserved identifier:
431- _m$digit+$END, e.g. `_m20` and `_m40` are reserved, but not `_m40Foobar`.
432
433## Contributing
434
435Contributions to SPIRV-Cross are welcome. See Testing and Licensing sections for details.
436
437### Testing
438
439SPIRV-Cross maintains a test suite of shaders with reference output of how the output looks after going through a roundtrip through
440glslangValidator/spirv-as then back through SPIRV-Cross again.
441The reference files are stored inside the repository in order to be able to track regressions.
442
443All pull requests should ensure that test output does not change unexpectedly. This can be tested with:
444
445```
446./checkout_glslang_spirv_tools.sh # Checks out glslang and SPIRV-Tools at a fixed revision which matches the reference output.
447                                  # NOTE: Some users have reported problems cloning from git:// paths. To use https:// instead pass in
448                                  # $ PROTOCOL=https ./checkout_glslang_spirv_tools.sh
449                                  # instead.
450./build_glslang_spirv_tools.sh    # Builds glslang and SPIRV-Tools.
451./test_shaders.sh                 # Runs over all changes and makes sure that there are no deltas compared to reference files.
452```
453
454`./test_shaders.sh` currently requires a Makefile setup with GCC/Clang to be set up.
455However, on Windows, this can be rather inconvenient if a MinGW environment is not set up.
456To use a spirv-cross binary you built with CMake (or otherwise), you can pass in an environment variable as such:
457
458```
459SPIRV_CROSS_PATH=path/to/custom/spirv-cross ./test_shaders.sh
460```
461
462However, when improving SPIRV-Cross there are of course legitimate cases where reference output should change.
463In these cases, run:
464
465```
466./update_test_shaders.sh          # SPIRV_CROSS_PATH also works here.
467```
468
469to update the reference files and include these changes as part of the pull request.
470Always make sure you are running the correct version of glslangValidator as well as SPIRV-Tools when updating reference files.
471See `checkout_glslang_spirv_tools.sh` which revisions are currently expected. The revisions change regularly.
472
473In short, the master branch should always be able to run `./test_shaders.py shaders` and friends without failure.
474SPIRV-Cross uses Travis CI to test all pull requests, so it is not strictly needed to perform testing yourself if you have problems running it locally.
475A pull request which does not pass testing on Travis will not be accepted however.
476
477When adding support for new features to SPIRV-Cross, a new shader and reference file should be added which covers usage of the new shader features in question.
478Travis CI runs the test suite with the CMake, by running `ctest`. This is a more straight-forward alternative to `./test_shaders.sh`.
479
480### Licensing
481
482Contributors of new files should add a copyright header at the top of every new source code file with their copyright
483along with the Apache 2.0 licensing stub.
484
485### Formatting
486
487SPIRV-Cross uses `clang-format` to automatically format code.
488Please use `clang-format` with the style sheet found in `.clang-format` to automatically format code before submitting a pull request.
489
490To make things easy, the `format_all.sh` script can be used to format all
491source files in the library. In this directory, run the following from the
492command line:
493
494	./format_all.sh
495
496## Regression testing
497
498In shaders/ a collection of shaders are maintained for purposes of regression testing.
499The current reference output is contained in reference/.
500`./test_shaders.py shaders` can be run to perform regression testing.
501
502See `./test_shaders.py --help` for more.
503
504### Metal backend
505
506To test the roundtrip path GLSL -> SPIR-V -> MSL, `--msl` can be added, e.g. `./test_shaders.py --msl shaders-msl`.
507
508### HLSL backend
509
510To test the roundtrip path GLSL -> SPIR-V -> HLSL, `--hlsl` can be added, e.g. `./test_shaders.py --hlsl shaders-hlsl`.
511
512### Updating regression tests
513
514When legitimate changes are found, use `--update` flag to update regression files.
515Otherwise, `./test_shaders.py` will fail with error code.
516
517### Mali Offline Compiler cycle counts
518
519To obtain a CSV of static shader cycle counts before and after going through spirv-cross, add
520`--malisc` flag to `./test_shaders`. This requires the Mali Offline Compiler to be installed in PATH.
521
522