Giter Site home page Giter Site logo

khronosgroup / spirv-cross Goto Github PK

View Code? Open in Web Editor NEW
2.0K 87.0 549.0 15.41 MB

SPIRV-Cross is a practical tool and library for performing reflection on SPIR-V and disassembling SPIR-V back to high level languages.

License: Apache License 2.0

C++ 29.03% Makefile 0.01% C 2.41% GLSL 63.66% JavaScript 3.95% Python 0.51% Shell 0.05% CMake 0.32% Assembly 0.03% Swift 0.03%

spirv-cross's Introduction

SPIRV-Cross

SPIRV-Cross is a tool designed for parsing and converting SPIR-V to other shader languages.

CI Build Status

Features

  • Convert SPIR-V to readable, usable and efficient GLSL
  • Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL)
  • Convert SPIR-V to readable, usable and efficient HLSL
  • Convert SPIR-V to a JSON reflection format
  • Convert SPIR-V to debuggable C++ [DEPRECATED]
  • Reflection API to simplify the creation of Vulkan pipeline layouts
  • Reflection API to modify and tweak OpDecorations
  • Supports "all" of vertex, fragment, tessellation, geometry and compute shaders.

SPIRV-Cross tries hard to emit readable and clean output from the SPIR-V. The goal is to emit GLSL or MSL that looks like it was written by a human and not awkward IR/assembly-like code.

NOTE: Individual features are expected to be mostly complete, but it is possible that certain obscure GLSL features are not yet supported. However, most missing features are expected to be "trivial" improvements at this stage.

Building

SPIRV-Cross has been tested on Linux, iOS/OSX, Windows and Android. CMake is the main build system.

NOTE: main branch rename

On 2023-01-12, master was renamed to main as per Khronos policy.

Linux and macOS

Building with CMake is recommended, as it is the only build system which is tested in continuous integration. It is also the only build system which has install commands and other useful build system features.

However, you can just run make on the command line as a fallback if you only care about the CLI tool.

A non-ancient GCC (4.8+) or Clang (3.x+) compiler is required as SPIRV-Cross uses C++11 extensively.

Windows

Building with CMake is recommended, which is the only way to target MSVC. MinGW-w64 based compilation works with make as a fallback.

Android

SPIRV-Cross is only useful as a library here. Use the CMake build to link SPIRV-Cross to your project.

C++ exceptions

The 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.

Static, shared and CLI

You 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).

Installing SPIRV-Cross (vcpkg)

Alternatively, you can build and install SPIRV-Cross using vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install spirv-cross

The SPIRV-Cross port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Usage

Using the C++ API

The C++ API is the main API for SPIRV-Cross. For more in-depth documentation than what's provided in this README, please have a look at the Wiki. NOTE: This API is not guaranteed to be ABI-stable, and it is highly recommended to link against this API statically. The API is generally quite stable, but it can change over time, see the C API for more stability.

To perform reflection and convert to other shader languages you can use the SPIRV-Cross API. For example:

#include "spirv_glsl.hpp"
#include <vector>
#include <utility>

extern std::vector<uint32_t> load_spirv_file();

int main()
{
	// Read SPIR-V from disk or similar.
	std::vector<uint32_t> spirv_binary = load_spirv_file();

	spirv_cross::CompilerGLSL glsl(std::move(spirv_binary));

	// The SPIR-V is now parsed, and we can perform reflection on it.
	spirv_cross::ShaderResources resources = glsl.get_shader_resources();

	// Get all sampled images in the shader.
	for (auto &resource : resources.sampled_images)
	{
		unsigned set = glsl.get_decoration(resource.id, spv::DecorationDescriptorSet);
		unsigned binding = glsl.get_decoration(resource.id, spv::DecorationBinding);
		printf("Image %s at set = %u, binding = %u\n", resource.name.c_str(), set, binding);

		// Modify the decoration to prepare it for GLSL.
		glsl.unset_decoration(resource.id, spv::DecorationDescriptorSet);

		// Some arbitrary remapping if we want.
		glsl.set_decoration(resource.id, spv::DecorationBinding, set * 16 + binding);
	}

	// Set some options.
	spirv_cross::CompilerGLSL::Options options;
	options.version = 310;
	options.es = true;
	glsl.set_common_options(options);

	// Compile to GLSL, ready to give to GL driver.
	std::string source = glsl.compile();
}

Using the C API wrapper

To facilitate C compatibility and compatibility with foreign programming languages, a C89-compatible API wrapper is provided. Unlike the C++ API, the goal of this wrapper is to be fully stable, both API and ABI-wise. This is the only interface which is supported when building SPIRV-Cross as a shared library.

An important point of the wrapper is that all memory allocations are contained in the spvc_context. This simplifies the use of the API greatly. However, you should destroy the context as soon as reasonable, or use spvc_context_release_allocations() if you intend to reuse the spvc_context object again soon.

Most functions return a spvc_result, where SPVC_SUCCESS is the only success code. For brevity, the code below does not do any error checking.

#include <spirv_cross_c.h>

const SpvId *spirv = get_spirv_data();
size_t word_count = get_spirv_word_count();

spvc_context context = NULL;
spvc_parsed_ir ir = NULL;
spvc_compiler compiler_glsl = NULL;
spvc_compiler_options options = NULL;
spvc_resources resources = NULL;
const spvc_reflected_resource *list = NULL;
const char *result = NULL;
size_t count;
size_t i;

// Create context.
spvc_context_create(&context);

// Set debug callback.
spvc_context_set_error_callback(context, error_callback, userdata);

// Parse the SPIR-V.
spvc_context_parse_spirv(context, spirv, word_count, &ir);

// Hand it off to a compiler instance and give it ownership of the IR.
spvc_context_create_compiler(context, SPVC_BACKEND_GLSL, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler_glsl);

// Do some basic reflection.
spvc_compiler_create_shader_resources(compiler_glsl, &resources);
spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count);

for (i = 0; i < count; i++)
{
    printf("ID: %u, BaseTypeID: %u, TypeID: %u, Name: %s\n", list[i].id, list[i].base_type_id, list[i].type_id,
           list[i].name);
    printf("  Set: %u, Binding: %u\n",
           spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationDescriptorSet),
           spvc_compiler_get_decoration(compiler_glsl, list[i].id, SpvDecorationBinding));
}

// Modify options.
spvc_compiler_create_compiler_options(compiler_glsl, &options);
spvc_compiler_options_set_uint(options, SPVC_COMPILER_OPTION_GLSL_VERSION, 330);
spvc_compiler_options_set_bool(options, SPVC_COMPILER_OPTION_GLSL_ES, SPVC_FALSE);
spvc_compiler_install_compiler_options(compiler_glsl, options);

spvc_compiler_compile(compiler_glsl, &result);
printf("Cross-compiled source: %s\n", result);

// Frees all memory we allocated so far.
spvc_context_destroy(context);

Linking

CMake add_subdirectory()

This is the recommended way if you are using CMake and want to link against SPIRV-Cross statically.

Integrating SPIRV-Cross in a custom build system

To add SPIRV-Cross to your own codebase, just copy the source and header files from root directory and build the relevant .cpp files you need. Make sure to build with C++11 support, e.g. -std=c++11 in GCC and Clang. Alternatively, the Makefile generates a libspirv-cross.a static library during build that can be linked in.

Linking against SPIRV-Cross as a system library

It is possible to link against SPIRV-Cross when it is installed as a system library, which would be mostly relevant for Unix-like platforms.

pkg-config

For Unix-based systems, a pkg-config is installed for the C API, e.g.:

$ pkg-config spirv-cross-c-shared --libs --cflags
-I/usr/local/include/spirv_cross -L/usr/local/lib -lspirv-cross-c-shared
CMake

If the project is installed, it can be found with find_package(), e.g.:

cmake_minimum_required(VERSION 3.5)
set(CMAKE_C_STANDARD 99)
project(Test LANGUAGES C)

find_package(spirv_cross_c_shared)
if (spirv_cross_c_shared_FOUND)
        message(STATUS "Found SPIRV-Cross C API! :)")
else()
        message(STATUS "Could not find SPIRV-Cross C API! :(")
endif()

add_executable(test test.c)
target_link_libraries(test spirv-cross-c-shared)

test.c:

#include <spirv_cross_c.h>

int main(void)
{
        spvc_context context;
        spvc_context_create(&context);
        spvc_context_destroy(context);
}

CLI

The CLI is suitable for basic cross-compilation tasks, but it cannot support the full flexibility that the API can. Some examples below.

Creating a SPIR-V file from GLSL with glslang

glslangValidator -H -V -o test.spv test.frag

Converting a SPIR-V file to GLSL ES

glslangValidator -H -V -o test.spv shaders/comp/basic.comp
./spirv-cross --version 310 --es test.spv

Converting to desktop GLSL

glslangValidator -H -V -o test.spv shaders/comp/basic.comp
./spirv-cross --version 330 --no-es test.spv --output test.comp

Disable prettifying optimizations

glslangValidator -H -V -o test.spv shaders/comp/basic.comp
./spirv-cross --version 310 --es test.spv --output test.comp --force-temporary

Using shaders generated from C++ backend

Please see samples/cpp where some GLSL shaders are compiled to SPIR-V, decompiled to C++ and run with test data. Reading through the samples should explain how to use the C++ interface. A simple Makefile is included to build all shaders in the directory.

Implementation notes

When 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, as not all features used by one high-level language are necessarily supported natively by the target shader language. SPIRV-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.

HLSL source to GLSL

HLSL entry points

When using SPIR-V shaders compiled from HLSL, there are some extra things you need to take care of. First make sure that the entry point is used correctly. If you forget to set the entry point correctly in glslangValidator (-e MyFancyEntryPoint), you will likely encounter this error message:

Cannot end a function before ending the current block.
Likely cause: If this SPIR-V was created from glslang HLSL, make sure the entry point is valid.
Vertex/Fragment interface linking

HLSL 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

struct VSOutput {
   // SV_Position is rerouted to gl_Position
   float4 position : SV_Position;
   float4 coord : TEXCOORD0;
};

VSOutput main(...) {}
struct VSOutput {
   float4 coord;
}
layout(location = 0) out VSOutput _magicNameGeneratedByGlslang;

While this works, be aware of the type of the struct which is used in the vertex stage and the fragment stage. There may be issues if the structure type name differs in vertex stage and fragment stage.

You can make use of the reflection interface to force the name of the struct type.

// Something like this for both vertex outputs and fragment inputs.
compiler.set_name(varying_resource.base_type_id, "VertexFragmentLinkage");

Some platform may require identical variable name for both vertex outputs and fragment inputs. (for example MacOSX) to rename variable base on location, please add

--rename-interface-variable <in|out> <location> <new_variable_name>

HLSL source to legacy GLSL/ESSL

HLSL tends to emit varying struct types to pass data between vertex and fragment. This is not supported in legacy GL/GLES targets, so to support this, varying structs are flattened. This is done automatically, but the API user might need to be aware that this is happening in order to support all cases.

Modern GLES code like this:

struct Output {
   vec4 a;
   vec2 b;
};
out Output vout;

Is transformed into:

struct Output {
   vec4 a;
   vec2 b;
};
varying vec4 Output_a;
varying vec2 Output_b;

Note that now, both the struct name and the member names will participate in the linking interface between vertex and fragment, so API users might want to ensure that both the struct names and member names match so that vertex outputs and fragment inputs can link properly.

Separate image samplers (HLSL/Vulkan) for backends which do not support it (GLSL)

Another 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.

// From main.cpp
// Builds a mapping for all combinations of images and samplers.
compiler->build_combined_image_samplers();

// Give the remapped combined samplers new names.
// Here you can also set up decorations if you want (binding = #N).
for (auto &remap : compiler->get_combined_image_samplers())
{
   compiler->set_name(remap.combined_id, join("SPIRV_Cross_Combined", compiler->get_name(remap.image_id),
            compiler->get_name(remap.sampler_id)));
}

If your target is Vulkan GLSL, --vulkan-semantics will emit separate image samplers as you'd expect. The command line client calls Compiler::build_combined_image_samplers automatically, but if you're calling the library, you'll need to do this yourself.

Descriptor sets (Vulkan GLSL) for backends which do not support them (pre HLSL 5.1 / GLSL)

Descriptor 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. This can be done with Compiler::set_decoration(id, spv::DecorationDescriptorSet). For other backends like MSL and HLSL, descriptor sets can be used, with some minor caveats, see below.

MSL 2.0+

Metal supports indirect argument buffers (--msl-argument-buffers). In this case, descriptor sets become argument buffers, and bindings are mapped to [[id(N)]] within the argument buffer. One quirk is that arrays of resources consume multiple ids, where Vulkan does not. This can be worked around either from shader authoring stage or remapping bindings as needed to avoid the overlap. There is also a rich API to declare remapping schemes which is intended to work like the pipeline layout in Vulkan. See CompilerMSL::add_msl_resource_binding. Remapping combined image samplers for example must be split into two bindings in MSL, so it's possible to declare an id for the texture and sampler binding separately.

HLSL - SM 5.1+

In SM 5.1+, descriptor set bindings are interpreted as register spaces directly. In HLSL however, arrays of resources consume multiple binding slots where Vulkan does not, so there might be overlap if the SPIR-V was not authored with this in mind. This can be worked around either from shader authoring stage (don't assign overlapping bindings) or remap bindings in SPIRV-Cross as needed to avoid the overlap.

Linking by name for targets which do not support explicit locations (legacy GLSL/ESSL)

Modern GLSL and HLSL sources (and SPIR-V) relies on explicit layout(location) qualifiers to guide the linking process between shader stages, but older GLSL relies on symbol names to perform the linking. When emitting shaders with older versions, these layout statements will be removed, so it is important that the API user ensures that the names of I/O variables are sanitized so that linking will work properly. The reflection API can rename variables, struct types and struct members to deal with these scenarios using Compiler::set_name and friends.

Clip-space conventions

SPIRV-Cross can perform some common clip space conversions on gl_Position/SV_Position by enabling CompilerGLSL::Options.vertex.fixup_clipspace. While this can be convenient, it is recommended to modify the projection matrices instead as that can achieve the same result.

For GLSL targets, enabling this will convert a shader which assumes [0, w] depth range (Vulkan / D3D / Metal) into [-w, w] range. For MSL and HLSL targets, enabling this will convert a shader in [-w, w] depth range (OpenGL) to [0, w] depth range.

By default, the CLI will not enable fixup_clipspace, but in the API you might want to set an explicit value using CompilerGLSL::set_options().

Y-flipping of gl_Position and similar is also supported. The use of this is discouraged, because relying on vertex shader Y-flipping tends to get quite messy. To enable this, set CompilerGLSL::Options.vertex.flip_vert_y or --flip-vert-y in CLI.

Reserved identifiers

When cross-compiling, certain identifiers are considered to be reserved by the implementation. Code generated by SPIRV-Cross cannot emit these identifiers as they are reserved and used for various internal purposes, and such variables will typically show up as _RESERVED_IDENTIFIER_FIXUP_ or some similar name to make it more obvious that an identifier has been renamed.

Reflection output will follow the exact name specified in the SPIR-V module. It might not be a valid identifier in the C sense, as it may contain non-alphanumeric/non-underscore characters.

Reserved identifiers currently assumed by the implementation are (in pseudo-regex):

  • _$digit+, e.g. _100, _2
  • $digit+.+, e.g. _100_tmp, _2_foobar. _2Bar is not reserved.
  • gl_- prefix
  • spv- prefix
  • SPIRV_Cross prefix. This prefix is generally used for interface variables where app needs to provide data for workaround purposes. This identifier will not be rewritten, but be aware of potential collisions.
  • Double underscores (reserved by all target languages).

Members of structs also have a reserved identifier:

  • _m$digit+$END, e.g. _m20 and _m40 are reserved, but not _m40Foobar.

Contributing

Contributions to SPIRV-Cross are welcome. See Testing and Licensing sections for details.

Testing

SPIRV-Cross maintains a test suite of shaders with reference output of how the output looks after going through a roundtrip through glslangValidator/spirv-as then back through SPIRV-Cross again. The reference files are stored inside the repository in order to be able to track regressions.

All pull requests should ensure that test output does not change unexpectedly. This can be tested with:

./checkout_glslang_spirv_tools.sh # Checks out glslang and SPIRV-Tools at a fixed revision which matches the reference output.
./build_glslang_spirv_tools.sh    # Builds glslang and SPIRV-Tools.
./test_shaders.sh                 # Runs over all changes and makes sure that there are no deltas compared to reference files.

./test_shaders.sh currently requires a Makefile setup with GCC/Clang to be set up. However, on Windows, this can be rather inconvenient if a MinGW environment is not set up. To use a spirv-cross binary you built with CMake (or otherwise), you can pass in an environment variable as such:

SPIRV_CROSS_PATH=path/to/custom/spirv-cross ./test_shaders.sh

However, when improving SPIRV-Cross there are of course legitimate cases where reference output should change. In these cases, run:

./update_test_shaders.sh          # SPIRV_CROSS_PATH also works here.

to update the reference files and include these changes as part of the pull request. Always make sure you are running the correct version of glslangValidator as well as SPIRV-Tools when updating reference files. See checkout_glslang_spirv_tools.sh which revisions are currently expected. The revisions change regularly.

In short, the main branch should always be able to run ./test_shaders.py shaders and friends without failure. SPIRV-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. A pull request which does not pass testing on Travis will not be accepted however.

When 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. Travis CI runs the test suite with the CMake, by running ctest. This is a more straight-forward alternative to ./test_shaders.sh.

Licensing

Contributors of new files should add a copyright header at the top of every new source code file with their copyright along with the Apache 2.0 licensing stub.

Formatting

SPIRV-Cross uses clang-format to automatically format code. Please use clang-format with the style sheet found in .clang-format to automatically format code before submitting a pull request.

To make things easy, the format_all.sh script can be used to format all source files in the library. In this directory, run the following from the command line:

./format_all.sh

Regression testing

In shaders/ a collection of shaders are maintained for purposes of regression testing. The current reference output is contained in reference/. ./test_shaders.py shaders can be run to perform regression testing.

See ./test_shaders.py --help for more.

Metal backend

To test the roundtrip path GLSL -> SPIR-V -> MSL, --msl can be added, e.g. ./test_shaders.py --msl shaders-msl.

HLSL backend

To test the roundtrip path GLSL -> SPIR-V -> HLSL, --hlsl can be added, e.g. ./test_shaders.py --hlsl shaders-hlsl.

Updating regression tests

When legitimate changes are found, use --update flag to update regression files. Otherwise, ./test_shaders.py will fail with error code.

Mali Offline Compiler cycle counts

To obtain a CSV of static shader cycle counts before and after going through spirv-cross, add --malisc flag to ./test_shaders. This requires the Mali Offline Compiler to be installed in PATH.

spirv-cross's People

Contributors

amerkoleci avatar attackgoat avatar atyuwen avatar billhollings avatar catcuddler avatar cdavis5e avatar dj2 avatar etang-cw avatar georgeouzou avatar gwihlidal avatar h3xl3r avatar hanskristian-work avatar hugobros3 avatar jherico avatar js6i avatar justsid avatar kangz avatar luboslenco avatar lukasbanana avatar marksatt-pitbull avatar mbarriault avatar msiglreith avatar pmoursnv avatar randomshaper avatar rcoreilly avatar rdb avatar robdangerous avatar troughton avatar try avatar zeux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spirv-cross's Issues

Flesh out C++ backend system for images and samplers

While the C++ backend can deal well with plain buffers, we need a more sophisticated interface for images.

It seems practical to expose a callback oriented (or plain virtual in C++) interface that lets API users handle sampling instead of having SPIRV-Cross implement a full texture unit and a texture creation API to go along with it. A few basic implementations of said interface could be useful for trivial use cases.

A way to deal with derivatives in fragment backend using a similar system to compute implementation of thread groups is useful, but compute seems like a more important use case for now.

get_type() don't return real array-size

Hello guys, the following function doesn't return the real array size.
Here is my code:
[SPIRV]
layout (set=0, binding=1) uniform texture2D myArrayOfSampledImages[12];

[Code]
`

    for (auto &resource : resources.storage_images)
    {
        unsigned int setNum = comp.get_decoration(resource.id, spv::DecorationDescriptorSet);
        unsigned int bindingNum = comp.get_decoration(resource.id, spv::DecorationBinding);

        spirv_cross::SPIRType type = comp.get_type(resource.type_id);
    }

`

spirv_cross

Or is this the wrong way to get the total array size?^^

shaders/tesc/basic.tesc fails

Generated GLSL in /tmp/tmpt1cmqw_0basic.tesc does not match reference /blah/SPIRV-Cross/shaders/tesc/basic.tesc!

$ diff /tmp/*tesc ../shaders/tesc/basic.tesc
3d2
< layout(vertices = 1) out;
5c4,6
< out patch vec3 vFoo;

---
> patch out vec3 vFoo;
> 
> layout(vertices = 1) out;
9,14c10,15
<     gl_TessLevelInner[0] = 8.8999996185302734375;
<     gl_TessLevelInner[1] = 6.900000095367431640625;
<     gl_TessLevelOuter[0] = 8.8999996185302734375;
<     gl_TessLevelOuter[1] = 6.900000095367431640625;
<     gl_TessLevelOuter[2] = 3.900000095367431640625;
<     gl_TessLevelOuter[3] = 4.900000095367431640625;

---
>     gl_TessLevelInner[0] = 8.9;
>     gl_TessLevelInner[1] = 6.9;
>     gl_TessLevelOuter[0] = 8.9;
>     gl_TessLevelOuter[1] = 6.9;
>     gl_TessLevelOuter[2] = 3.9;
>     gl_TessLevelOuter[3] = 4.9;
17d17
< 

There are three problems:

  • ordering of the "out patch" vs. "patch out"
  • location of the layout directive
  • floating point numbers that can't be represented exactly. For these I recommend using a fractional portion like .875 instead of .9

MSL: Wrongly named point_size builtin

When generating MSL shader source with "MSLConfiguration.is_rendering_points" set to true, there's a mismatch in naming for the [[point_size]] builtin between output block and assigment in vertex function:

struct mmain_out
{
    float3 v_bary [[user(locn0)]];
    float4 gl_PerVertex_gl_Position [[position]];
    float gl_PerVertex_gl_PointSize [[point_size]];
    float gl_PerVertex_gl_ClipDistance /* [[clip_distance]] built-in not yet supported under Metal. */;
};

vertex mmain_out mmain(mmain_in in [[stage_in]], constant PushConstants& vs_pcs [[buffer(16)]], uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]])
{
    mmain_out out = {};
    out.v_bary = in.a_bary;
    out.gl_PointSize = 2.0;
    out.gl_PerVertex_gl_Position = (vs_pcs.mvp * in.a_position);
    return out;
}

float gl_PerVertex_gl_PointSize [[point_size]];
vs
out.gl_PointSize = 2.0;

Several MSL tests fail in Travis but not locally due to non-optimized for(;;) loops

The following GLSL tests:

flatten/dynamic.flatten.vert
flatten/copy.flatten.vert
frag/for-loop-init.frag

all convert correctly GLSL->SPIRV->MSL, compile as valid MSL, and pass as tests when run locally, but cause the Travis build to fail the MD5 comparison when submitted to GitHub.

All of these tests seem to be failing because they create a non-optimized for(;;) loops when run under Travis, whereas the same tests create correctly-structured for-loops when run locally.

Internal Compiler Error - VS 2013

Hello guys, i tried to compile my rendering engine (developed on vs 2015) to compile it on vs 2013.
I have got always the C1001 Error: Internal Compiler Error in file "spirv_common.hpp".

struct SPIREntryPoint
{
    SPIREntryPoint(uint32_t self_, spv::ExecutionModel execution_model, std::string entry_name)
        : self(self_)
        , name(std::move(entry_name))
        , model(execution_model)
    {
    }
    SPIREntryPoint() = default;

    uint32_t self = 0;
    std::string name;
    std::vector<uint32_t> interface_variables;

    uint64_t flags = 0;
    struct
    {
        uint32_t x = 0, y = 0, z = 0;
    } workgroup_size;
    uint32_t invocations = 0;
    uint32_t output_vertices = 0;
    spv::ExecutionModel model = {};
};

I could manage to fix it by removing the empty-bracket initilization from the
spv::ExecutionModel model = {};

I just wanna know why this is working then. (and i dont want to do this every time i update spirv-cross in my engine)

Thanks in Advance :)

Support tesselation shaders in Metal backend..

Hi,
just pointing it out..ย Not muchย usage right now since MoltenVK stillย doesn't support tesselation stage which is new in OSX 10.12 and IOS 10..
Can't ask about geometry shaders as this stage isn't supported on Metal..
Wouldย be nice if a detailed issue is created detailing all Metal shading features and if currently supported by SPIR-Vย cross similar to this (HLSL support in glslang):
KhronosGroup/glslang#362

SPIRV-Cross dont work

Hello guys,
i am really sorry that i have to create a issue here, but i tryed almost everything and i have always the same problem and i dont know if its a bug or a mistake of my part.

So i want to use SPIRV-Cross do build automatically an appropriate Pipeline-Layout, but the library stops always at this part in spirv_cross.cpp in the parse() function:

uint32_t offset = 5; while (offset < len) inst.emplace_back(spirv, offset);

There is always an endless loop here, with every shader i tryed to load. Shaders working fine. I tryied using a static lib (building with VS 15) and adding the files to my own codebase. With both approaches the same result.

Hope you can help me :(

GLSL code generation throws exception in non-Vulkan semantics mode when sampling a texture (generated from HLSL)

The to-GLSL compiler crashes when options.vulkan_semantics = false:

		throw CompilerError("Cannot find mapping for combined sampler, was build_combined_image_samplers() used "
		                    "before compile() was called?");

Works fine when options.vulkan_semantics = true, but obviously it'll then generate descriptor set annotations that won't work in regular GLSL.

Here's the original HLSL:

struct VertexData {
	float4 color : COLOR0;
	float2 uv : TEXCOORD0;
};

SamplerState samp : register(s0);
Texture2D<float4> tex : register(t0);

float4 pshader(VertexData vin) : SV_Target {
	return tex.Sample(samp, vin.uv) * vin.color;
}

Resulting in the following SPIR-V:

                          Capability Shader
           1:             ExtInstImport  "GLSL.std.450"
                          MemoryModel Logical GLSL450
                          EntryPoint Fragment 4  "pshader" 9 22 26
                          ExecutionMode 4 OriginUpperLeft
                          Name 4  "pshader"
                          Name 9  "@entryPointOutput"
                          Name 12  "tex"
                          Name 16  "samp"
                          Name 22  "uv"
                          Name 26  "color"
                          Decorate 9(@entryPointOutput) Location 0
                          Decorate 12(tex) DescriptorSet 0
                          Decorate 12(tex) Binding 0
                          Decorate 16(samp) DescriptorSet 0
                          Decorate 16(samp) Binding 0
                          Decorate 22(uv) Location 1
                          Decorate 26(color) Location 0
           2:             TypeVoid
           3:             TypeFunction 2
           6:             TypeFloat 32
           7:             TypeVector 6(float) 4
           8:             TypePointer Output 7(fvec4)
9(@entryPointOutput):      8(ptr) Variable Output
          10:             TypeImage 6(float) 2D sampled format:Unknown
          11:             TypePointer UniformConstant 10
     12(tex):     11(ptr) Variable UniformConstant
          14:             TypeSampler
          15:             TypePointer UniformConstant 14
    16(samp):     15(ptr) Variable UniformConstant
          18:             TypeSampledImage 10
          20:             TypeVector 6(float) 2
          21:             TypePointer Input 20(fvec2)
      22(uv):     21(ptr) Variable Input
          25:             TypePointer Input 7(fvec4)
   26(color):     25(ptr) Variable Input
  4(pshader):           2 Function None 3
           5:             Label
          13:          10 Load 12(tex)
          17:          14 Load 16(samp)
          19:          18 SampledImage 13 17
          23:   20(fvec2) Load 22(uv)
          24:    7(fvec4) ImageSampleImplicitLod 19 23
          27:    7(fvec4) Load 26(color)
          28:    7(fvec4) FMul 24 27
                          Store 9(@entryPointOutput) 28
                          Return
                          FunctionEnd

And the crash happened when trying to generate GLSL from this using spirv-cross (as a library), of course.

Output interface block causes a crash when converting to metal

If you have the following GLSL code compiled to SPIR-V:

uniform Transform
{
    mat4 transform;
} block;

in vec3 position;
in vec4 color;

out VertexOut
{
    vec4 color;
} outputs;

void main()
{
    gl_Position = block.transform*vec4(position, 1.0);
    outputs.color = color;
}

cross-compiling to metal will throw an exception in the function Compiler::get_member_decoration() because the meta members element is empty.

Wrong type is assigned to globlal variable.

spirv-cross assigns wrong type for a global variable. Reproducable with the attached shader.

$ glslangValidator -G ao.comp -o ao.spv
$ spirv-cross ao.spv

...
layout(binding = 1) uniform writeonly image2D destTex;

Sphere sphere[3];
Ray plane;  // <-- * this should be 'Plane plane'
...

ao.comp.txt

test_shaders.py on OS X: FileNotFoundError: [Errno 2] No such file or directory: 'glslangValidator'

@Kangz @HansKristian-ARM

Where you able to get the test script running on OS X?

I am attempting to run the following on OS X 10.11.6 (El Capitan):

./test_shaders.py --metal shaders-msl

but I get the following error:

FileNotFoundError: [Errno 2] No such file or directory: 'glslangValidator'

glslang/build/StandAlone is in my $PATH, it is built, and I can successfully invoke an unqualified glslangValidator directly from the command line from any directory, including the directory containing test_shaders.py.

Any idea why this isn't working for me? Was there additional setup you performed for any of SPIRV-Cross, glslangValidator, or Python in order to allow Python's subprocess.check_call() function to find glslangValidator under OS X?

Thanks.

Integer ops do not correctly bitcast

SPIR-V allows certain opcodes to be of "unexpected" types, e.g. adds where one argument is signed and the other is not. This should be fixed so that SPIRV-Cross emits bitcast opcodes where needed to ensure that the output GLSL is valid and correct.

This is mostly a problem with operations like ivec4(bvec4), ++ operator, etc where a SPIR-V compiler emits magic snippets of code. ++ operator was already handled, but we need to expand this to all opcodes.

To verify implementation, a test setup for SPIR-V assembly will be needed as well.

Progress is tracked in integer-bitcast-ops branch.

Python3 detection not working on Windows

I get a "Could not find python3" warning when I run cmake for this project on Windows, despite having Python 3.5.2 installed. It seems to be looking for a python3.exe, and I don't see one in the installation directory (just python.exe).

It's not a fatal error, but is there any way to eliminate the spurious warning? Some way to disable testing before the Python3 check, perhaps?

SubpassData and input_attachment are ignored

The decompiler currently does not handle input attachments. For example, starting from:

#version 310 es

precision highp float;
layout(input_attachment_index = 1, set = 2, binding = 4) uniform highp subpassInput i;
uniform Block { ivec2 coord2; };
out vec4 o;

void main()
{
    o = subpassLoad(i);
}

I do:

% glslangValidator -V a.frag
% spirv-dis frag.spv | grep InputAttachment
               OpCapability InputAttachment
               OpDecorate %i InputAttachmentIndex 1
% spirv-cross frag.spv | grep binding
layout(set = 2, binding = 4) uniform highp sampler2D i;

Short Question

Hello just a short question,
is it possible to get the member-name of a struct? Say i have this

layout (set = 6, binding = 1) uniform Material_D
{
    vec4 color;
    float specularIntensity;
    float specularPower;
    float uvScale;
} material;

with
const spirv_cross::SPIRType& type = comp.get_type(resource.type_id);
i can get the member types, but i didnt find anything about the member names.
Is this possible?
Thanks in Advance
P.S. For the future, where can i ask such questions?

EDIT:
My intention is to get the offset and size of a member through a name e.g. getOffset("specularPower") --> return a struct with { 20, 4 }

Inactive variables

I'm generating spir-v using glslang. Although shader reflection from glslang correctly reports only active variables (varying inputs/outputs, ubos etc), they appear in the generated spir-v.

SPIR-Cross lists these variables when doing print_resources(). Is there a way to prevent inactive variables from being listed in shader resources?

CPP backend does not emit struct information for writeonly buffer correctly

In recent commit 6aa2007 , CPP backend turned into not emitting struct definition for writeonly buffer correctly.

$ ./spirv-cross --cpp --output basic-comp.cc shaders/comp/basic.comp
namespace Impl
{
    struct Shader
    {
        struct Resources : ComputeResources
        {
            struct SSBO
            {
                vec4 in_data[1];
            };

            internal::Resource<struct SSBO> _23__;
#define _23 __res->_23__.get()

            internal::Resource<struct SSBO> _45__; // <-
#define _45 __res->_45__.get()

Writing readonly in variable in GLSL

When converting an HLSL shader that does something like this:

PSInput Main(VSInput input)
{
  input.Position.y = 0;
  ...
}

it is converted to glsl that looks something like this:

layout(location = 0) in vec4 Position;
...

void main()
{
  Position.y = 0.0;
}

The driver does not accept this because Position is readonly. To fix this I can simply change the hlsl to introduce a temporary local variable which is used further in the function (float3 tempPos = input.Position). However, I think this should be done by the cross compiler or it should be an error caught by the cross compiler.

new Microsoft DXIL format output support?

Hi,
don't know if makes sense to ask as part of this project.. but seeing existing HLSL support, would like to ask SPIRV-Cross devs for supporting as output Microsoft new DXIL format which is part of open sourced Microsoft new shader compiler for Shader Model 6.0, i.e. effectively supporting SPIRV -> DXIL translation..
also don't know where to ask about DXIL->SPIRV translation as don't hope Microsoft does this work..
thanks..

Test framework for C++ backend needed

With C++ backend we can validate outputs easily unlike GLSL which needs to run through a driver.
Tests for C++ should cover C++ specific issues mostly.

Exception thrown when parsing SPIR-V with mismatched entry point

As reported in KhronosGroup/glslang#588 (I first thought it was a glslang bug, and maybe it still is, but SPIRV-Cross shouldn't throw an exception).

The following HLSL:

float4 PixelShaderFunction(float4 input) : COLOR0   {
    return float4(0.0, 1.0, 0.0, 2.0);
}

Generates (through glslangValidator -V -D) the following SPIR-V:

                              Capability Shader
               1:             ExtInstImport  "GLSL.std.450"
                              MemoryModel Logical GLSL450
                              EntryPoint Fragment 4  "main"
                              ExecutionMode 4 OriginUpperLeft
                              Name 4  "main"
                              Name 11  "PixelShaderFunction(vf4;"
                              Name 10  "input"
               2:             TypeVoid
               3:             TypeFunction 2
               6:             TypeFloat 32
               7:             TypeVector 6(float) 4
               8:             TypePointer Function 7(fvec4)
               9:             TypeFunction 7(fvec4) 8(ptr)
              13:    6(float) Constant 0
              14:    6(float) Constant 1065353216
              15:    6(float) Constant 1073741824
              16:    7(fvec4) ConstantComposite 13 14 13 15
         4(main):           2 Function None 3
               5:             Label
                              FunctionEnd
11(PixelShaderFunction(vf4;):    7(fvec4) Function None 9
       10(input):      8(ptr) FunctionParameter
              12:             Label
                              ReturnValue 16
                              FunctionEnd

Note that I specified "main" as the entry point while it was actually called "PixelShaderFunction", which causes the duplicate blocks. This crashes when fed into SPIRV-Cross, here:

throw CompilerError("Cannot start a block before ending the current block.");

This seems unfortunate and a better error message would really be nice.

flatten_interface_block is too limited

This library includes a function for flattening UBO for legacy GL targets (flatten_interface_block), but it only works if all members are of the same primitive type (so would work if all of them are float3 for example).

I'd like to change this - currently using SPIRV-Cross on our shader codebase isn't really practical for legacy GLES targets because of this (and even on GLES 3 there are bugs in some Adreno drivers that make using UBO problematic).

My understanding is that the biggest issue with this is that right now flattening can only rewrite the UBO declaration, which requires that SPIRV access chains are compatible between old and new layout. This may be solvable to an extent for simple cases, but ideally this would be generic.

I see two possible approaches for this:

  1. Extend flatten_interface_block to be able to rewrite SPIRV access chains. I'm a bit wary of this approach but mostly because I don't have a good understanding of SPIRV yet and am not sure of what rewriting parts of SPIRV code involves.

  2. Change flatten_interface_block to merely mark UB as "flattened", and extend GLSL generator to rewrite access chains. I did something along these lines once before, in an AST-to-GLSL translator:

https://github.com/zeux/hlslparser/commit/5a2106a754ac6b08fc4f017f26a3faea6b590a20#diff-8fa46791ec7a30a112f1575798cebc19R1311 (click "Load diff" to go to the important part)

The diff is a bit messy because I initially tried to generate a GLSL struct from a uniform buffer but it became apparent that supporting arrays is too inefficient with that approach even with glsl-optimizer running on the result - but it should give you the idea of what roughly I am aiming for. This approach results in generic UBO support that can respect whatever packing rules the UBO in question has, and is trivial to do immediate constant folding (https://github.com/zeux/hlslparser/commit/6b6b919ca3cf7eff9a602536bc6d8e3dfc2f00ba) on so that you can convert accesses like

Lights[index].data.radius

to

LightBuffer[5 * index + 4].w

for something like:

struct Light {
    float4x4 transform;
    struct Data {
        float3 color;
        float radius;
    } data;
};

Looking for some guidance & discussion on the above - does it seem like a worthwhile feature for SPIRV-Cross to adopt, what approach seems more promising, am I missing some complexities that this would involve due to the nature of SPIRV, etc.

Pass Vulkan CTS in GLSL backend

The GLSL backend should be verified to pass Vulkan CTS via a roundtrip.
GLSL -> glslang -> SPIRV-Cross -> glslang -> Vulkan.
A way to integrate SPIRV-Cross into Vulkan CTS should be devised.

CompilerCPP does not generate valid c++ for array constant expressions

Invalid c++ is generated for shaders that use constant expressions to initialize arrays.
For example in shaders/frag/constant-array.frag the generated cpp is this:

vec4 indexable[3] = vec4[](vec4(1.0f), vec4(2.0f), vec4(3.0f));
vec4 indexable_1[2][2] = vec4[][](vec4[](vec4(1.0f), vec4(2.0f)), vec4[](vec4(8.0f), vec4(10.0f)));

While this is valid glsl, it is not valid c++.
I fixed this by redefining
virtual std::string constant_expression(const SPIRConstant &c);
in CompilerCPP like this:

string CompilerCPP::constant_expression(const SPIRConstant &c)
{
    if (!c.subconstants.empty())
    {
        // Handles Arrays and structures.
        string res = "{";
        for (auto &elem : c.subconstants)
        {
            res += constant_expression(get<SPIRConstant>(elem));
            if (&elem != &c.subconstants.back())
                res += ", ";
        }
        res += "}";
        return res;
    }
    else if (c.columns() == 1)
    {
        return constant_expression_vector(c, 0);
    }
    else
    {
        string res = "{";
        for (uint32_t col = 0; col < c.columns(); col++)
        {
            res += constant_expression_vector(c, col);
            if (col + 1 < c.columns())
                res += ", ";
        }
        res += "}";
        return res;
    }
}

Compilation errors on Linux due to macro conflict in Xlib.h

When building using SPIRV-Cross and Vulkan, if VK_USE_PLATFORM_XLIB_KHR is defined there is a macro conflict between spirv_common.hpp and X11/Xlib.h

The macro is defined as #define Bool int at line 82 in X11/Xlib.h
This conflicts with the Bool enum defined within spirv_common.hpp, this is a problem for those wishing to easily include spirv-cross and are using the Xlib surface creation with Vulkan.

HLSL support

Not an issue, are there any plans to support HLSL conversion?

Thanks

Wrong layout for tessellation evaluation shader

The header of my tessellation evaluation shader looks like this:

#version 450
layout(triangles, equal_spacing, ccw) in;

However, in the output the 'triangles' is omitted from layout line.

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif
#extension GL_ARB_tessellation_shader : require
layout(ccw, equal_spacing) in;

This throws error at runtime:

GLSL linker error: ERROR: Tessellation evaluation shader must specify triangles, quads or isolines.

After editing the output and explicitly specifying 'triangles', everything appears to work perfectly.

layout(triangles, ccw, equal_spacing) in;

Any idea on the possible cause? Or is this implementation specific and 'triangles' should be taken as default?

I am using SPIRV-Cross through krafix, macos 10.11.6, Intel Iris GPU.

Correct Spir-V not correctly translating to GLES due to extension

Hi,

I'm currently trying to get desktop glsl to gles but I've come across a problem. In desktop glsl, you can sample a texture by creating texture2d and sampler objects in the shader. This is the behavior I'm getting after translating both valid glsl and the experimental hlsl support in glslang. They both produce correct Spir-V as far as I can tell.

However, if I use SPIRV-Cross to try and translate that Spir-V into glsl-es, it asserts saying that the GL_ARB_shader_image_load_store is required.

How is this normally handled? If the Spir-V is valid, should it not compile to everything, perhaps falling back to normal texture sampling and issuing a warning?

Adds unused sampler uniforms when there are functions with sampler parameters

This shader:

#version 330

uniform sampler2D s1;
uniform sampler2D s2;

in vec2 texcoord;
in float selector;

layout (location = 0) out vec4 o;

vec4 helper(sampler2D helpsampler, vec2 c) {
    return texture(helpsampler, c);
}

void main(void) {
    if (selector < 0.0) {
        o = helper(s1, texcoord);
    } else {
        o = helper(s2, texcoord);
    }
}

turns into this after glslang + spirv-cross:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif

uniform sampler2D helpsampler;
uniform sampler2D s1;
uniform sampler2D s2;

in float selector;
layout(location = 0) out vec4 o;
in vec2 texcoord;

vec4 helper(sampler2D helpsampler_1, vec2 c)
{
    return texture(helpsampler_1, c);
}

void main()
{
    vec2 param;
    vec2 param_1;
    if ((selector < 0.0))
    {
        param = texcoord;
        o = helper(s1, param);
    }
    else
    {
        param_1 = texcoord;
        o = helper(s2, param_1);
    }
}

There's a completely unused "helpsampler" uniform and the old "helpsampler" function parameter has been renamed to "helpsampler_1". With a sufficiently complex shader and enough samplers this can make a shader go over implementation-defined limit on number of samplers. This new uniform is also reported in shader resources which confused the hell out of my shader introspection code.

Flexible array member in CPP output

Flexible array member is not supported in C++11 http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c

Thus the following generated CPP code is failed to compile with clang 3.8.

// (c++ code generated from basic.comp example)
namespace Impl
{
    struct Shader
    {
        struct Resources : ComputeResources
        {
            struct SSBO
            {
                vec4 in_data[];
            };
basic-shader.cc:17:22: error: flexible array member 'in_data' of type 'vec4 []' with non-trivial destruction
                vec4 in_data[];

Possible solution is to use pointer representation(vec4 *in_data), but this will require manual update PreDereference flag in PointerInterface class.

Remove redundant nested parenthesis eg: if ((x == y))

Metal presents a warning when redundant parens are encountered in some statements.

For example:

<program source>:97:16: warning: equality comparison with extraneous parentheses
    if ((_4463 == 0.0))
         ~~~~~~^~~~~~
<program source>:97:16: note: remove extraneous parentheses around the comparison to silence this warning
    if ((_4463 == 0.0))
        ~      ^     ~

It sounds like a fix should be fairly straightforward, and would be useful for all language versions...but I don't have a strong enough understanding of statement assembly to make a solid multi-language fix for this.

Can someone with better knowledge of statement assembly (maybe H-K) take a stab at this please?

Thanks...

...Bill

DecorationNonWritable is not respected

Compiler::parse has a comment which indicates that images are set to limited access, and then promoted up, but it doesn't seem like this is being handled properly:

"// glslangValidator does not emit required qualifiers here.
// Solve this by making the image access as restricted as possible
// and loosen up if we need to."

In the following example shader, inputTexture should be decorated as NonWriteable, but it is not. This makes reflecting the difference between DX-style SRVs vs UAVs quite challenging.

#version 430 core

precision highp float;
precision highp int;

layout (local_size_x = 1, local_size_y = 1) in;

layout(rgba16f) readonly uniform image2D inputTexture;
layout(r32f) writeonly uniform image2D outputTexture;

void main()
{
	ivec2 iId = ivec2(gl_GlobalInvocationID.xy) * 2;
	ivec2 oId = ivec2(gl_GlobalInvocationID.xy);
	ivec2 inputSize = imageSize(inputTexture);
	iId.x = clamp(iId.x, 0, max(0, inputSize.x - 2));
	iId.y = clamp(iId.y, 0, max(0, inputSize.y - 2));
	vec3 texel = 
		imageLoad(inputTexture, iId + ivec2(0, 0)).xyz +
		imageLoad(inputTexture, iId + ivec2(1, 0)).xyz +
		imageLoad(inputTexture, iId + ivec2(0, 1)).xyz +
		imageLoad(inputTexture, iId + ivec2(1, 1)).xyz;	
	imageStore(outputTexture, oId, vec4(dot(texel / 4.0, vec3(0.2126, 0.7152, 0.0722)), 0.0, 0.0, 0.0));
}

With SPIRV-Cross, I would expect the following to return true for inputTexture:

compiler.get_decoration(resource.id, spv::DecorationNonWritable)

With glslang::TIntermTraverser, the parsing is correct when visitSymbol is encountered. The following would result in layoutReadOnly being set to true:

virtual void visitSymbol(glslang::TIntermSymbol* base)
{
    if (base->getQualifier().storage == glslang::EvqUniform)
    {
        bool layoutReadOnly = base->getQualifier().readonly;
    }
}

Here is the disassembled spirv for the example shader (notice the correct OpDecorate %inputTexture NonWritable decoration):

; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 100
; Schema: 0
               OpCapability Shader
               OpCapability ImageQuery
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID
               OpExecutionMode %main LocalSize 1 1 1
               OpSource GLSL 430
               OpName %main "main"
               OpName %iId "iId"
               OpName %gl_GlobalInvocationID "gl_GlobalInvocationID"
               OpName %oId "oId"
               OpName %inputSize "inputSize"
               OpName %inputTexture "inputTexture"
               OpName %texel "texel"
               OpName %outputTexture "outputTexture"
               OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId
               OpDecorate %inputTexture DescriptorSet 0
               OpDecorate %inputTexture NonWritable
               OpDecorate %outputTexture DescriptorSet 0
               OpDecorate %outputTexture NonReadable
       %void = OpTypeVoid
          %3 = OpTypeFunction %void
        %int = OpTypeInt 32 1
      %v2int = OpTypeVector %int 2
%_ptr_Function_v2int = OpTypePointer Function %v2int
       %uint = OpTypeInt 32 0
     %v3uint = OpTypeVector %uint 3
%_ptr_Input_v3uint = OpTypePointer Input %v3uint
%gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input
     %v2uint = OpTypeVector %uint 2
         %18 = OpConstant %int 2
      %float = OpTypeFloat 32
         %27 = OpTypeImage %float 2D 0 0 0 2 Rgba16f
%_ptr_UniformConstant_27 = OpTypePointer UniformConstant %27
%inputTexture = OpVariable %_ptr_UniformConstant_27 UniformConstant
         %32 = OpConstant %uint 0
%_ptr_Function_int = OpTypePointer Function %int
         %36 = OpConstant %int 0
         %43 = OpConstant %uint 1
    %v3float = OpTypeVector %float 3
%_ptr_Function_v3float = OpTypePointer Function %v3float
         %57 = OpConstantComposite %v2int %36 %36
    %v4float = OpTypeVector %float 4
         %64 = OpConstant %int 1
         %65 = OpConstantComposite %v2int %64 %36
         %72 = OpConstantComposite %v2int %36 %64
         %79 = OpConstantComposite %v2int %64 %64
         %84 = OpTypeImage %float 2D 0 0 0 2 R32f
%_ptr_UniformConstant_84 = OpTypePointer UniformConstant %84
%outputTexture = OpVariable %_ptr_UniformConstant_84 UniformConstant
         %90 = OpConstant %float 4
         %93 = OpConstant %float 0.2126
         %94 = OpConstant %float 0.7152
         %95 = OpConstant %float 0.0722
         %96 = OpConstantComposite %v3float %93 %94 %95
         %98 = OpConstant %float 0
       %main = OpFunction %void None %3
          %5 = OpLabel
        %iId = OpVariable %_ptr_Function_v2int Function
        %oId = OpVariable %_ptr_Function_v2int Function
  %inputSize = OpVariable %_ptr_Function_v2int Function
      %texel = OpVariable %_ptr_Function_v3float Function
         %15 = OpLoad %v3uint %gl_GlobalInvocationID
         %16 = OpVectorShuffle %v2uint %15 %15 0 1
         %17 = OpBitcast %v2int %16
         %19 = OpCompositeConstruct %v2int %18 %18
         %20 = OpIMul %v2int %17 %19
               OpStore %iId %20
         %22 = OpLoad %v3uint %gl_GlobalInvocationID
         %23 = OpVectorShuffle %v2uint %22 %22 0 1
         %24 = OpBitcast %v2int %23
               OpStore %oId %24
         %30 = OpLoad %27 %inputTexture
         %31 = OpImageQuerySize %v2int %30
               OpStore %inputSize %31
         %34 = OpAccessChain %_ptr_Function_int %iId %32
         %35 = OpLoad %int %34
         %37 = OpAccessChain %_ptr_Function_int %inputSize %32
         %38 = OpLoad %int %37
         %39 = OpISub %int %38 %18
         %40 = OpExtInst %int %1 SMax %36 %39
         %41 = OpExtInst %int %1 SClamp %35 %36 %40
         %42 = OpAccessChain %_ptr_Function_int %iId %32
               OpStore %42 %41
         %44 = OpAccessChain %_ptr_Function_int %iId %43
         %45 = OpLoad %int %44
         %46 = OpAccessChain %_ptr_Function_int %inputSize %43
         %47 = OpLoad %int %46
         %48 = OpISub %int %47 %18
         %49 = OpExtInst %int %1 SMax %36 %48
         %50 = OpExtInst %int %1 SClamp %45 %36 %49
         %51 = OpAccessChain %_ptr_Function_int %iId %43
               OpStore %51 %50
         %55 = OpLoad %27 %inputTexture
         %56 = OpLoad %v2int %iId
         %58 = OpIAdd %v2int %56 %57
         %60 = OpImageRead %v4float %55 %58
         %61 = OpVectorShuffle %v3float %60 %60 0 1 2
         %62 = OpLoad %27 %inputTexture
         %63 = OpLoad %v2int %iId
         %66 = OpIAdd %v2int %63 %65
         %67 = OpImageRead %v4float %62 %66
         %68 = OpVectorShuffle %v3float %67 %67 0 1 2
         %69 = OpFAdd %v3float %61 %68
         %70 = OpLoad %27 %inputTexture
         %71 = OpLoad %v2int %iId
         %73 = OpIAdd %v2int %71 %72
         %74 = OpImageRead %v4float %70 %73
         %75 = OpVectorShuffle %v3float %74 %74 0 1 2
         %76 = OpFAdd %v3float %69 %75
         %77 = OpLoad %27 %inputTexture
         %78 = OpLoad %v2int %iId
         %80 = OpIAdd %v2int %78 %79
         %81 = OpImageRead %v4float %77 %80
         %82 = OpVectorShuffle %v3float %81 %81 0 1 2
         %83 = OpFAdd %v3float %76 %82
               OpStore %texel %83
         %87 = OpLoad %84 %outputTexture
         %88 = OpLoad %v2int %oId
         %89 = OpLoad %v3float %texel
         %91 = OpCompositeConstruct %v3float %90 %90 %90
         %92 = OpFDiv %v3float %89 %91
         %97 = OpDot %float %92 %96
         %99 = OpCompositeConstruct %v4float %97 %98 %98 %98
               OpImageWrite %87 %88 %99
               OpReturn
               OpFunctionEnd

Thank you!
Graham

How to get array size of an array of sampled images

Hello in my Shader-Code i have this:
layout (set = 1, binding = 4) uniform sampler2D ShadowMap_S[16];

I want to get the array-size from this (in this case: 16). I thought the "vecsize" from the type is it, but its always 1.

vecsize

BTW: What is "resources.storage_images"? My first thought was this are the arrays, but thats obviously not true.

Loops in legacy GLES

For loops are currently broken in legacy GLES, as loop variable must be declared inside loop scope. Throwing "for: Missing init declaration":

i = 0;
for (; (i < 4); i = (i + 1))
{
    amount = (amount * 0.5);
}

Any insight on how hard would this be to fix?

Geometry shader contains "layout invocations" even when version is less than #400

This geometry shader:

#version 330
layout(points) in;
layout(max_vertices = 4, triangle_strip) out;
void main()
{
    gl_Position = vec4(1.0f);
    EmitVertex();
    EndPrimitive();
}

when compiled to SPIR-V and back to GLSL results in this:

#version 330
#ifdef GL_ARB_shading_language_420pack
#extension GL_ARB_shading_language_420pack : require
#endif
layout(invocations = 1, points) in;

which will fail with "'invocations' : not supported for this version or the enabled extensions".

Add test cases for debug-stripped SPIR-V files.

There have been some bugs related to files which lack debug information. We should do this as part of the regular regression testing by running all SPIR-V binaries through spirv-remap or similar.

Ability to set entry-point name for spirv-glsl

At least in Vulkan, the entry-point of the shader isn't a constant (main) but is given at shader compilation. Considering the use-case of having an abstraction layer over OpenGL and Vulkan that takes SPIRV for shaders, it seems very useful for spirv-glsl to be able to define at compilation time which function should be output as "main". Better, to save parse-time on the OpenGL driver-side, it would be good if only the main function's dependencies were output in the GLSL.

'flat' keyword omitted

When passing integer attributes from geometry shader into fragment shader, 'flat' keyword used to prevent interpolation is removed from the output. For integers, 'flat' seems to be mandatory and thus removing it will break the shader.

Source:

// Geometry shader
out fData {
    flat int axis;
} frag;

// Fragment shader
in fData {
    flat int axis;
} frag;

Output:

// Geometry shader
out fData {
    int axis;
} frag;

// Fragment shader
in fData {
   int axis;
}

Am I missing something? Is there a way to preserve 'flat'?

I am using SPIRV-Cross through krafix, macos 10.11.6 / win 10, Intel Iris GPU.

Incorrect texelFetch emitted for sampler2DMS

I compiled this shader with glslang:
#version 420 uniform sampler2DMS colorBuffer; layout(location = 0) out vec4 outColor; void main(void) { outColor = texelFetch(colorBuffer, ivec2(gl_FragCoord.xy), 0); }

This compiles successfully but when compiled back to GLSL with SPIRV-cross it produces this:
outColor = texelFetch(colorBuffer, ivec2(gl_FragCoord.xy));

which will fail with "'texelFetch' : no matching overloaded function found".

[CPP] Invalid syntax is generated for array variable.

When compiling generated cpp code from this shader #17

Two compilation error happens.

ao.cc:147:43: error: 'basis' declared as array of references of type 'vec3 &' (aka 'tvec3<float, highp> &')
        inline void orthoBasis(vec3& basis[3], const vec3& n)
                                          ^
ao.cc:224:18: error: array initializer must be an initializer list
            vec3 basis[3] = param;
                 ^

In the former case, removing '&' will solve the issue.
In the latter case, we may need to emit c++ code like this:

vec3 basis[3];
basis[0] = param[0];
basis[1] = param[1];
basis[2] = param[2];

Incorrect GLSL generated from spirv-remap -minimized shader

This shader:

#version 420
uniform sampler2D tex1;
out vec4 t;
void main() {
    float f = texture(tex1, vec2(0.0f)).x;
    t = vec4(f * f);
}

works OK when GLSL is created directly from glslang-outputted spv file but breaks after spirv-remap has been run. Produced output looks like this:

    vec4 _17 = texture(tex1, vec2(0.0));
    float f = .x;
    t = vec4((_17f * _17f));

The SPIR-V code itself seems ok, the relevant part before remap:

         %21 = OpCompositeExtract %6 %18 0
               OpStore %8 %21
         %24 = OpLoad %6 %8
         %25 = OpLoad %6 %8
         %26 = OpFMul %6 %24 %25

and after:

         %20 = OpCompositeExtract %6 %17 0
         %23 = OpFMul %6 %20 %20

Looks like something is wrong in the handling of OpCompositeExtract when it's not followed by OpStore. Or is this a bug in the remapper?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.