Merge commit '2da12dca5803c3dcde920a1cff838fd98aecb36f'

This commit is contained in:
twinaphex 2018-07-04 22:51:43 +02:00
commit 155f797ccb
94 changed files with 4759 additions and 361 deletions

View File

@ -93,6 +93,10 @@ spirv_cross_add_library(spirv-cross-cpp spirv_cross_cpp STATIC
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_cpp.cpp)
spirv_cross_add_library(spirv-cross-reflect spirv_cross_reflect STATIC
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_reflect.cpp)
spirv_cross_add_library(spirv-cross-msl spirv_cross_msl STATIC
${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.hpp
${CMAKE_CURRENT_SOURCE_DIR}/spirv_msl.cpp)
@ -110,7 +114,7 @@ target_compile_options(spirv-cross PRIVATE ${spirv-compiler-options})
target_compile_definitions(spirv-cross PRIVATE ${spirv-compiler-defines})
install(TARGETS spirv-cross RUNTIME DESTINATION bin)
target_link_libraries(spirv-cross spirv-cross-glsl spirv-cross-hlsl spirv-cross-cpp spirv-cross-msl spirv-cross-util spirv-cross-core)
target_link_libraries(spirv-cross spirv-cross-glsl spirv-cross-hlsl spirv-cross-cpp spirv-cross-reflect spirv-cross-msl spirv-cross-util spirv-cross-core)
target_link_libraries(spirv-cross-util spirv-cross-core)
target_link_libraries(spirv-cross-glsl spirv-cross-core)
target_link_libraries(spirv-cross-msl spirv-cross-glsl)

View File

@ -11,6 +11,7 @@ SPIRV-Cross is a tool designed for parsing and converting SPIR-V to other shader
- 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 debuggable C++ [EXPERIMENTAL]
- Convert SPIR-V to a JSON reflection format [EXPERIMENTAL]
- 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.

View File

@ -19,6 +19,7 @@
#include "spirv_glsl.hpp"
#include "spirv_hlsl.hpp"
#include "spirv_msl.hpp"
#include "spirv_reflect.hpp"
#include <algorithm>
#include <cstdio>
#include <cstring>
@ -149,6 +150,22 @@ struct CLIParser
return val;
}
// Return a string only if it's not prefixed with `--`, otherwise return the default value
const char *next_value_string(const char *default_value)
{
if (!argc)
{
return default_value;
}
if (0 == strncmp("--", *argv, 2))
{
return default_value;
}
return next_string();
}
const char *next_string()
{
if (!argc)
@ -461,6 +478,7 @@ struct CLIArguments
bool fixup = false;
bool yflip = false;
bool sso = false;
bool support_nonzero_baseinstance = true;
vector<PLSArg> pls_in;
vector<PLSArg> pls_out;
vector<Remap> remaps;
@ -481,6 +499,7 @@ struct CLIArguments
uint32_t iterations = 1;
bool cpp = false;
string reflect;
bool msl = false;
bool hlsl = false;
bool hlsl_compat = false;
@ -512,6 +531,7 @@ static void print_help()
"\t[--msl]\n"
"\t[--msl-version <MMmmpp>]\n"
"\t[--hlsl]\n"
"\t[--reflect]\n"
"\t[--shader-model]\n"
"\t[--hlsl-enable-compat]\n"
"\t[--separate-shader-objects]\n"
@ -528,7 +548,8 @@ static void print_help()
"\t[--rename-interface-variable <in|out> <location> <new_variable_name>]\n"
"\t[--set-hlsl-vertex-input-semantic <location> <semantic>]\n"
"\t[--rename-entry-point <old> <new> <stage>]\n"
"\t[--combined-samplers-inherit-bindings]"
"\t[--combined-samplers-inherit-bindings]\n"
"\t[--no-support-nonzero-baseinstance]\n"
"\n");
}
@ -663,6 +684,7 @@ static int main_inner(int argc, char *argv[])
cbs.add("--flip-vert-y", [&args](CLIParser &) { args.yflip = true; });
cbs.add("--iterations", [&args](CLIParser &parser) { args.iterations = parser.next_uint(); });
cbs.add("--cpp", [&args](CLIParser &) { args.cpp = true; });
cbs.add("--reflect", [&args](CLIParser &parser) { args.reflect = parser.next_value_string("json"); });
cbs.add("--cpp-interface-name", [&args](CLIParser &parser) { args.cpp_interface_name = parser.next_string(); });
cbs.add("--metal", [&args](CLIParser &) { args.msl = true; }); // Legacy compatibility
cbs.add("--msl", [&args](CLIParser &) { args.msl = true; });
@ -737,6 +759,8 @@ static int main_inner(int argc, char *argv[])
cbs.add("--combined-samplers-inherit-bindings",
[&args](CLIParser &) { args.combined_samplers_inherit_bindings = true; });
cbs.add("--no-support-nonzero-baseinstance", [&](CLIParser &) { args.support_nonzero_baseinstance = false; });
cbs.default_handler = [&args](const char *value) { args.input = value; };
cbs.error_handler = [] { print_help(); };
@ -757,8 +781,20 @@ static int main_inner(int argc, char *argv[])
return EXIT_FAILURE;
}
unique_ptr<CompilerGLSL> compiler;
// Special case reflection because it has little to do with the path followed by code-outputting compilers
if (!args.reflect.empty())
{
CompilerReflection compiler(read_spirv_file(args.input));
compiler.set_format(args.reflect);
auto json = compiler.compile();
if (args.output)
write_string_to_file(args.output, json.c_str());
else
printf("%s", json.c_str());
return EXIT_SUCCESS;
}
unique_ptr<CompilerGLSL> compiler;
bool combined_image_samplers = false;
bool build_dummy_sampler = false;
@ -895,6 +931,7 @@ static int main_inner(int argc, char *argv[])
opts.vulkan_semantics = args.vulkan_semantics;
opts.vertex.fixup_clipspace = args.fixup;
opts.vertex.flip_vert_y = args.yflip;
opts.vertex.support_nonzero_base_instance = args.support_nonzero_baseinstance;
compiler->set_common_options(opts);
// Set HLSL specific options.

View File

@ -127,6 +127,7 @@
<ClCompile Include="..\spirv_cpp.cpp" />
<ClCompile Include="..\spirv_cross.cpp" />
<ClCompile Include="..\spirv_glsl.cpp" />
<ClCompile Include="..\spirv_reflect.cpp" />
<ClCompile Include="..\spirv_hlsl.cpp" />
<ClCompile Include="..\spirv_msl.cpp" />
<ClCompile Include="..\spirv_cfg.cpp" />
@ -138,6 +139,7 @@
<ClInclude Include="..\spirv_cpp.hpp" />
<ClInclude Include="..\spirv_cross.hpp" />
<ClInclude Include="..\spirv_glsl.hpp" />
<ClInclude Include="..\spirv_reflect.hpp" />
<ClInclude Include="..\spirv.hpp" />
<ClInclude Include="..\spirv_hlsl.hpp" />
<ClInclude Include="..\spirv_msl.hpp" />

View File

@ -24,6 +24,9 @@
<ClCompile Include="..\spirv_glsl.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\spirv_reflect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\spirv_cpp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -50,6 +53,9 @@
<ClInclude Include="..\spirv_glsl.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\spirv_reflect.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\spirv.hpp">
<Filter>Header Files</Filter>
</ClInclude>

View File

@ -0,0 +1,32 @@
RWByteAddressBuffer bar : register(u0);
RWByteAddressBuffer foo : register(u1);
void comp_main()
{
[unroll]
for (int _135 = 0; _135 < 16; )
{
bar.Store4(_135 * 16 + 0, asuint(asfloat(foo.Load4(_135 * 16 + 0))));
_135++;
continue;
}
[loop]
for (int _136 = 0; _136 < 16; )
{
bar.Store4((15 - _136) * 16 + 0, asuint(asfloat(foo.Load4(_136 * 16 + 0))));
_136++;
continue;
}
[branch]
if (asfloat(bar.Load(160)) > 10.0f)
{
foo.Store4(320, asuint(5.0f.xxxx));
}
foo.Store4(320, asuint(20.0f.xxxx));
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,31 @@
Texture2D<float4> uShadow : register(t0);
SamplerComparisonState _uShadow_sampler : register(s0);
Texture2D<float4> uTexture : register(t1);
SamplerComparisonState uSampler : register(s2);
static float3 vUV;
static float FragColor;
struct SPIRV_Cross_Input
{
float3 vUV : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = uShadow.SampleCmp(_uShadow_sampler, vUV.xy, vUV.z) + uTexture.SampleCmp(uSampler, vUV.xy, vUV.z);
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,28 @@
static float4 gl_Position;
static int gl_VertexIndex;
static int gl_InstanceIndex;
struct SPIRV_Cross_Input
{
uint gl_VertexIndex : SV_VertexID;
uint gl_InstanceIndex : SV_InstanceID;
};
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
};
void vert_main()
{
gl_Position = float(uint(gl_VertexIndex) + uint(gl_InstanceIndex)).xxxx;
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_VertexIndex = int(stage_input.gl_VertexIndex);
gl_InstanceIndex = int(stage_input.gl_InstanceIndex);
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
return stage_output;
}

View File

@ -0,0 +1,16 @@
globallycoherent RWByteAddressBuffer _29 : register(u3);
ByteAddressBuffer _33 : register(t2);
RWTexture2D<float> uImageIn : register(u0);
globallycoherent RWTexture2D<float> uImageOut : register(u1);
void comp_main()
{
uImageOut[int2(9, 7)] = uImageIn[int2(9, 7)].x;
_29.Store(0, asuint(asfloat(_33.Load(0))));
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,23 @@
static const uint s = 10u;
static const bool _13 = (s > 20u);
static const uint _16 = _13 ? 30u : 50u;
static float FragColor;
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float(_16);
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float3 vUV [[user(locn0)]];
};
fragment main0_out main0(main0_in in [[stage_in]], depth2d<float> uShadow [[texture(0)]], depth2d<float> uTexture [[texture(1)]], sampler uShadowSmplr [[sampler(0)]], sampler uSampler [[sampler(2)]])
{
main0_out out = {};
out.FragColor = uShadow.sample_compare(uShadowSmplr, in.vUV.xy, in.vUV.z) + uTexture.sample_compare(uSampler, in.vUV.xy, in.vUV.z);
return out;
}

View File

@ -0,0 +1,17 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
vertex main0_out main0(uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]])
{
main0_out out = {};
out.gl_Position = float4(float(gl_VertexIndex + gl_InstanceIndex));
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
constant uint s_tmp [[function_constant(0)]];
constant uint s = is_function_constant_defined(s_tmp) ? s_tmp : 10u;
constant bool _13 = (s > 20u);
constant uint _16 = _13 ? 30u : 50u;
struct main0_out
{
float FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float(_16);
return out;
}

View File

@ -0,0 +1,19 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize [[point_size]];
};
vertex main0_out main0()
{
main0_out out = {};
out.gl_PointSize = 1.0;
out.gl_Position = float4(out.gl_PointSize);
return out;
}

View File

@ -1,3 +1,5 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
@ -8,10 +10,16 @@ struct main0_out
float4 gl_Position [[position]];
};
// Returns 2D texture coords corresponding to 1D texel buffer coords
uint2 spvTexelBufferCoord(uint tc)
{
return uint2(tc % 4096, tc / 4096);
}
vertex main0_out main0(texture2d<float> uSamp [[texture(4)]], texture2d<float> uSampo [[texture(5)]])
{
main0_out out = {};
out.gl_Position = uSamp.read(uint2(10, 0)) + uSampo.read(uint2(100, 0));
out.gl_Position = uSamp.read(spvTexelBufferCoord(10)) + uSampo.read(spvTexelBufferCoord(100));
return out;
}

View File

@ -0,0 +1,33 @@
#version 310 es
precision mediump float;
precision highp int;
layout(location = 0) flat in mediump int vIndex;
layout(location = 0) out float FragColor;
void main()
{
highp float _19;
switch (vIndex)
{
case 0:
case 2:
{
_19 = 1.0;
break;
}
case 1:
default:
{
_19 = 3.0;
break;
}
case 8:
{
_19 = 8.0;
break;
}
}
FragColor = _19;
}

View File

@ -0,0 +1,13 @@
#version 450
layout(binding = 0) uniform sampler2DShadow uShadow;
uniform sampler2DShadow SPIRV_Cross_CombineduTextureuSampler;
layout(location = 0) in vec3 vUV;
layout(location = 0) out float FragColor;
void main()
{
FragColor = texture(uShadow, vec3(vUV.xy, vUV.z)) + texture(SPIRV_Cross_CombineduTextureuSampler, vec3(vUV.xy, vUV.z));
}

View File

@ -0,0 +1,14 @@
#version 450
layout(set = 0, binding = 0) uniform sampler2DShadow uShadow;
layout(set = 0, binding = 1) uniform texture2D uTexture;
layout(set = 0, binding = 2) uniform samplerShadow uSampler;
layout(location = 0) in vec3 vUV;
layout(location = 0) out float FragColor;
void main()
{
FragColor = texture(uShadow, vec3(vUV.xy, vUV.z)) + texture(sampler2DShadow(uTexture, uSampler), vec3(vUV.xy, vUV.z));
}

View File

@ -0,0 +1,41 @@
#version 450
layout(triangles) in;
layout(max_vertices = 3, triangle_strip) out;
struct VertexOutput
{
vec4 pos;
};
struct GeometryOutput
{
vec4 pos;
uint layer;
};
void _main(VertexOutput _input[3], GeometryOutput stream)
{
GeometryOutput _output;
_output.layer = 1u;
for (int v = 0; v < 3; v++)
{
_output.pos = _input[v].pos;
gl_Position = _output.pos;
gl_Layer = int(_output.layer);
EmitVertex();
}
EndPrimitive();
}
void main()
{
VertexOutput _input[3];
_input[0].pos = gl_in[0].gl_Position;
_input[1].pos = gl_in[1].gl_Position;
_input[2].pos = gl_in[2].gl_Position;
VertexOutput param[3] = _input;
GeometryOutput param_1;
_main(param, param_1);
GeometryOutput stream = param_1;
}

View File

@ -0,0 +1,9 @@
#version 450
uniform int SPIRV_Cross_BaseInstance;
void main()
{
gl_Position = vec4(float(uint(gl_VertexID) + uint((gl_InstanceID + SPIRV_Cross_BaseInstance))));
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
void main()
{
FragColor = float((10u > 20u) ? 30u : 50u);
}

View File

@ -0,0 +1,13 @@
#version 450
layout(constant_id = 0) const uint s = 10u;
const bool _13 = (s > 20u);
const uint _16 = _13 ? 30u : 50u;
layout(location = 0) out float FragColor;
void main()
{
FragColor = float(_16);
}

View File

@ -0,0 +1,41 @@
RWByteAddressBuffer bar : register(u0);
RWByteAddressBuffer foo : register(u1);
void _main()
{
[unroll]
for (int i = 0; i < 16; i++)
{
bar.Store4(i * 16 + 0, asuint(asfloat(foo.Load4(i * 16 + 0))));
}
[loop]
for (int i_1 = 0; i_1 < 16; i_1++)
{
bar.Store4((15 - i_1) * 16 + 0, asuint(asfloat(foo.Load4(i_1 * 16 + 0))));
}
float v = asfloat(bar.Load(160));
float w = asfloat(foo.Load(160));
[branch]
if (v > 10.0f)
{
foo.Store4(320, asuint(5.0f.xxxx));
}
float value = 20.0f;
[flatten]
if (w > 40.0f)
{
value = 20.0f;
}
foo.Store4(320, asuint(value.xxxx));
}
void comp_main()
{
_main();
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,41 @@
Texture2D<float4> uShadow : register(t0);
SamplerComparisonState _uShadow_sampler : register(s0);
Texture2D<float4> uTexture : register(t1);
SamplerComparisonState uSampler : register(s2);
static float3 vUV;
static float FragColor;
struct SPIRV_Cross_Input
{
float3 vUV : TEXCOORD0;
};
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
float sample_combined()
{
return uShadow.SampleCmp(_uShadow_sampler, vUV.xy, vUV.z);
}
float sample_separate()
{
return uTexture.SampleCmp(uSampler, vUV.xy, vUV.z);
}
void frag_main()
{
FragColor = sample_combined() + sample_separate();
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
vUV = stage_input.vUV;
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -0,0 +1,37 @@
static float4 gl_Position;
static int gl_VertexIndex;
static int gl_InstanceIndex;
struct SPIRV_Cross_Input
{
uint gl_VertexIndex : SV_VertexID;
uint gl_InstanceIndex : SV_InstanceID;
};
struct SPIRV_Cross_Output
{
float4 gl_Position : SV_Position;
};
float4 _main(uint vid, uint iid)
{
return float(vid + iid).xxxx;
}
void vert_main()
{
uint vid = uint(gl_VertexIndex);
uint iid = uint(gl_InstanceIndex);
uint param = vid;
uint param_1 = iid;
gl_Position = _main(param, param_1);
}
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_VertexIndex = int(stage_input.gl_VertexIndex);
gl_InstanceIndex = int(stage_input.gl_InstanceIndex);
vert_main();
SPIRV_Cross_Output stage_output;
stage_output.gl_Position = gl_Position;
return stage_output;
}

View File

@ -0,0 +1,18 @@
globallycoherent RWByteAddressBuffer _29 : register(u3);
ByteAddressBuffer _33 : register(t2);
RWTexture2D<float> uImageIn : register(u0);
globallycoherent RWTexture2D<float> uImageOut : register(u1);
void comp_main()
{
int2 coord = int2(9, 7);
float4 indata = uImageIn[coord].xxxx;
uImageOut[coord] = indata.x;
_29.Store(0, asuint(asfloat(_33.Load(0))));
}
[numthreads(1, 1, 1)]
void main()
{
comp_main();
}

View File

@ -0,0 +1,23 @@
static const uint s = 10u;
static const bool _13 = (s > 20u);
static const uint _16 = _13 ? 30u : 50u;
static float FragColor;
struct SPIRV_Cross_Output
{
float FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float(_16);
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

View File

@ -36,6 +36,12 @@ struct main0_out
float4 gl_Position [[position]];
};
// Returns 2D texture coords corresponding to 1D texel buffer coords
uint2 spvTexelBufferCoord(uint tc)
{
return uint2(tc % 4096, tc / 4096);
}
attr_desc fetch_desc(thread const int& location, constant VertexBuffer& v_227)
{
int attribute_flags = v_227.input_attributes[location].w;
@ -76,10 +82,10 @@ float4 fetch_attr(thread const attr_desc& desc, thread const int& vertex_id, thr
{
int _131 = first_byte;
first_byte = _131 + 1;
tmp.x = input_stream.read(uint2(_131, 0)).x;
tmp.x = input_stream.read(spvTexelBufferCoord(_131)).x;
int _138 = first_byte;
first_byte = _138 + 1;
tmp.y = input_stream.read(uint2(_138, 0)).x;
tmp.y = input_stream.read(spvTexelBufferCoord(_138)).x;
uint4 param = tmp;
int param_1 = desc.swap_bytes;
result[n] = float(get_bits(param, param_1));
@ -89,16 +95,16 @@ float4 fetch_attr(thread const attr_desc& desc, thread const int& vertex_id, thr
{
int _156 = first_byte;
first_byte = _156 + 1;
tmp.x = input_stream.read(uint2(_156, 0)).x;
tmp.x = input_stream.read(spvTexelBufferCoord(_156)).x;
int _163 = first_byte;
first_byte = _163 + 1;
tmp.y = input_stream.read(uint2(_163, 0)).x;
tmp.y = input_stream.read(spvTexelBufferCoord(_163)).x;
int _170 = first_byte;
first_byte = _170 + 1;
tmp.z = input_stream.read(uint2(_170, 0)).x;
tmp.z = input_stream.read(spvTexelBufferCoord(_170)).x;
int _177 = first_byte;
first_byte = _177 + 1;
tmp.w = input_stream.read(uint2(_177, 0)).x;
tmp.w = input_stream.read(spvTexelBufferCoord(_177)).x;
uint4 param_2 = tmp;
int param_3 = desc.swap_bytes;
result[n] = as_type<float>(get_bits(param_2, param_3));
@ -108,7 +114,7 @@ float4 fetch_attr(thread const attr_desc& desc, thread const int& vertex_id, thr
{
int _195 = first_byte;
first_byte = _195 + 1;
result[n] = float(input_stream.read(uint2(_195, 0)).x);
result[n] = float(input_stream.read(spvTexelBufferCoord(_195)).x);
reverse_order = desc.swap_bytes != 0;
break;
}

View File

@ -0,0 +1,34 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float FragColor [[color(0)]];
};
struct main0_in
{
float3 vUV [[user(locn0)]];
};
float sample_combined(thread float3& vUV, thread depth2d<float> uShadow, thread const sampler uShadowSmplr)
{
return uShadow.sample_compare(uShadowSmplr, vUV.xy, vUV.z);
}
float sample_separate(thread float3& vUV, thread depth2d<float> uTexture, thread sampler uSampler)
{
return uTexture.sample_compare(uSampler, vUV.xy, vUV.z);
}
fragment main0_out main0(main0_in in [[stage_in]], depth2d<float> uShadow [[texture(0)]], depth2d<float> uTexture [[texture(1)]], sampler uShadowSmplr [[sampler(0)]], sampler uSampler [[sampler(2)]])
{
main0_out out = {};
out.FragColor = sample_combined(in.vUV, uShadow, uShadowSmplr) + sample_separate(in.vUV, uTexture, uSampler);
return out;
}

View File

@ -0,0 +1,28 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
float4 _main(thread const uint& vid, thread const uint& iid)
{
return float4(float(vid + iid));
}
vertex main0_out main0(uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]])
{
main0_out out = {};
uint vid = gl_VertexIndex;
uint iid = gl_InstanceIndex;
uint param = vid;
uint param_1 = iid;
out.gl_Position = _main(param, param_1);
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
constant uint s_tmp [[function_constant(0)]];
constant uint s = is_function_constant_defined(s_tmp) ? s_tmp : 10u;
constant bool _13 = (s > 20u);
constant uint _16 = _13 ? 30u : 50u;
struct main0_out
{
float FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float(_16);
return out;
}

View File

@ -0,0 +1,26 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize [[point_size]];
};
void write_outblock(thread float4& gl_Position, thread float& gl_PointSize)
{
gl_PointSize = 1.0;
gl_Position = float4(gl_PointSize);
}
vertex main0_out main0()
{
main0_out out = {};
write_outblock(out.gl_Position, out.gl_PointSize);
return out;
}

View File

@ -1,3 +1,5 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
@ -8,10 +10,16 @@ struct main0_out
float4 gl_Position [[position]];
};
// Returns 2D texture coords corresponding to 1D texel buffer coords
uint2 spvTexelBufferCoord(uint tc)
{
return uint2(tc % 4096, tc / 4096);
}
vertex main0_out main0(texture2d<float> uSamp [[texture(4)]], texture2d<float> uSampo [[texture(5)]])
{
main0_out out = {};
out.gl_Position = uSamp.read(uint2(10, 0)) + uSampo.read(uint2(100, 0));
out.gl_Position = uSamp.read(spvTexelBufferCoord(10)) + uSampo.read(spvTexelBufferCoord(100));
return out;
}

View File

@ -0,0 +1,49 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "vert"
},
{
"name" : "main2",
"mode" : "vert"
},
{
"name" : "main",
"mode" : "frag"
},
{
"name" : "main2",
"mode" : "frag"
}
],
"types" : {
"_8" : {
"name" : "_8",
"members" : [
{
"name" : "_m0",
"type" : "vec4"
},
{
"name" : "_m1",
"type" : "float"
},
{
"name" : "_m2",
"type" : "float",
"array" : [
1
]
},
{
"name" : "_m3",
"type" : "float",
"array" : [
1
]
}
]
}
}
}

View File

@ -0,0 +1,64 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "comp"
}
],
"types" : {
"_19" : {
"name" : "Foo",
"members" : [
{
"name" : "m",
"type" : "mat4",
"offset" : 0
}
]
},
"_21" : {
"name" : "SSBO2",
"members" : [
{
"name" : "out_data",
"type" : "_19",
"array" : [
0
],
"offset" : 0
}
]
},
"_28" : {
"name" : "SSBO",
"members" : [
{
"name" : "in_data",
"type" : "_19",
"array" : [
0
],
"offset" : 0
}
]
}
},
"ssbos" : [
{
"type" : "_21",
"name" : "SSBO2",
"writeonly" : true,
"block_size" : 0,
"set" : 0,
"binding" : 1
},
{
"type" : "_28",
"name" : "SSBO",
"readonly" : true,
"block_size" : 0,
"set" : 0,
"binding" : 0
}
]
}

View File

@ -0,0 +1,474 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "comp"
}
],
"types" : {
"_11" : {
"name" : "S0",
"members" : [
{
"name" : "a",
"type" : "vec2",
"array" : [
1
],
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 8
}
]
},
"_14" : {
"name" : "S1",
"members" : [
{
"name" : "a",
"type" : "vec3",
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 12
}
]
},
"_17" : {
"name" : "S2",
"members" : [
{
"name" : "a",
"type" : "vec3",
"array" : [
1
],
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 16
}
]
},
"_19" : {
"name" : "S3",
"members" : [
{
"name" : "a",
"type" : "vec2",
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 8
}
]
},
"_20" : {
"name" : "S4",
"members" : [
{
"name" : "c",
"type" : "vec2",
"offset" : 0
}
]
},
"_23" : {
"name" : "Content",
"members" : [
{
"name" : "m0s",
"type" : "_11",
"array" : [
1
],
"offset" : 0
},
{
"name" : "m1s",
"type" : "_14",
"array" : [
1
],
"offset" : 16
},
{
"name" : "m2s",
"type" : "_17",
"array" : [
1
],
"offset" : 32
},
{
"name" : "m0",
"type" : "_11",
"offset" : 64
},
{
"name" : "m1",
"type" : "_14",
"offset" : 80
},
{
"name" : "m2",
"type" : "_17",
"offset" : 96
},
{
"name" : "m3",
"type" : "_19",
"offset" : 128
},
{
"name" : "m4",
"type" : "float",
"offset" : 144
},
{
"name" : "m3s",
"type" : "_20",
"array" : [
8
],
"offset" : 152
}
]
},
"_36" : {
"name" : "SSBO1",
"members" : [
{
"name" : "content",
"type" : "_23",
"offset" : 0
},
{
"name" : "content1",
"type" : "_23",
"array" : [
2
],
"offset" : 224
},
{
"name" : "content2",
"type" : "_23",
"offset" : 672
},
{
"name" : "m0",
"type" : "mat2",
"offset" : 896
},
{
"name" : "m1",
"type" : "mat2",
"offset" : 912
},
{
"name" : "m2",
"type" : "mat2x3",
"array" : [
4
],
"offset" : 928
},
{
"name" : "m3",
"type" : "mat3x2",
"offset" : 1056
},
{
"name" : "m4",
"type" : "mat2",
"row_major" : true,
"offset" : 1080
},
{
"name" : "m5",
"type" : "mat2",
"row_major" : true,
"array" : [
9
],
"offset" : 1096
},
{
"name" : "m6",
"type" : "mat2x3",
"row_major" : true,
"array" : [
2,
4
],
"offset" : 1240
},
{
"name" : "m7",
"type" : "mat3x2",
"row_major" : true,
"offset" : 1440
},
{
"name" : "array",
"type" : "float",
"array" : [
0
],
"offset" : 1472
}
]
},
"_42" : {
"name" : "S0",
"members" : [
{
"name" : "a",
"type" : "vec2",
"array" : [
1
],
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 16
}
]
},
"_44" : {
"name" : "S1",
"members" : [
{
"name" : "a",
"type" : "vec3",
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 12
}
]
},
"_47" : {
"name" : "S2",
"members" : [
{
"name" : "a",
"type" : "vec3",
"array" : [
1
],
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 16
}
]
},
"_49" : {
"name" : "S3",
"members" : [
{
"name" : "a",
"type" : "vec2",
"offset" : 0
},
{
"name" : "b",
"type" : "float",
"offset" : 8
}
]
},
"_50" : {
"name" : "S4",
"members" : [
{
"name" : "c",
"type" : "vec2",
"offset" : 0
}
]
},
"_52" : {
"name" : "Content",
"members" : [
{
"name" : "m0s",
"type" : "_42",
"array" : [
1
],
"offset" : 0
},
{
"name" : "m1s",
"type" : "_44",
"array" : [
1
],
"offset" : 32
},
{
"name" : "m2s",
"type" : "_47",
"array" : [
1
],
"offset" : 48
},
{
"name" : "m0",
"type" : "_42",
"offset" : 80
},
{
"name" : "m1",
"type" : "_44",
"offset" : 112
},
{
"name" : "m2",
"type" : "_47",
"offset" : 128
},
{
"name" : "m3",
"type" : "_49",
"offset" : 160
},
{
"name" : "m4",
"type" : "float",
"offset" : 176
},
{
"name" : "m3s",
"type" : "_50",
"array" : [
8
],
"offset" : 192
}
]
},
"_59" : {
"name" : "SSBO0",
"members" : [
{
"name" : "content",
"type" : "_52",
"offset" : 0
},
{
"name" : "content1",
"type" : "_52",
"array" : [
2
],
"offset" : 320
},
{
"name" : "content2",
"type" : "_52",
"offset" : 960
},
{
"name" : "m0",
"type" : "mat2",
"offset" : 1280
},
{
"name" : "m1",
"type" : "mat2",
"offset" : 1312
},
{
"name" : "m2",
"type" : "mat2x3",
"array" : [
4
],
"offset" : 1344
},
{
"name" : "m3",
"type" : "mat3x2",
"offset" : 1472
},
{
"name" : "m4",
"type" : "mat2",
"row_major" : true,
"offset" : 1520
},
{
"name" : "m5",
"type" : "mat2",
"row_major" : true,
"array" : [
9
],
"offset" : 1552
},
{
"name" : "m6",
"type" : "mat2x3",
"row_major" : true,
"array" : [
2,
4
],
"offset" : 1840
},
{
"name" : "m7",
"type" : "mat3x2",
"row_major" : true,
"offset" : 2224
},
{
"name" : "array",
"type" : "float",
"array" : [
0
],
"offset" : 2256
}
]
}
},
"ssbos" : [
{
"type" : "_36",
"name" : "SSBO1",
"restrict" : true,
"block_size" : 1472,
"set" : 0,
"binding" : 1
},
{
"type" : "_59",
"name" : "SSBO0",
"restrict" : true,
"block_size" : 2256,
"set" : 0,
"binding" : 0
}
]
}

View File

@ -0,0 +1,37 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"outputs" : [
{
"type" : "float",
"name" : "FragColor",
"location" : 0
}
],
"separate_images" : [
{
"type" : "texture2D",
"name" : "uDepth",
"set" : 0,
"binding" : 2
}
],
"separate_samplers" : [
{
"type" : "sampler",
"name" : "uSampler",
"set" : 0,
"binding" : 0
},
{
"type" : "sampler",
"name" : "uSampler1",
"set" : 0,
"binding" : 1
}
]
}

View File

@ -0,0 +1,50 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"inputs" : [
{
"type" : "vec2",
"name" : "vTex",
"location" : 0
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
],
"separate_images" : [
{
"type" : "texture2D",
"name" : "uTexture0",
"set" : 0,
"binding" : 2
},
{
"type" : "texture2D",
"name" : "uTexture1",
"set" : 0,
"binding" : 3
}
],
"separate_samplers" : [
{
"type" : "sampler",
"name" : "uSampler0",
"set" : 0,
"binding" : 0
},
{
"type" : "sampler",
"name" : "uSampler1",
"set" : 0,
"binding" : 1
}
]
}

View File

@ -0,0 +1,47 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "_entryPointOutput",
"location" : 0
}
],
"textures" : [
{
"type" : "sampler2D",
"name" : "ROIm",
"set" : 0,
"binding" : 1
}
],
"separate_images" : [
{
"type" : "samplerBuffer",
"name" : "ROBuf",
"set" : 0,
"binding" : 0
}
],
"images" : [
{
"type" : "image2D",
"name" : "RWIm",
"set" : 0,
"binding" : 1,
"format" : "rgba32f"
},
{
"type" : "imageBuffer",
"name" : "RWBuf",
"set" : 0,
"binding" : 0,
"format" : "rgba32f"
}
]
}

View File

@ -0,0 +1,31 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"subpass_inputs" : [
{
"type" : "subpassInputMS",
"name" : "uSubpass0",
"set" : 0,
"binding" : 0,
"input_attachment_index" : 0
},
{
"type" : "subpassInputMS",
"name" : "uSubpass1",
"set" : 0,
"binding" : 1,
"input_attachment_index" : 1
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
]
}

View File

@ -0,0 +1,31 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"subpass_inputs" : [
{
"type" : "subpassInput",
"name" : "uSubpass0",
"set" : 0,
"binding" : 0,
"input_attachment_index" : 0
},
{
"type" : "subpassInput",
"name" : "uSubpass1",
"set" : 0,
"binding" : 1,
"input_attachment_index" : 1
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
]
}

View File

@ -0,0 +1,46 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"types" : {
"_13" : {
"name" : "PushConstants",
"members" : [
{
"name" : "value0",
"type" : "vec4",
"offset" : 0
},
{
"name" : "value1",
"type" : "vec4",
"offset" : 16
}
]
}
},
"inputs" : [
{
"type" : "vec4",
"name" : "vColor",
"location" : 0
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
],
"push_constants" : [
{
"type" : "_13",
"name" : "push",
"push_constant" : true
}
]
}

View File

@ -0,0 +1,73 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"inputs" : [
{
"type" : "vec2",
"name" : "vTex",
"location" : 0
},
{
"type" : "vec3",
"name" : "vTex3",
"location" : 1
}
],
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
],
"separate_images" : [
{
"type" : "texture2D",
"name" : "uTexture",
"array" : [
4
],
"set" : 0,
"binding" : 1
},
{
"type" : "texture2DArray",
"name" : "uTextureArray",
"array" : [
4
],
"set" : 0,
"binding" : 4
},
{
"type" : "textureCube",
"name" : "uTextureCube",
"array" : [
4
],
"set" : 0,
"binding" : 3
},
{
"type" : "texture3D",
"name" : "uTexture3D",
"array" : [
4
],
"set" : 0,
"binding" : 2
}
],
"separate_samplers" : [
{
"type" : "sampler",
"name" : "uSampler",
"set" : 0,
"binding" : 0
}
]
}

View File

@ -0,0 +1,71 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "frag"
}
],
"types" : {
"_137" : {
"name" : "Foo",
"members" : [
{
"name" : "elems",
"type" : "float",
"array" : [
135
]
}
]
}
},
"outputs" : [
{
"type" : "vec4",
"name" : "FragColor",
"location" : 0
}
],
"specialization_constants" : [
{
"id" : 1,
"type" : "float",
"default_value" : 1.5
},
{
"id" : 2,
"type" : "float",
"default_value" : 2.5
},
{
"id" : 3,
"type" : "int",
"default_value" : 3
},
{
"id" : 4,
"type" : "int",
"default_value" : 4
},
{
"id" : 5,
"type" : "uint",
"default_value" : 5
},
{
"id" : 6,
"type" : "uint",
"default_value" : 6
},
{
"id" : 7,
"type" : "bool",
"default_value" : false
},
{
"id" : 8,
"type" : "bool",
"default_value" : true
}
]
}

View File

@ -0,0 +1,61 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "vert"
}
],
"types" : {
"_89" : {
"name" : "gl_PerVertex",
"members" : [
{
"name" : "gl_Position",
"type" : "vec4"
},
{
"name" : "gl_PointSize",
"type" : "float"
}
]
},
"_102" : {
"name" : "Block",
"members" : [
{
"name" : "var",
"type" : "mat2x3",
"row_major" : true,
"array" : [
4,
3
],
"offset" : 0
}
]
}
},
"inputs" : [
{
"type" : "vec4",
"name" : "a_position",
"location" : 0
}
],
"outputs" : [
{
"type" : "float",
"name" : "v_vtxResult",
"location" : 0
}
],
"ubos" : [
{
"type" : "_102",
"name" : "Block",
"block_size" : 576,
"set" : 0,
"binding" : 0
}
]
}

View File

@ -0,0 +1,40 @@
{
"entryPoints" : [
{
"name" : "main",
"mode" : "vert"
}
],
"types" : {
"_8" : {
"name" : "gl_PerVertex",
"members" : [
{
"name" : "gl_Position",
"type" : "vec4"
},
{
"name" : "gl_PointSize",
"type" : "float"
}
]
}
},
"textures" : [
{
"type" : "samplerBuffer",
"name" : "uSamp",
"set" : 0,
"binding" : 4
}
],
"images" : [
{
"type" : "imageBuffer",
"name" : "uSampo",
"set" : 0,
"binding" : 5,
"format" : "rgba32f"
}
]
}

View File

@ -0,0 +1,33 @@
#version 310 es
precision mediump float;
precision highp int;
layout(location = 0) flat in mediump int vIndex;
layout(location = 0) out float FragColor;
void main()
{
highp float _19;
switch (vIndex)
{
case 0:
case 2:
{
_19 = 1.0;
break;
}
case 1:
default:
{
_19 = 3.0;
break;
}
case 8:
{
_19 = 8.0;
break;
}
}
FragColor = _19;
}

View File

@ -0,0 +1,23 @@
#version 450
layout(binding = 0) uniform sampler2DShadow uShadow;
uniform sampler2DShadow SPIRV_Cross_CombineduTextureuSampler;
layout(location = 0) in vec3 vUV;
layout(location = 0) out float FragColor;
float sample_combined()
{
return texture(uShadow, vec3(vUV.xy, vUV.z));
}
float sample_separate()
{
return texture(SPIRV_Cross_CombineduTextureuSampler, vec3(vUV.xy, vUV.z));
}
void main()
{
FragColor = sample_combined() + sample_separate();
}

View File

@ -0,0 +1,24 @@
#version 450
layout(set = 0, binding = 0) uniform sampler2DShadow uShadow;
layout(set = 0, binding = 1) uniform texture2D uTexture;
layout(set = 0, binding = 2) uniform samplerShadow uSampler;
layout(location = 0) in vec3 vUV;
layout(location = 0) out float FragColor;
float sample_combined()
{
return texture(uShadow, vec3(vUV.xy, vUV.z));
}
float sample_separate()
{
return texture(sampler2DShadow(uTexture, uSampler), vec3(vUV.xy, vUV.z));
}
void main()
{
FragColor = sample_combined() + sample_separate();
}

View File

@ -0,0 +1,41 @@
#version 450
layout(triangles) in;
layout(max_vertices = 3, triangle_strip) out;
struct VertexOutput
{
vec4 pos;
};
struct GeometryOutput
{
vec4 pos;
uint layer;
};
void _main(VertexOutput _input[3], GeometryOutput stream)
{
GeometryOutput _output;
_output.layer = 1u;
for (int v = 0; v < 3; v++)
{
_output.pos = _input[v].pos;
gl_Position = _output.pos;
gl_Layer = int(_output.layer);
EmitVertex();
}
EndPrimitive();
}
void main()
{
VertexOutput _input[3];
_input[0].pos = gl_in[0].gl_Position;
_input[1].pos = gl_in[1].gl_Position;
_input[2].pos = gl_in[2].gl_Position;
VertexOutput param[3] = _input;
GeometryOutput param_1;
_main(param, param_1);
GeometryOutput stream = param_1;
}

View File

@ -0,0 +1,18 @@
#version 450
uniform int SPIRV_Cross_BaseInstance;
vec4 _main(uint vid, uint iid)
{
return vec4(float(vid + iid));
}
void main()
{
uint vid = uint(gl_VertexID);
uint iid = uint((gl_InstanceID + SPIRV_Cross_BaseInstance));
uint param = vid;
uint param_1 = iid;
gl_Position = _main(param, param_1);
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
void main()
{
FragColor = float((10u > 20u) ? 30u : 50u);
}

View File

@ -0,0 +1,13 @@
#version 450
layout(constant_id = 0) const uint s = 10u;
const bool _13 = (s > 20u);
const uint _16 = _13 ? 30u : 50u;
layout(location = 0) out float FragColor;
void main()
{
FragColor = float(_16);
}

View File

@ -0,0 +1,146 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 85
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %main "main"
OpExecutionMode %main LocalSize 1 1 1
OpSource HLSL 500
OpName %main "main"
OpName %_main_ "@main("
OpName %i "i"
OpName %bar "bar"
OpMemberName %bar 0 "@data"
OpName %bar_0 "bar"
OpName %foo "foo"
OpName %i_0 "i"
OpName %v "v"
OpName %w "w"
OpName %value "value"
OpDecorate %_runtimearr_v4float ArrayStride 16
OpMemberDecorate %bar 0 Offset 0
OpDecorate %bar BufferBlock
OpDecorate %bar_0 DescriptorSet 0
OpDecorate %bar_0 Binding 0
OpDecorate %foo DescriptorSet 0
OpDecorate %foo Binding 1
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_16 = OpConstant %int 16
%bool = OpTypeBool
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_runtimearr_v4float = OpTypeRuntimeArray %v4float
%bar = OpTypeStruct %_runtimearr_v4float
%_ptr_Uniform_bar = OpTypePointer Uniform %bar
%bar_0 = OpVariable %_ptr_Uniform_bar Uniform
%foo = OpVariable %_ptr_Uniform_bar Uniform
%_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
%int_1 = OpConstant %int 1
%int_15 = OpConstant %int 15
%_ptr_Function_float = OpTypePointer Function %float
%int_10 = OpConstant %int 10
%uint = OpTypeInt 32 0
%uint_0 = OpConstant %uint 0
%_ptr_Uniform_float = OpTypePointer Uniform %float
%float_10 = OpConstant %float 10
%int_20 = OpConstant %int 20
%float_5 = OpConstant %float 5
%72 = OpConstantComposite %v4float %float_5 %float_5 %float_5 %float_5
%float_20 = OpConstant %float 20
%float_40 = OpConstant %float 40
%main = OpFunction %void None %3
%5 = OpLabel
%84 = OpFunctionCall %void %_main_
OpReturn
OpFunctionEnd
%_main_ = OpFunction %void None %3
%7 = OpLabel
%i = OpVariable %_ptr_Function_int Function
%i_0 = OpVariable %_ptr_Function_int Function
%v = OpVariable %_ptr_Function_float Function
%w = OpVariable %_ptr_Function_float Function
%value = OpVariable %_ptr_Function_float Function
OpStore %i %int_0
OpBranch %12
%12 = OpLabel
OpLoopMerge %14 %15 Unroll
OpBranch %16
%16 = OpLabel
%17 = OpLoad %int %i
%20 = OpSLessThan %bool %17 %int_16
OpBranchConditional %20 %13 %14
%13 = OpLabel
%27 = OpLoad %int %i
%29 = OpLoad %int %i
%31 = OpAccessChain %_ptr_Uniform_v4float %foo %int_0 %29
%32 = OpLoad %v4float %31
%33 = OpAccessChain %_ptr_Uniform_v4float %bar_0 %int_0 %27
OpStore %33 %32
OpBranch %15
%15 = OpLabel
%34 = OpLoad %int %i
%36 = OpIAdd %int %34 %int_1
OpStore %i %36
OpBranch %12
%14 = OpLabel
OpStore %i_0 %int_0
OpBranch %38
%38 = OpLabel
OpLoopMerge %40 %41 DontUnroll
OpBranch %42
%42 = OpLabel
%43 = OpLoad %int %i_0
%44 = OpSLessThan %bool %43 %int_16
OpBranchConditional %44 %39 %40
%39 = OpLabel
%46 = OpLoad %int %i_0
%47 = OpISub %int %int_15 %46
%48 = OpLoad %int %i_0
%49 = OpAccessChain %_ptr_Uniform_v4float %foo %int_0 %48
%50 = OpLoad %v4float %49
%51 = OpAccessChain %_ptr_Uniform_v4float %bar_0 %int_0 %47
OpStore %51 %50
OpBranch %41
%41 = OpLabel
%52 = OpLoad %int %i_0
%53 = OpIAdd %int %52 %int_1
OpStore %i_0 %53
OpBranch %38
%40 = OpLabel
%60 = OpAccessChain %_ptr_Uniform_float %bar_0 %int_0 %int_10 %uint_0
%61 = OpLoad %float %60
OpStore %v %61
%63 = OpAccessChain %_ptr_Uniform_float %foo %int_0 %int_10 %uint_0
%64 = OpLoad %float %63
OpStore %w %64
%65 = OpLoad %float %v
%67 = OpFOrdGreaterThan %bool %65 %float_10
OpSelectionMerge %69 DontFlatten
OpBranchConditional %67 %68 %69
%68 = OpLabel
%73 = OpAccessChain %_ptr_Uniform_v4float %foo %int_0 %int_20
OpStore %73 %72
OpBranch %69
%69 = OpLabel
OpStore %value %float_20
%76 = OpLoad %float %w
%78 = OpFOrdGreaterThan %bool %76 %float_40
OpSelectionMerge %80 Flatten
OpBranchConditional %78 %79 %80
%79 = OpLabel
OpStore %value %float_20
OpBranch %80
%80 = OpLabel
%81 = OpLoad %float %value
%82 = OpCompositeConstruct %v4float %81 %81 %81 %81
%83 = OpAccessChain %_ptr_Uniform_v4float %foo %int_0 %int_20
OpStore %83 %82
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,71 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 44
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %vUV %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %sample_combined_ "sample_combined("
OpName %sample_separate_ "sample_separate("
OpName %uShadow "uShadow"
OpName %vUV "vUV"
OpName %uTexture "uTexture"
OpName %uSampler "uSampler"
OpName %FragColor "FragColor"
OpDecorate %uShadow DescriptorSet 0
OpDecorate %uShadow Binding 0
OpDecorate %vUV Location 0
OpDecorate %uTexture DescriptorSet 0
OpDecorate %uTexture Binding 1
OpDecorate %uSampler DescriptorSet 0
OpDecorate %uSampler Binding 2
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeFunction %float
%12 = OpTypeImage %float 2D 2 0 0 1 Unknown
%13 = OpTypeSampledImage %12
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
%uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant
%v3float = OpTypeVector %float 3
%_ptr_Input_v3float = OpTypePointer Input %v3float
%vUV = OpVariable %_ptr_Input_v3float Input
%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12
%uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant
%29 = OpTypeSampler
%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
%uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant
%_ptr_Output_float = OpTypePointer Output %float
%FragColor = OpVariable %_ptr_Output_float Output
%main = OpFunction %void None %3
%5 = OpLabel
%41 = OpFunctionCall %float %sample_combined_
%42 = OpFunctionCall %float %sample_separate_
%43 = OpFAdd %float %41 %42
OpStore %FragColor %43
OpReturn
OpFunctionEnd
%sample_combined_ = OpFunction %float None %7
%9 = OpLabel
%16 = OpLoad %13 %uShadow
%20 = OpLoad %v3float %vUV
%21 = OpCompositeExtract %float %20 2
%22 = OpImageSampleDrefImplicitLod %float %16 %20 %21
OpReturnValue %22
OpFunctionEnd
%sample_separate_ = OpFunction %float None %7
%11 = OpLabel
%28 = OpLoad %12 %uTexture
%32 = OpLoad %29 %uSampler
%33 = OpSampledImage %13 %28 %32
%34 = OpLoad %v3float %vUV
%35 = OpCompositeExtract %float %34 2
%36 = OpImageSampleDrefImplicitLod %float %33 %34 %35
OpReturnValue %36
OpFunctionEnd

View File

@ -0,0 +1,65 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 36
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %vid_1 %iid_1 %_entryPointOutput
OpSource HLSL 500
OpName %main "main"
OpName %_main_u1_u1_ "@main(u1;u1;"
OpName %vid "vid"
OpName %iid "iid"
OpName %vid_0 "vid"
OpName %vid_1 "vid"
OpName %iid_0 "iid"
OpName %iid_1 "iid"
OpName %_entryPointOutput "@entryPointOutput"
OpName %param "param"
OpName %param_0 "param"
OpDecorate %vid_1 BuiltIn VertexIndex
OpDecorate %iid_1 BuiltIn InstanceIndex
OpDecorate %_entryPointOutput BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%10 = OpTypeFunction %v4float %_ptr_Function_uint %_ptr_Function_uint
%_ptr_Input_uint = OpTypePointer Input %uint
%vid_1 = OpVariable %_ptr_Input_uint Input
%iid_1 = OpVariable %_ptr_Input_uint Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%vid_0 = OpVariable %_ptr_Function_uint Function
%iid_0 = OpVariable %_ptr_Function_uint Function
%param = OpVariable %_ptr_Function_uint Function
%param_0 = OpVariable %_ptr_Function_uint Function
%25 = OpLoad %uint %vid_1
OpStore %vid_0 %25
%28 = OpLoad %uint %iid_1
OpStore %iid_0 %28
%32 = OpLoad %uint %vid_0
OpStore %param %32
%34 = OpLoad %uint %iid_0
OpStore %param_0 %34
%35 = OpFunctionCall %v4float %_main_u1_u1_ %param %param_0
OpStore %_entryPointOutput %35
OpReturn
OpFunctionEnd
%_main_u1_u1_ = OpFunction %v4float None %10
%vid = OpFunctionParameter %_ptr_Function_uint
%iid = OpFunctionParameter %_ptr_Function_uint
%14 = OpLabel
%15 = OpLoad %uint %vid
%16 = OpLoad %uint %iid
%17 = OpIAdd %uint %15 %16
%18 = OpConvertUToF %float %17
%19 = OpCompositeConstruct %v4float %18 %18 %18 %18
OpReturnValue %19
OpFunctionEnd

View File

@ -0,0 +1,25 @@
#version 450
layout(local_size_x = 1) in;
layout(r32f, binding = 0) uniform readonly image2D uImageIn;
layout(r32f, binding = 1) uniform coherent writeonly image2D uImageOut;
layout(set = 0, binding = 2) readonly buffer Foo
{
float foo;
};
layout(set = 0, binding = 3) coherent writeonly buffer Bar
{
float bar;
};
void main()
{
ivec2 coord = ivec2(9, 7);
vec4 indata = imageLoad(uImageIn, coord);
imageStore(uImageOut, coord, indata);
bar = foo;
}

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -0,0 +1,71 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 44
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %vUV %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %sample_combined_ "sample_combined("
OpName %sample_separate_ "sample_separate("
OpName %uShadow "uShadow"
OpName %vUV "vUV"
OpName %uTexture "uTexture"
OpName %uSampler "uSampler"
OpName %FragColor "FragColor"
OpDecorate %uShadow DescriptorSet 0
OpDecorate %uShadow Binding 0
OpDecorate %vUV Location 0
OpDecorate %uTexture DescriptorSet 0
OpDecorate %uTexture Binding 1
OpDecorate %uSampler DescriptorSet 0
OpDecorate %uSampler Binding 2
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeFunction %float
%12 = OpTypeImage %float 2D 2 0 0 1 Unknown
%13 = OpTypeSampledImage %12
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
%uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant
%v3float = OpTypeVector %float 3
%_ptr_Input_v3float = OpTypePointer Input %v3float
%vUV = OpVariable %_ptr_Input_v3float Input
%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12
%uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant
%29 = OpTypeSampler
%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
%uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant
%_ptr_Output_float = OpTypePointer Output %float
%FragColor = OpVariable %_ptr_Output_float Output
%main = OpFunction %void None %3
%5 = OpLabel
%41 = OpFunctionCall %float %sample_combined_
%42 = OpFunctionCall %float %sample_separate_
%43 = OpFAdd %float %41 %42
OpStore %FragColor %43
OpReturn
OpFunctionEnd
%sample_combined_ = OpFunction %float None %7
%9 = OpLabel
%16 = OpLoad %13 %uShadow
%20 = OpLoad %v3float %vUV
%21 = OpCompositeExtract %float %20 2
%22 = OpImageSampleDrefImplicitLod %float %16 %20 %21
OpReturnValue %22
OpFunctionEnd
%sample_separate_ = OpFunction %float None %7
%11 = OpLabel
%28 = OpLoad %12 %uTexture
%32 = OpLoad %29 %uSampler
%33 = OpSampledImage %13 %28 %32
%34 = OpLoad %v3float %vUV
%35 = OpCompositeExtract %float %34 2
%36 = OpImageSampleDrefImplicitLod %float %33 %34 %35
OpReturnValue %36
OpFunctionEnd

View File

@ -0,0 +1,65 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 36
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %vid_1 %iid_1 %_entryPointOutput
OpSource HLSL 500
OpName %main "main"
OpName %_main_u1_u1_ "@main(u1;u1;"
OpName %vid "vid"
OpName %iid "iid"
OpName %vid_0 "vid"
OpName %vid_1 "vid"
OpName %iid_0 "iid"
OpName %iid_1 "iid"
OpName %_entryPointOutput "@entryPointOutput"
OpName %param "param"
OpName %param_0 "param"
OpDecorate %vid_1 BuiltIn VertexIndex
OpDecorate %iid_1 BuiltIn InstanceIndex
OpDecorate %_entryPointOutput BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%10 = OpTypeFunction %v4float %_ptr_Function_uint %_ptr_Function_uint
%_ptr_Input_uint = OpTypePointer Input %uint
%vid_1 = OpVariable %_ptr_Input_uint Input
%iid_1 = OpVariable %_ptr_Input_uint Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%vid_0 = OpVariable %_ptr_Function_uint Function
%iid_0 = OpVariable %_ptr_Function_uint Function
%param = OpVariable %_ptr_Function_uint Function
%param_0 = OpVariable %_ptr_Function_uint Function
%25 = OpLoad %uint %vid_1
OpStore %vid_0 %25
%28 = OpLoad %uint %iid_1
OpStore %iid_0 %28
%32 = OpLoad %uint %vid_0
OpStore %param %32
%34 = OpLoad %uint %iid_0
OpStore %param_0 %34
%35 = OpFunctionCall %v4float %_main_u1_u1_ %param %param_0
OpStore %_entryPointOutput %35
OpReturn
OpFunctionEnd
%_main_u1_u1_ = OpFunction %v4float None %10
%vid = OpFunctionParameter %_ptr_Function_uint
%iid = OpFunctionParameter %_ptr_Function_uint
%14 = OpLabel
%15 = OpLoad %uint %vid
%16 = OpLoad %uint %iid
%17 = OpIAdd %uint %15 %16
%18 = OpConvertUToF %float %17
%19 = OpCompositeConstruct %v4float %18 %18 %18 %18
OpReturnValue %19
OpFunctionEnd

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -0,0 +1,12 @@
#version 450
void write_outblock()
{
gl_PointSize = 1.0;
gl_Position = vec4(gl_PointSize);
}
void main()
{
write_outblock();
}

View File

@ -0,0 +1,60 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 3
; Bound: 20
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %_
OpEntryPoint Vertex %main2 "main2" %_
OpEntryPoint Fragment %main3 "main" %FragColor
OpEntryPoint Fragment %main4 "main2" %FragColor
OpSource GLSL 450
OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
OpDecorate %FragColor Location 0
OpDecorate %gl_PerVertex Block
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%v4floatptr = OpTypePointer Output %v4float
%uint = OpTypeInt 32 0
%uint_1 = OpConstant %uint 1
%_arr_float_uint_1 = OpTypeArray %float %uint_1
%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
%_ = OpVariable %_ptr_Output_gl_PerVertex Output
%FragColor = OpVariable %v4floatptr Output
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%float_1 = OpConstant %float 1
%17 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%float_2 = OpConstant %float 2
%18 = OpConstantComposite %v4float %float_2 %float_2 %float_2 %float_2
%_ptr_Output_v4float = OpTypePointer Output %v4float
%main = OpFunction %void None %3
%5 = OpLabel
%19 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %19 %17
OpReturn
OpFunctionEnd
%main2 = OpFunction %void None %3
%6 = OpLabel
%20 = OpAccessChain %_ptr_Output_v4float %_ %int_0
OpStore %20 %18
OpReturn
OpFunctionEnd
%main3 = OpFunction %void None %3
%7 = OpLabel
OpStore %FragColor %17
OpReturn
OpFunctionEnd
%main4 = OpFunction %void None %3
%8 = OpLabel
OpStore %FragColor %18
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,24 @@
#version 310 es
layout(local_size_x = 1) in;
struct Foo
{
mat4 m;
};
layout(std430, binding = 0) readonly buffer SSBO
{
Foo in_data[];
};
layout(std430, binding = 1) writeonly buffer SSBO2
{
Foo out_data[];
};
void main()
{
uint ident = gl_GlobalInvocationID.x;
out_data[ident].m = in_data[ident].m * in_data[ident].m;
}

View File

@ -0,0 +1,87 @@
#version 450
layout(local_size_x = 1) in;
struct S0
{
vec2 a[1];
float b;
};
struct S1
{
vec3 a;
float b;
};
struct S2
{
vec3 a[1];
float b;
};
struct S3
{
vec2 a;
float b;
};
struct S4
{
vec2 c;
};
struct Content
{
S0 m0s[1];
S1 m1s[1];
S2 m2s[1];
S0 m0;
S1 m1;
S2 m2;
S3 m3;
float m4;
S4 m3s[8];
};
layout(binding = 1, std430) restrict buffer SSBO1
{
Content content;
Content content1[2];
Content content2;
layout(column_major) mat2 m0;
layout(column_major) mat2 m1;
layout(column_major) mat2x3 m2[4];
layout(column_major) mat3x2 m3;
layout(row_major) mat2 m4;
layout(row_major) mat2 m5[9];
layout(row_major) mat2x3 m6[4][2];
layout(row_major) mat3x2 m7;
float array[];
} ssbo_430;
layout(binding = 0, std140) restrict buffer SSBO0
{
Content content;
Content content1[2];
Content content2;
layout(column_major) mat2 m0;
layout(column_major) mat2 m1;
layout(column_major) mat2x3 m2[4];
layout(column_major) mat3x2 m3;
layout(row_major) mat2 m4;
layout(row_major) mat2 m5[9];
layout(row_major) mat2x3 m6[4][2];
layout(row_major) mat3x2 m7;
float array[];
} ssbo_140;
void main()
{
ssbo_430.content = ssbo_140.content;
}

View File

@ -0,0 +1,29 @@
#version 310 es
precision mediump float;
layout(set = 0, binding = 0) uniform mediump samplerShadow uSampler;
layout(set = 0, binding = 1) uniform mediump sampler uSampler1;
layout(set = 0, binding = 2) uniform texture2D uDepth;
layout(location = 0) out float FragColor;
float samp2(texture2D t, mediump samplerShadow s)
{
return texture(sampler2DShadow(t, s), vec3(1.0));
}
float samp3(texture2D t, mediump sampler s)
{
return texture(sampler2D(t, s), vec2(1.0)).x;
}
float samp(texture2D t, mediump samplerShadow s, mediump sampler s1)
{
float r0 = samp2(t, s);
float r1 = samp3(t, s1);
return r0 + r1;
}
void main()
{
FragColor = samp(uDepth, uSampler, uSampler1);
}

View File

@ -0,0 +1,47 @@
#version 310 es
precision mediump float;
layout(set = 0, binding = 0) uniform mediump sampler uSampler0;
layout(set = 0, binding = 1) uniform mediump sampler uSampler1;
layout(set = 0, binding = 2) uniform mediump texture2D uTexture0;
layout(set = 0, binding = 3) uniform mediump texture2D uTexture1;
layout(location = 0) out vec4 FragColor;
layout(location = 0) in vec2 vTex;
vec4 sample_dual(mediump sampler samp, mediump texture2D tex)
{
return texture(sampler2D(tex, samp), vTex);
}
vec4 sample_global_tex(mediump sampler samp)
{
vec4 a = texture(sampler2D(uTexture0, samp), vTex);
vec4 b = sample_dual(samp, uTexture1);
return a + b;
}
vec4 sample_global_sampler(mediump texture2D tex)
{
vec4 a = texture(sampler2D(tex, uSampler0), vTex);
vec4 b = sample_dual(uSampler1, tex);
return a + b;
}
vec4 sample_duals()
{
vec4 a = sample_dual(uSampler0, uTexture0);
vec4 b = sample_dual(uSampler1, uTexture1);
return a + b;
}
void main()
{
vec4 c0 = sample_duals();
vec4 c1 = sample_global_tex(uSampler0);
vec4 c2 = sample_global_tex(uSampler1);
vec4 c3 = sample_global_sampler(uTexture0);
vec4 c4 = sample_global_sampler(uTexture1);
FragColor = c0 + c1 + c2 + c3 + c4;
}

View File

@ -0,0 +1,103 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 2
; Bound: 63
; Schema: 0
OpCapability Shader
OpCapability SampledBuffer
OpCapability ImageBuffer
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %_entryPointOutput
OpExecutionMode %main OriginUpperLeft
OpSource HLSL 500
OpName %main "main"
OpName %_main_ "@main("
OpName %storeTemp "storeTemp"
OpName %RWIm "RWIm"
OpName %v "v"
OpName %RWBuf "RWBuf"
OpName %ROIm "ROIm"
OpName %ROBuf "ROBuf"
OpName %_entryPointOutput "@entryPointOutput"
OpDecorate %RWIm DescriptorSet 0
OpDecorate %RWIm Binding 1
OpDecorate %RWBuf DescriptorSet 0
OpDecorate %RWBuf Binding 0
OpDecorate %ROIm DescriptorSet 0
OpDecorate %ROIm Binding 1
OpDecorate %ROBuf DescriptorSet 0
OpDecorate %ROBuf Binding 0
OpDecorate %_entryPointOutput Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%8 = OpTypeFunction %v4float
%_ptr_Function_v4float = OpTypePointer Function %v4float
%float_10 = OpConstant %float 10
%float_0_5 = OpConstant %float 0.5
%float_8 = OpConstant %float 8
%float_2 = OpConstant %float 2
%17 = OpConstantComposite %v4float %float_10 %float_0_5 %float_8 %float_2
%18 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18
%RWIm = OpVariable %_ptr_UniformConstant_18 UniformConstant
%uint = OpTypeInt 32 0
%v2uint = OpTypeVector %uint 2
%uint_10 = OpConstant %uint 10
%25 = OpConstantComposite %v2uint %uint_10 %uint_10
%uint_30 = OpConstant %uint 30
%30 = OpConstantComposite %v2uint %uint_30 %uint_30
%32 = OpTypeImage %float Buffer 0 0 0 2 Rgba32f
%_ptr_UniformConstant_32 = OpTypePointer UniformConstant %32
%RWBuf = OpVariable %_ptr_UniformConstant_32 UniformConstant
%uint_80 = OpConstant %uint 80
%38 = OpTypeImage %float 2D 0 0 0 1 Unknown
%SampledImage = OpTypeSampledImage %38
%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %SampledImage
%ROIm = OpVariable %_ptr_UniformConstant_38 UniformConstant
%uint_50 = OpConstant %uint 50
%uint_60 = OpConstant %uint 60
%44 = OpConstantComposite %v2uint %uint_50 %uint_60
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%50 = OpTypeImage %float Buffer 0 0 0 1 Rgba32f
%_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50
%ROBuf = OpVariable %_ptr_UniformConstant_50 UniformConstant
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%62 = OpFunctionCall %v4float %_main_
OpStore %_entryPointOutput %62
OpReturn
OpFunctionEnd
%_main_ = OpFunction %v4float None %8
%10 = OpLabel
%storeTemp = OpVariable %_ptr_Function_v4float Function
%v = OpVariable %_ptr_Function_v4float Function
OpStore %storeTemp %17
%21 = OpLoad %18 %RWIm
%26 = OpLoad %v4float %storeTemp
OpImageWrite %21 %25 %26
%28 = OpLoad %18 %RWIm
%31 = OpImageRead %v4float %28 %30
OpStore %v %31
%35 = OpLoad %32 %RWBuf
%37 = OpLoad %v4float %v
OpImageWrite %35 %uint_80 %37
%41 = OpLoad %SampledImage %ROIm
%ROImage = OpImage %38 %41
%47 = OpImageFetch %v4float %ROImage %44 Lod %int_0
%48 = OpLoad %v4float %v
%49 = OpFAdd %v4float %48 %47
OpStore %v %49
%53 = OpLoad %50 %ROBuf
%54 = OpImageFetch %v4float %53 %uint_80
%55 = OpLoad %v4float %v
%56 = OpFAdd %v4float %55 %54
OpStore %v %56
%57 = OpLoad %v4float %v
OpReturnValue %57
OpFunctionEnd

View File

@ -0,0 +1,10 @@
#version 450
layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS uSubpass0;
layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS uSubpass1;
layout(location = 0) out vec4 FragColor;
void main()
{
FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2) + subpassLoad(uSubpass0, gl_SampleID);
}

View File

@ -0,0 +1,11 @@
#version 310 es
precision mediump float;
layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInput uSubpass0;
layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInput uSubpass1;
layout(location = 0) out vec4 FragColor;
void main()
{
FragColor = subpassLoad(uSubpass0) + subpassLoad(uSubpass1);
}

View File

@ -0,0 +1,16 @@
#version 310 es
precision mediump float;
layout(push_constant, std430) uniform PushConstants
{
vec4 value0;
vec4 value1;
} push;
layout(location = 0) in vec4 vColor;
layout(location = 0) out vec4 FragColor;
void main()
{
FragColor = vColor + push.value0 + push.value1;
}

View File

@ -0,0 +1,42 @@
#version 310 es
precision mediump float;
layout(set = 0, binding = 0) uniform mediump sampler uSampler;
layout(set = 0, binding = 1) uniform mediump texture2D uTexture[4];
layout(set = 0, binding = 2) uniform mediump texture3D uTexture3D[4];
layout(set = 0, binding = 3) uniform mediump textureCube uTextureCube[4];
layout(set = 0, binding = 4) uniform mediump texture2DArray uTextureArray[4];
layout(location = 0) out vec4 FragColor;
layout(location = 0) in vec2 vTex;
layout(location = 1) in vec3 vTex3;
vec4 sample_func(mediump sampler samp, vec2 uv)
{
return texture(sampler2D(uTexture[2], samp), uv);
}
vec4 sample_func_dual(mediump sampler samp, mediump texture2D tex, vec2 uv)
{
return texture(sampler2D(tex, samp), uv);
}
vec4 sample_func_dual_array(mediump sampler samp, mediump texture2D tex[4], vec2 uv)
{
return texture(sampler2D(tex[1], samp), uv);
}
void main()
{
vec2 off = 1.0 / vec2(textureSize(sampler2D(uTexture[1], uSampler), 0));
vec2 off2 = 1.0 / vec2(textureSize(sampler2D(uTexture[2], uSampler), 1));
vec4 c0 = sample_func(uSampler, vTex + off + off2);
vec4 c1 = sample_func_dual(uSampler, uTexture[1], vTex + off + off2);
vec4 c2 = sample_func_dual_array(uSampler, uTexture, vTex + off + off2);
vec4 c3 = texture(sampler2DArray(uTextureArray[3], uSampler), vTex3);
vec4 c4 = texture(samplerCube(uTextureCube[1], uSampler), vTex3);
vec4 c5 = texture(sampler3D(uTexture3D[2], uSampler), vTex3);
FragColor = c0 + c1 + c2 + c3 + c4 + c5;
}

View File

@ -0,0 +1,78 @@
#version 310 es
precision mediump float;
layout(location = 0) out vec4 FragColor;
layout(constant_id = 1) const float a = 1.5;
layout(constant_id = 2) const float b = 2.5;
layout(constant_id = 3) const int c = 3;
layout(constant_id = 4) const int d = 4;
layout(constant_id = 5) const uint e = 5u;
layout(constant_id = 6) const uint f = 6u;
layout(constant_id = 7) const bool g = false;
layout(constant_id = 8) const bool h = true;
// glslang doesn't seem to support partial spec constants or composites yet, so only test the basics.
struct Foo
{
float elems[d + 2];
};
void main()
{
float t0 = a;
float t1 = b;
uint c0 = uint(c); // OpIAdd with different types.
// FConvert, float-to-double.
int c1 = -c; // SNegate
int c2 = ~c; // OpNot
int c3 = c + d; // OpIAdd
int c4 = c - d; // OpISub
int c5 = c * d; // OpIMul
int c6 = c / d; // OpSDiv
uint c7 = e / f; // OpUDiv
int c8 = c % d; // OpSMod
uint c9 = e % f; // OpUMod
// TODO: OpSRem, any way to access this in GLSL?
int c10 = c >> d; // OpShiftRightArithmetic
uint c11 = e >> f; // OpShiftRightLogical
int c12 = c << d; // OpShiftLeftLogical
int c13 = c | d; // OpBitwiseOr
int c14 = c ^ d; // OpBitwiseXor
int c15 = c & d; // OpBitwiseAnd
// VectorShuffle, CompositeExtract, CompositeInsert, not testable atm.
bool c16 = g || h; // OpLogicalOr
bool c17 = g && h; // OpLogicalAnd
bool c18 = !g; // OpLogicalNot
bool c19 = g == h; // OpLogicalEqual
bool c20 = g != h; // OpLogicalNotEqual
// OpSelect not testable atm.
bool c21 = c == d; // OpIEqual
bool c22 = c != d; // OpINotEqual
bool c23 = c < d; // OpSLessThan
bool c24 = e < f; // OpULessThan
bool c25 = c > d; // OpSGreaterThan
bool c26 = e > f; // OpUGreaterThan
bool c27 = c <= d; // OpSLessThanEqual
bool c28 = e <= f; // OpULessThanEqual
bool c29 = c >= d; // OpSGreaterThanEqual
bool c30 = e >= f; // OpUGreaterThanEqual
// OpQuantizeToF16 not testable atm.
int c31 = c8 + c3;
int c32 = int(e); // OpIAdd with different types.
bool c33 = bool(c); // int -> bool
bool c34 = bool(e); // uint -> bool
int c35 = int(g); // bool -> int
uint c36 = uint(g); // bool -> uint
float c37 = float(g); // bool -> float
// Flexible sized arrays with spec constants and spec constant ops.
float vec0[c + 3][8];
float vec1[c + 2];
Foo foo;
FragColor = vec4(t0 + t1) + vec0[0][0] + vec1[0] + foo.elems[c];
}

View File

@ -0,0 +1,20 @@
#version 310 es
layout(location = 0) in highp vec4 a_position;
layout(location = 0) out mediump float v_vtxResult;
layout(set = 0, binding = 0, std140, row_major) uniform Block
{
highp mat2x3 var[3][4];
};
mediump float compare_float (highp float a, highp float b) { return abs(a - b) < 0.05 ? 1.0 : 0.0; }
mediump float compare_vec3 (highp vec3 a, highp vec3 b) { return compare_float(a.x, b.x)*compare_float(a.y, b.y)*compare_float(a.z, b.z); }
mediump float compare_mat2x3 (highp mat2x3 a, highp mat2x3 b){ return compare_vec3(a[0], b[0])*compare_vec3(a[1], b[1]); }
void main (void)
{
gl_Position = a_position;
mediump float result = 1.0;
result *= compare_mat2x3(var[0][0], mat2x3(2.0, 6.0, -6.0, 0.0, 5.0, 5.0));
v_vtxResult = result;
}

View File

@ -0,0 +1,10 @@
#version 310 es
#extension GL_OES_texture_buffer : require
layout(binding = 4) uniform highp samplerBuffer uSamp;
layout(rgba32f, binding = 5) uniform readonly highp imageBuffer uSampo;
void main()
{
gl_Position = texelFetch(uSamp, 10) + imageLoad(uSampo, 100);
}

View File

@ -0,0 +1,45 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 28
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %vIndex %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource ESSL 310
OpName %main "main"
OpName %vIndex "vIndex"
OpName %FragColor "FragColor"
OpDecorate %vIndex RelaxedPrecision
OpDecorate %vIndex Flat
OpDecorate %vIndex Location 0
OpDecorate %13 RelaxedPrecision
OpDecorate %FragColor RelaxedPrecision
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%float_8 = OpConstant %float 8
%int = OpTypeInt 32 1
%_ptr_Input_int = OpTypePointer Input %int
%vIndex = OpVariable %_ptr_Input_int Input
%float_1 = OpConstant %float 1
%float_3 = OpConstant %float 3
%_ptr_Output_float = OpTypePointer Output %float
%FragColor = OpVariable %_ptr_Output_float Output
%main = OpFunction %void None %3
%5 = OpLabel
%13 = OpLoad %int %vIndex
OpSelectionMerge %17 None
OpSwitch %13 %15 0 %14 2 %14 1 %15 8 %17
%15 = OpLabel
OpBranch %17
%14 = OpLabel
OpBranch %17
%17 = OpLabel
%27 = OpPhi %float %float_3 %15 %float_1 %14 %float_8 %5
OpStore %FragColor %27
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,71 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 44
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %vUV %FragColor
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %sample_combined_ "sample_combined("
OpName %sample_separate_ "sample_separate("
OpName %uShadow "uShadow"
OpName %vUV "vUV"
OpName %uTexture "uTexture"
OpName %uSampler "uSampler"
OpName %FragColor "FragColor"
OpDecorate %uShadow DescriptorSet 0
OpDecorate %uShadow Binding 0
OpDecorate %vUV Location 0
OpDecorate %uTexture DescriptorSet 0
OpDecorate %uTexture Binding 1
OpDecorate %uSampler DescriptorSet 0
OpDecorate %uSampler Binding 2
OpDecorate %FragColor Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%7 = OpTypeFunction %float
%12 = OpTypeImage %float 2D 2 0 0 1 Unknown
%13 = OpTypeSampledImage %12
%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
%uShadow = OpVariable %_ptr_UniformConstant_13 UniformConstant
%v3float = OpTypeVector %float 3
%_ptr_Input_v3float = OpTypePointer Input %v3float
%vUV = OpVariable %_ptr_Input_v3float Input
%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %12
%uTexture = OpVariable %_ptr_UniformConstant_25 UniformConstant
%29 = OpTypeSampler
%_ptr_UniformConstant_29 = OpTypePointer UniformConstant %29
%uSampler = OpVariable %_ptr_UniformConstant_29 UniformConstant
%_ptr_Output_float = OpTypePointer Output %float
%FragColor = OpVariable %_ptr_Output_float Output
%main = OpFunction %void None %3
%5 = OpLabel
%41 = OpFunctionCall %float %sample_combined_
%42 = OpFunctionCall %float %sample_separate_
%43 = OpFAdd %float %41 %42
OpStore %FragColor %43
OpReturn
OpFunctionEnd
%sample_combined_ = OpFunction %float None %7
%9 = OpLabel
%16 = OpLoad %13 %uShadow
%20 = OpLoad %v3float %vUV
%21 = OpCompositeExtract %float %20 2
%22 = OpImageSampleDrefImplicitLod %float %16 %20 %21
OpReturnValue %22
OpFunctionEnd
%sample_separate_ = OpFunction %float None %7
%11 = OpLabel
%28 = OpLoad %12 %uTexture
%32 = OpLoad %29 %uSampler
%33 = OpSampledImage %13 %28 %32
%34 = OpLoad %v3float %vUV
%35 = OpCompositeExtract %float %34 2
%36 = OpImageSampleDrefImplicitLod %float %33 %34 %35
OpReturnValue %36
OpFunctionEnd

View File

@ -0,0 +1,130 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 74
; Schema: 0
OpCapability Geometry
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Geometry %main "main" %stream_pos %stream_layer %input_pos
OpExecutionMode %main Triangles
OpExecutionMode %main Invocations 1
OpExecutionMode %main OutputTriangleStrip
OpExecutionMode %main OutputVertices 3
OpSource HLSL 500
OpName %main "main"
OpName %VertexOutput "VertexOutput"
OpMemberName %VertexOutput 0 "pos"
OpName %GeometryOutput "GeometryOutput"
OpMemberName %GeometryOutput 0 "pos"
OpMemberName %GeometryOutput 1 "layer"
OpName %_main_struct_VertexOutput_vf41_3__struct_GeometryOutput_vf4_u11_ "@main(struct-VertexOutput-vf41[3];struct-GeometryOutput-vf4-u11;"
OpName %input "input"
OpName %stream "stream"
OpName %output "output"
OpName %v "v"
OpName %stream_pos "stream.pos"
OpName %stream_layer "stream.layer"
OpName %input_0 "input"
OpName %input_pos "input.pos"
OpName %stream_0 "stream"
OpName %param "param"
OpName %param_0 "param"
OpDecorate %stream_pos BuiltIn Position
OpDecorate %stream_layer BuiltIn Layer
OpDecorate %input_pos BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%VertexOutput = OpTypeStruct %v4float
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%_arr_VertexOutput_uint_3 = OpTypeArray %VertexOutput %uint_3
%_ptr_Function__arr_VertexOutput_uint_3 = OpTypePointer Function %_arr_VertexOutput_uint_3
%GeometryOutput = OpTypeStruct %v4float %uint
%_ptr_Function_GeometryOutput = OpTypePointer Function %GeometryOutput
%15 = OpTypeFunction %void %_ptr_Function__arr_VertexOutput_uint_3 %_ptr_Function_GeometryOutput
%int = OpTypeInt 32 1
%int_1 = OpConstant %int 1
%uint_1 = OpConstant %uint 1
%_ptr_Function_uint = OpTypePointer Function %uint
%_ptr_Function_int = OpTypePointer Function %int
%int_0 = OpConstant %int 0
%int_3 = OpConstant %int 3
%bool = OpTypeBool
%_ptr_Function_v4float = OpTypePointer Function %v4float
%_ptr_Output_v4float = OpTypePointer Output %v4float
%stream_pos = OpVariable %_ptr_Output_v4float Output
%_ptr_Output_uint = OpTypePointer Output %uint
%stream_layer = OpVariable %_ptr_Output_uint Output
%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
%_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3
%input_pos = OpVariable %_ptr_Input__arr_v4float_uint_3 Input
%_ptr_Input_v4float = OpTypePointer Input %v4float
%int_2 = OpConstant %int 2
%main = OpFunction %void None %3
%5 = OpLabel
%input_0 = OpVariable %_ptr_Function__arr_VertexOutput_uint_3 Function
%stream_0 = OpVariable %_ptr_Function_GeometryOutput Function
%param = OpVariable %_ptr_Function__arr_VertexOutput_uint_3 Function
%param_0 = OpVariable %_ptr_Function_GeometryOutput Function
%58 = OpAccessChain %_ptr_Input_v4float %input_pos %int_0
%59 = OpLoad %v4float %58
%60 = OpAccessChain %_ptr_Function_v4float %input_0 %int_0 %int_0
OpStore %60 %59
%61 = OpAccessChain %_ptr_Input_v4float %input_pos %int_1
%62 = OpLoad %v4float %61
%63 = OpAccessChain %_ptr_Function_v4float %input_0 %int_1 %int_0
OpStore %63 %62
%65 = OpAccessChain %_ptr_Input_v4float %input_pos %int_2
%66 = OpLoad %v4float %65
%67 = OpAccessChain %_ptr_Function_v4float %input_0 %int_2 %int_0
OpStore %67 %66
%70 = OpLoad %_arr_VertexOutput_uint_3 %input_0
OpStore %param %70
%72 = OpFunctionCall %void %_main_struct_VertexOutput_vf41_3__struct_GeometryOutput_vf4_u11_ %param %param_0
%73 = OpLoad %GeometryOutput %param_0
OpStore %stream_0 %73
OpReturn
OpFunctionEnd
%_main_struct_VertexOutput_vf41_3__struct_GeometryOutput_vf4_u11_ = OpFunction %void None %15
%input = OpFunctionParameter %_ptr_Function__arr_VertexOutput_uint_3
%stream = OpFunctionParameter %_ptr_Function_GeometryOutput
%19 = OpLabel
%output = OpVariable %_ptr_Function_GeometryOutput Function
%v = OpVariable %_ptr_Function_int Function
%25 = OpAccessChain %_ptr_Function_uint %output %int_1
OpStore %25 %uint_1
OpStore %v %int_0
OpBranch %29
%29 = OpLabel
OpLoopMerge %31 %32 None
OpBranch %33
%33 = OpLabel
%34 = OpLoad %int %v
%37 = OpSLessThan %bool %34 %int_3
OpBranchConditional %37 %30 %31
%30 = OpLabel
%38 = OpLoad %int %v
%40 = OpAccessChain %_ptr_Function_v4float %input %38 %int_0
%41 = OpLoad %v4float %40
%42 = OpAccessChain %_ptr_Function_v4float %output %int_0
OpStore %42 %41
%45 = OpAccessChain %_ptr_Function_v4float %output %int_0
%46 = OpLoad %v4float %45
OpStore %stream_pos %46
%49 = OpAccessChain %_ptr_Function_uint %output %int_1
%50 = OpLoad %uint %49
OpStore %stream_layer %50
OpEmitVertex
OpBranch %32
%32 = OpLabel
%51 = OpLoad %int %v
%52 = OpIAdd %int %51 %int_1
OpStore %v %52
OpBranch %29
%31 = OpLabel
OpEndPrimitive
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,65 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 6
; Bound: 36
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Vertex %main "main" %vid_1 %iid_1 %_entryPointOutput
OpSource HLSL 500
OpName %main "main"
OpName %_main_u1_u1_ "@main(u1;u1;"
OpName %vid "vid"
OpName %iid "iid"
OpName %vid_0 "vid"
OpName %vid_1 "vid"
OpName %iid_0 "iid"
OpName %iid_1 "iid"
OpName %_entryPointOutput "@entryPointOutput"
OpName %param "param"
OpName %param_0 "param"
OpDecorate %vid_1 BuiltIn VertexIndex
OpDecorate %iid_1 BuiltIn InstanceIndex
OpDecorate %_entryPointOutput BuiltIn Position
%void = OpTypeVoid
%3 = OpTypeFunction %void
%uint = OpTypeInt 32 0
%_ptr_Function_uint = OpTypePointer Function %uint
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%10 = OpTypeFunction %v4float %_ptr_Function_uint %_ptr_Function_uint
%_ptr_Input_uint = OpTypePointer Input %uint
%vid_1 = OpVariable %_ptr_Input_uint Input
%iid_1 = OpVariable %_ptr_Input_uint Input
%_ptr_Output_v4float = OpTypePointer Output %v4float
%_entryPointOutput = OpVariable %_ptr_Output_v4float Output
%main = OpFunction %void None %3
%5 = OpLabel
%vid_0 = OpVariable %_ptr_Function_uint Function
%iid_0 = OpVariable %_ptr_Function_uint Function
%param = OpVariable %_ptr_Function_uint Function
%param_0 = OpVariable %_ptr_Function_uint Function
%25 = OpLoad %uint %vid_1
OpStore %vid_0 %25
%28 = OpLoad %uint %iid_1
OpStore %iid_0 %28
%32 = OpLoad %uint %vid_0
OpStore %param %32
%34 = OpLoad %uint %iid_0
OpStore %param_0 %34
%35 = OpFunctionCall %v4float %_main_u1_u1_ %param %param_0
OpStore %_entryPointOutput %35
OpReturn
OpFunctionEnd
%_main_u1_u1_ = OpFunction %v4float None %10
%vid = OpFunctionParameter %_ptr_Function_uint
%iid = OpFunctionParameter %_ptr_Function_uint
%14 = OpLabel
%15 = OpLoad %uint %vid
%16 = OpLoad %uint %iid
%17 = OpIAdd %uint %15 %16
%18 = OpConvertUToF %float %17
%19 = OpCompositeConstruct %v4float %18 %18 %18 %18
OpReturnValue %19
OpFunctionEnd

View File

@ -0,0 +1,9 @@
#version 450
layout(location = 0) out float FragColor;
layout(constant_id = 0) const uint s = 10u;
const uint f = s > 20u ? 30u : 50u;
void main()
{
FragColor = float(f);
}

View File

@ -578,6 +578,15 @@ struct SPIRBlock : IVariant
MergeSelection
};
enum Hints
{
HintNone,
HintUnroll,
HintDontUnroll,
HintFlatten,
HintDontFlatten
};
enum Method
{
MergeToSelectForLoop,
@ -610,6 +619,7 @@ struct SPIRBlock : IVariant
Terminator terminator = Unknown;
Merge merge = MergeNone;
Hints hint = HintNone;
uint32_t next_block = 0;
uint32_t merge_block = 0;
uint32_t continue_block = 0;

View File

@ -1063,6 +1063,34 @@ const SPIRType &Compiler::get_type_from_variable(uint32_t id) const
return get<SPIRType>(get<SPIRVariable>(id).basetype);
}
uint32_t Compiler::get_non_pointer_type_id(uint32_t type_id) const
{
auto *p_type = &get<SPIRType>(type_id);
while (p_type->pointer)
{
assert(p_type->parent_type);
type_id = p_type->parent_type;
p_type = &get<SPIRType>(type_id);
}
return type_id;
}
const SPIRType &Compiler::get_non_pointer_type(const SPIRType &type) const
{
auto *p_type = &type;
while (p_type->pointer)
{
assert(p_type->parent_type);
p_type = &get<SPIRType>(p_type->parent_type);
}
return *p_type;
}
const SPIRType &Compiler::get_non_pointer_type(uint32_t type_id) const
{
return get_non_pointer_type(get<SPIRType>(type_id));
}
void Compiler::set_member_decoration_string(uint32_t id, uint32_t index, spv::Decoration decoration,
const std::string &argument)
{
@ -1814,7 +1842,7 @@ void Compiler::parse(const Instruction &instruction)
type.basetype = SPIRType::Image;
type.image.type = ops[1];
type.image.dim = static_cast<Dim>(ops[2]);
type.image.depth = ops[3] != 0;
type.image.depth = ops[3] == 1;
type.image.arrayed = ops[4] != 0;
type.image.ms = ops[5] != 0;
type.image.sampled = ops[6];
@ -2221,6 +2249,14 @@ void Compiler::parse(const Instruction &instruction)
current_block->next_block = ops[0];
current_block->merge = SPIRBlock::MergeSelection;
selection_merge_targets.insert(current_block->next_block);
if (length >= 2)
{
if (ops[1] & SelectionControlFlattenMask)
current_block->hint = SPIRBlock::HintFlatten;
else if (ops[1] & SelectionControlDontFlattenMask)
current_block->hint = SPIRBlock::HintDontFlatten;
}
break;
}
@ -2243,6 +2279,14 @@ void Compiler::parse(const Instruction &instruction)
// they are treated as continues.
if (current_block->continue_block != current_block->self)
continue_blocks.insert(current_block->continue_block);
if (length >= 3)
{
if (ops[2] & LoopControlUnrollMask)
current_block->hint = SPIRBlock::HintUnroll;
else if (ops[2] & LoopControlDontUnrollMask)
current_block->hint = SPIRBlock::HintDontUnroll;
}
break;
}
@ -4243,14 +4287,8 @@ bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args
// Required if we access chain into builtins like gl_GlobalInvocationID.
add_if_builtin(args[2]);
auto *type = &compiler.get<SPIRType>(var->basetype);
// Start traversing type hierarchy at the proper non-pointer types.
while (type->pointer)
{
assert(type->parent_type);
type = &compiler.get<SPIRType>(type->parent_type);
}
auto *type = &compiler.get_non_pointer_type(var->basetype);
auto &flags =
type->storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
@ -4329,11 +4367,43 @@ bool Compiler::has_active_builtin(BuiltIn builtin, StorageClass storage)
void Compiler::analyze_image_and_sampler_usage()
{
CombinedImageSamplerUsageHandler handler(*this);
CombinedImageSamplerDrefHandler dref_handler(*this);
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), dref_handler);
CombinedImageSamplerUsageHandler handler(*this, dref_handler.dref_combined_samplers);
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
comparison_samplers = move(handler.comparison_samplers);
comparison_images = move(handler.comparison_images);
comparison_ids = move(handler.comparison_ids);
need_subpass_input = handler.need_subpass_input;
// Forward information from separate images and samplers into combined image samplers.
for (auto &combined : combined_image_samplers)
if (comparison_ids.count(combined.sampler_id))
comparison_ids.insert(combined.combined_id);
}
bool Compiler::CombinedImageSamplerDrefHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t)
{
// Mark all sampled images which are used with Dref.
switch (opcode)
{
case OpImageSampleDrefExplicitLod:
case OpImageSampleDrefImplicitLod:
case OpImageSampleProjDrefExplicitLod:
case OpImageSampleProjDrefImplicitLod:
case OpImageSparseSampleProjDrefImplicitLod:
case OpImageSparseSampleDrefImplicitLod:
case OpImageSparseSampleProjDrefExplicitLod:
case OpImageSparseSampleDrefExplicitLod:
case OpImageDrefGather:
case OpImageSparseDrefGather:
dref_combined_samplers.insert(args[2]);
return true;
default:
break;
}
return true;
}
bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length)
@ -4354,20 +4424,12 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint
return true;
}
void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_images(uint32_t image)
void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_ids(uint32_t id)
{
// Traverse the variable dependency hierarchy and tag everything in its path with comparison images.
comparison_images.insert(image);
for (auto &img : dependency_hierarchy[image])
add_hierarchy_to_comparison_images(img);
}
void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_samplers(uint32_t sampler)
{
// Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers.
comparison_samplers.insert(sampler);
for (auto &samp : dependency_hierarchy[sampler])
add_hierarchy_to_comparison_samplers(samp);
// Traverse the variable dependency hierarchy and tag everything in its path with comparison ids.
comparison_ids.insert(id);
for (auto &dep_id : dependency_hierarchy[id])
add_hierarchy_to_comparison_ids(dep_id);
}
bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
@ -4387,6 +4449,10 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_
auto &type = compiler.get<SPIRType>(args[0]);
if (type.image.dim == DimSubpassData)
need_subpass_input = true;
// If we load a SampledImage and it will be used with Dref, propagate the state up.
if (dref_combined_samplers.count(args[1]) != 0)
add_hierarchy_to_comparison_ids(args[1]);
break;
}
@ -4396,16 +4462,20 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_
return false;
uint32_t result_type = args[0];
uint32_t result_id = args[1];
auto &type = compiler.get<SPIRType>(result_type);
if (type.image.depth)
if (type.image.depth || dref_combined_samplers.count(result_id) != 0)
{
// This image must be a depth image.
uint32_t image = args[2];
add_hierarchy_to_comparison_images(image);
add_hierarchy_to_comparison_ids(image);
// This sampler must be a SamplerComparisionState, and not a regular SamplerState.
// This sampler must be a SamplerComparisonState, and not a regular SamplerState.
uint32_t sampler = args[3];
add_hierarchy_to_comparison_samplers(sampler);
add_hierarchy_to_comparison_ids(sampler);
// Mark the OpSampledImage itself as being comparison state.
comparison_ids.insert(result_id);
}
return true;
}
@ -4567,3 +4637,57 @@ bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &resul
return false;
}
}
Bitset Compiler::combined_decoration_for_member(const SPIRType &type, uint32_t index) const
{
Bitset flags;
auto &memb = meta[type.self].members;
if (index >= memb.size())
return flags;
auto &dec = memb[index];
// If our type is a struct, traverse all the members as well recursively.
flags.merge_or(dec.decoration_flags);
for (uint32_t i = 0; i < type.member_types.size(); i++)
flags.merge_or(combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i));
return flags;
}
bool Compiler::is_desktop_only_format(spv::ImageFormat format)
{
switch (format)
{
// Desktop-only formats
case ImageFormatR11fG11fB10f:
case ImageFormatR16f:
case ImageFormatRgb10A2:
case ImageFormatR8:
case ImageFormatRg8:
case ImageFormatR16:
case ImageFormatRg16:
case ImageFormatRgba16:
case ImageFormatR16Snorm:
case ImageFormatRg16Snorm:
case ImageFormatRgba16Snorm:
case ImageFormatR8Snorm:
case ImageFormatRg8Snorm:
case ImageFormatR8ui:
case ImageFormatRg8ui:
case ImageFormatR16ui:
case ImageFormatRgb10a2ui:
case ImageFormatR8i:
case ImageFormatRg8i:
case ImageFormatR16i:
return true;
default:
break;
}
return false;
}
bool Compiler::image_is_comparison(const spirv_cross::SPIRType &type, uint32_t id) const
{
return type.image.depth || (comparison_ids.count(id) != 0);
}

View File

@ -170,6 +170,15 @@ public:
// Gets the SPIR-V type of a variable.
const SPIRType &get_type_from_variable(uint32_t id) const;
// Gets the id of SPIR-V type underlying the given type_id, which might be a pointer.
uint32_t get_non_pointer_type_id(uint32_t type_id) const;
// Gets the SPIR-V type underlying the given type, which might be a pointer.
const SPIRType &get_non_pointer_type(const SPIRType &type) const;
// Gets the SPIR-V type underlying the given type_id, which might be a pointer.
const SPIRType &get_non_pointer_type(uint32_t type_id) const;
// Gets the underlying storage class for an OpVariable.
spv::StorageClass get_storage_class(uint32_t id) const;
@ -817,8 +826,7 @@ protected:
// There might be unrelated IDs found in this set which do not correspond to actual variables.
// This set should only be queried for the existence of samplers which are already known to be variables or parameter IDs.
// Similar is implemented for images, as well as if subpass inputs are needed.
std::unordered_set<uint32_t> comparison_samplers;
std::unordered_set<uint32_t> comparison_images;
std::unordered_set<uint32_t> comparison_ids;
bool need_subpass_input = false;
// In certain backends, we will need to use a dummy sampler to be able to emit code.
@ -827,23 +835,37 @@ protected:
uint32_t dummy_sampler_id = 0;
void analyze_image_and_sampler_usage();
struct CombinedImageSamplerDrefHandler : OpcodeHandler
{
CombinedImageSamplerDrefHandler(Compiler &compiler_)
: compiler(compiler_)
{
}
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
std::unordered_set<uint32_t> dref_combined_samplers;
};
struct CombinedImageSamplerUsageHandler : OpcodeHandler
{
CombinedImageSamplerUsageHandler(Compiler &compiler_)
CombinedImageSamplerUsageHandler(Compiler &compiler_,
const std::unordered_set<uint32_t> &dref_combined_samplers_)
: compiler(compiler_)
, dref_combined_samplers(dref_combined_samplers_)
{
}
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
Compiler &compiler;
const std::unordered_set<uint32_t> &dref_combined_samplers;
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> dependency_hierarchy;
std::unordered_set<uint32_t> comparison_images;
std::unordered_set<uint32_t> comparison_samplers;
std::unordered_set<uint32_t> comparison_ids;
void add_hierarchy_to_comparison_samplers(uint32_t sampler);
void add_hierarchy_to_comparison_images(uint32_t sampler);
void add_hierarchy_to_comparison_ids(uint32_t ids);
bool need_subpass_input = false;
};
@ -856,6 +878,11 @@ protected:
bool instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op, const uint32_t *args,
uint32_t length);
Bitset combined_decoration_for_member(const SPIRType &type, uint32_t index) const;
static bool is_desktop_only_format(spv::ImageFormat format);
bool image_is_comparison(const SPIRType &type, uint32_t id) const;
private:
// Used only to implement the old deprecated get_entry_point() interface.
const SPIREntryPoint &get_first_entry_point(const std::string &name) const;

View File

@ -689,22 +689,6 @@ void CompilerGLSL::emit_struct(SPIRType &type)
statement("");
}
Bitset CompilerGLSL::combined_decoration_for_member(const SPIRType &type, uint32_t index)
{
Bitset flags;
auto &memb = meta[type.self].members;
if (index >= memb.size())
return flags;
auto &dec = memb[index];
// If our type is a struct, traverse all the members as well recursively.
flags.merge_or(dec.decoration_flags);
for (uint32_t i = 0; i < type.member_types.size(); i++)
flags.merge_or(combined_decoration_for_member(get<SPIRType>(type.member_types[i]), i));
return flags;
}
string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
{
string res;
@ -786,10 +770,8 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
{
auto check_desktop = [this] {
if (options.es)
SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
};
if (options.es && is_desktop_only_format(format))
SPIRV_CROSS_THROW("Attempting to use image format not supported in ES profile.");
switch (format)
{
@ -807,7 +789,6 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
return "rg32f";
case ImageFormatRg16f:
return "rg16f";
case ImageFormatRgba32i:
return "rgba32i";
case ImageFormatRgba16i:
@ -820,7 +801,6 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
return "rg32i";
case ImageFormatRg16i:
return "rg16i";
case ImageFormatRgba32ui:
return "rgba32ui";
case ImageFormatRgba16ui:
@ -833,71 +813,46 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
return "rg32ui";
case ImageFormatRg16ui:
return "rg16ui";
// Desktop-only formats
case ImageFormatR11fG11fB10f:
check_desktop();
return "r11f_g11f_b10f";
case ImageFormatR16f:
check_desktop();
return "r16f";
case ImageFormatRgb10A2:
check_desktop();
return "rgb10_a2";
case ImageFormatR8:
check_desktop();
return "r8";
case ImageFormatRg8:
check_desktop();
return "rg8";
case ImageFormatR16:
check_desktop();
return "r16";
case ImageFormatRg16:
check_desktop();
return "rg16";
case ImageFormatRgba16:
check_desktop();
return "rgba16";
case ImageFormatR16Snorm:
check_desktop();
return "r16_snorm";
case ImageFormatRg16Snorm:
check_desktop();
return "rg16_snorm";
case ImageFormatRgba16Snorm:
check_desktop();
return "rgba16_snorm";
case ImageFormatR8Snorm:
check_desktop();
return "r8_snorm";
case ImageFormatRg8Snorm:
check_desktop();
return "rg8_snorm";
case ImageFormatR8ui:
check_desktop();
return "r8ui";
case ImageFormatRg8ui:
check_desktop();
return "rg8ui";
case ImageFormatR16ui:
check_desktop();
return "r16ui";
case ImageFormatRgb10a2ui:
check_desktop();
return "rgb10_a2ui";
case ImageFormatR8i:
check_desktop();
return "r8i";
case ImageFormatRg8i:
check_desktop();
return "rg8i";
case ImageFormatR16i:
check_desktop();
return "r16i";
default:
case ImageFormatUnknown:
return nullptr;
@ -2246,7 +2201,8 @@ void CompilerGLSL::emit_resources()
{
// For gl_InstanceIndex emulation on GLES, the API user needs to
// supply this uniform.
if (meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
if (options.vertex.support_nonzero_base_instance &&
meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
{
statement("uniform int SPIRV_Cross_BaseInstance;");
emitted = true;
@ -2545,15 +2501,15 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
break;
#define GLSL_BOP(opname, x) \
case Op##opname: \
binary = true; \
op = x; \
case Op##opname: \
binary = true; \
op = x; \
break
#define GLSL_UOP(opname, x) \
case Op##opname: \
unary = true; \
op = x; \
case Op##opname: \
unary = true; \
op = x; \
break
GLSL_UOP(SNegate, "-");
@ -2597,11 +2553,14 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
// In order to preserve its compile-time constness in Vulkan GLSL,
// we need to reduce the OpSelect expression back to this simplified model.
// If we cannot, fail.
if (!to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
if (to_trivial_mix_op(type, op, cop.arguments[2], cop.arguments[1], cop.arguments[0]))
{
SPIRV_CROSS_THROW(
"Cannot implement specialization constant op OpSelect. "
"Need trivial select implementation which can be resolved to a simple cast from boolean.");
// Implement as a simple cast down below.
}
else
{
// Implement a ternary and pray the compiler understands it :)
return to_ternary_expression(type, cop.arguments[0], cop.arguments[1], cop.arguments[2]);
}
break;
}
@ -3501,7 +3460,7 @@ bool CompilerGLSL::check_explicit_lod_allowed(uint32_t lod)
return allowed;
}
string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod)
string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t tex)
{
const char *type;
switch (imgtype.image.dim)
@ -3531,7 +3490,7 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
bool use_explicit_lod = check_explicit_lod_allowed(lod);
if (op == "textureLod" || op == "textureProjLod" || op == "textureGrad")
if (op == "textureLod" || op == "textureProjLod" || op == "textureGrad" || op == "textureProjGrad")
{
if (is_legacy_es())
{
@ -3542,25 +3501,64 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp
require_extension_internal("GL_ARB_shader_texture_lod");
}
if (op == "textureLodOffset" || op == "textureProjLodOffset")
{
if (is_legacy_es())
SPIRV_CROSS_THROW(join(op, " not allowed in legacy ES"));
require_extension_internal("GL_EXT_gpu_shader4");
}
// GLES has very limited support for shadow samplers.
// Basically shadow2D and shadow2DProj work through EXT_shadow_samplers,
// everything else can just throw
if (image_is_comparison(imgtype, tex) && is_legacy_es())
{
if (op == "texture" || op == "textureProj")
require_extension_internal("GL_EXT_shadow_samplers");
else
SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES"));
}
bool is_es_and_depth = is_legacy_es() && image_is_comparison(imgtype, tex);
std::string type_prefix = image_is_comparison(imgtype, tex) ? "shadow" : "texture";
if (op == "texture")
return join("texture", type);
return is_es_and_depth ? join(type_prefix, type, "EXT") : join(type_prefix, type);
else if (op == "textureLod")
{
if (use_explicit_lod)
return join("texture", type, is_legacy_es() ? "LodEXT" : "Lod");
return join(type_prefix, type, is_legacy_es() ? "LodEXT" : "Lod");
else
return join("texture", type);
return join(type_prefix, type);
}
else if (op == "textureProj")
return join("texture", type, "Proj");
return join(type_prefix, type, is_es_and_depth ? "ProjEXT" : "Proj");
else if (op == "textureGrad")
return join("texture", type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
return join(type_prefix, type, is_legacy_es() ? "GradEXT" : is_legacy_desktop() ? "GradARB" : "Grad");
else if (op == "textureProjLod")
{
if (use_explicit_lod)
return join("texture", type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
return join(type_prefix, type, is_legacy_es() ? "ProjLodEXT" : "ProjLod");
else
return join("texture", type);
return join(type_prefix, type, "Proj");
}
else if (op == "textureLodOffset")
{
if (use_explicit_lod)
return join(type_prefix, type, "LodOffset");
else
return join(type_prefix, type);
}
else if (op == "textureProjGrad")
return join(type_prefix, type,
is_legacy_es() ? "ProjGradEXT" : is_legacy_desktop() ? "ProjGradARB" : "ProjGrad");
else if (op == "textureProjLodOffset")
{
if (use_explicit_lod)
return join(type_prefix, type, "ProjLodOffset");
else
return join(type_prefix, type, "ProjOffset");
}
else
{
@ -3622,6 +3620,37 @@ bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t
return ret;
}
string CompilerGLSL::to_ternary_expression(const SPIRType &restype, uint32_t select, uint32_t true_value,
uint32_t false_value)
{
string expr;
auto &lerptype = expression_type(select);
if (lerptype.vecsize == 1)
expr = join(to_enclosed_expression(select), " ? ", to_enclosed_expression(true_value), " : ",
to_enclosed_expression(false_value));
else
{
auto swiz = [this](uint32_t expression, uint32_t i) { return to_extract_component_expression(expression, i); };
expr = type_to_glsl_constructor(restype);
expr += "(";
for (uint32_t i = 0; i < restype.vecsize; i++)
{
expr += swiz(select, i);
expr += " ? ";
expr += swiz(true_value, i);
expr += " : ";
expr += swiz(false_value, i);
if (i + 1 < restype.vecsize)
expr += ", ";
}
expr += ")";
}
return expr;
}
void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp)
{
auto &lerptype = expression_type(lerp);
@ -3652,31 +3681,7 @@ void CompilerGLSL::emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left,
// Could use GL_EXT_shader_integer_mix on desktop at least,
// but Apple doesn't support it. :(
// Just implement it as ternary expressions.
string expr;
if (lerptype.vecsize == 1)
expr = join(to_enclosed_expression(lerp), " ? ", to_enclosed_expression(right), " : ",
to_enclosed_expression(left));
else
{
auto swiz = [this](uint32_t expression, uint32_t i) {
return to_extract_component_expression(expression, i);
};
expr = type_to_glsl_constructor(restype);
expr += "(";
for (uint32_t i = 0; i < restype.vecsize; i++)
{
expr += swiz(lerp, i);
expr += " ? ";
expr += swiz(right, i);
expr += " : ";
expr += swiz(left, i);
if (i + 1 < restype.vecsize)
expr += ", ";
}
expr += ")";
}
auto expr = to_ternary_expression(get<SPIRType>(result_type), lerp, right, left);
emit_op(result_type, id, expr, should_forward(left) && should_forward(right) && should_forward(lerp));
inherit_expression_dependencies(id, left);
inherit_expression_dependencies(id, right);
@ -3759,7 +3764,7 @@ void CompilerGLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_i
if (options.vulkan_semantics && combined_image_samplers.empty())
{
emit_binary_func_op(result_type, result_id, image_id, samp_id,
type_to_glsl(get<SPIRType>(result_type)).c_str());
type_to_glsl(get<SPIRType>(result_type), result_id).c_str());
// Make sure to suppress usage tracking. It is illegal to create temporaries of opaque types.
forwarded_temporaries.erase(result_id);
@ -3924,6 +3929,10 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
coffset, offset, bias, comp, sample, &forward);
expr += ")";
// texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here.
if (is_legacy() && image_is_comparison(imgtype, img))
expr += ".r";
emit_op(result_type, id, expr, forward);
for (auto &inherit : inherited_expressions)
inherit_expression_dependencies(id, inherit);
@ -3944,8 +3953,9 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
// Returns the function name for a texture sampling function for the specified image and sampling characteristics.
// For some subclasses, the function is a method on the specified image.
string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
bool has_array_offsets, bool has_offset, bool has_grad, bool, uint32_t lod)
string CompilerGLSL::to_function_name(uint32_t tex, const SPIRType &imgtype, bool is_fetch, bool is_gather,
bool is_proj, bool has_array_offsets, bool has_offset, bool has_grad, bool,
uint32_t lod)
{
string fname;
@ -3955,7 +3965,7 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is
// This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
bool workaround_lod_array_shadow_as_grad = false;
if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
imgtype.image.depth && lod)
image_is_comparison(imgtype, tex) && lod)
{
auto *constant_lod = maybe_get<SPIRConstant>(lod);
if (!constant_lod || constant_lod->scalar_f32() != 0.0f)
@ -3985,7 +3995,7 @@ string CompilerGLSL::to_function_name(uint32_t, const SPIRType &imgtype, bool is
if (has_offset)
fname += "Offset";
return is_legacy() ? legacy_tex_op(fname, imgtype, lod) : fname;
return is_legacy() ? legacy_tex_op(fname, imgtype, lod, tex) : fname;
}
std::string CompilerGLSL::convert_separate_image_to_combined(uint32_t id)
@ -4070,7 +4080,7 @@ string CompilerGLSL::to_function_args(uint32_t img, const SPIRType &imgtype, boo
// This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube.
bool workaround_lod_array_shadow_as_grad =
((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) &&
imgtype.image.depth && lod;
image_is_comparison(imgtype, img) && lod;
if (dref)
{
@ -4484,6 +4494,16 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
emit_binary_func_op(result_type, id, args[0], args[1], "interpolateAtOffset");
break;
case GLSLstd450NMin:
emit_binary_func_op(result_type, id, args[0], args[1], "unsupported_glsl450_nmin");
break;
case GLSLstd450NMax:
emit_binary_func_op(result_type, id, args[0], args[1], "unsupported_glsl450_nmax");
break;
case GLSLstd450NClamp:
emit_binary_func_op(result_type, id, args[0], args[1], "unsupported_glsl450_nclamp");
break;
default:
statement("// unimplemented GLSL op ", eop);
break;
@ -4802,7 +4822,7 @@ void CompilerGLSL::emit_subgroup_op(const Instruction &i)
break;
// clang-format off
#define GROUP_OP(op, glsl_op) \
#define GLSL_GROUP_OP(op, glsl_op) \
case OpGroupNonUniform##op: \
{ \
auto operation = static_cast<GroupOperation>(ops[3]); \
@ -4818,20 +4838,20 @@ case OpGroupNonUniform##op: \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
GROUP_OP(FAdd, Add)
GROUP_OP(FMul, Mul)
GROUP_OP(FMin, Min)
GROUP_OP(FMax, Max)
GROUP_OP(IAdd, Add)
GROUP_OP(IMul, Mul)
GROUP_OP(SMin, Min)
GROUP_OP(SMax, Max)
GROUP_OP(UMin, Min)
GROUP_OP(UMax, Max)
GROUP_OP(BitwiseAnd, And)
GROUP_OP(BitwiseOr, Or)
GROUP_OP(BitwiseXor, Xor)
#undef GROUP_OP
GLSL_GROUP_OP(FAdd, Add)
GLSL_GROUP_OP(FMul, Mul)
GLSL_GROUP_OP(FMin, Min)
GLSL_GROUP_OP(FMax, Max)
GLSL_GROUP_OP(IAdd, Add)
GLSL_GROUP_OP(IMul, Mul)
GLSL_GROUP_OP(SMin, Min)
GLSL_GROUP_OP(SMax, Max)
GLSL_GROUP_OP(UMin, Min)
GLSL_GROUP_OP(UMax, Max)
GLSL_GROUP_OP(BitwiseAnd, And)
GLSL_GROUP_OP(BitwiseOr, Or)
GLSL_GROUP_OP(BitwiseXor, Xor)
#undef GLSL_GROUP_OP
// clang-format on
case OpGroupNonUniformQuadSwap:
@ -4961,10 +4981,15 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
case BuiltInInstanceIndex:
if (options.vulkan_semantics)
return "gl_InstanceIndex";
else
else if (options.vertex.support_nonzero_base_instance)
return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
else
return "gl_InstanceID";
case BuiltInPrimitiveId:
return "gl_PrimitiveID";
if (storage == StorageClassInput && get_entry_point().model == ExecutionModelGeometry)
return "gl_PrimitiveIDIn";
else
return "gl_PrimitiveID";
case BuiltInInvocationId:
return "gl_InvocationID";
case BuiltInLayer:
@ -5119,16 +5144,10 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
if (!chain_only)
expr = to_enclosed_expression(base);
uint32_t type_id = expression_type_id(base);
const auto *type = &get<SPIRType>(type_id);
// Start traversing type hierarchy at the proper non-pointer types,
// but keep type_id referencing the original pointer for use below.
while (type->pointer)
{
assert(type->parent_type);
type = &get<SPIRType>(type->parent_type);
}
uint32_t type_id = expression_type_id(base);
const auto *type = &get_non_pointer_type(type_id);
bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos;
bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base);
@ -5571,14 +5590,8 @@ std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(con
bool *need_transpose,
uint32_t *out_matrix_stride)
{
const auto *type = &basetype;
// Start traversing type hierarchy at the proper non-pointer types.
while (type->pointer)
{
assert(type->parent_type);
type = &get<SPIRType>(type->parent_type);
}
const auto *type = &get_non_pointer_type(basetype);
// This holds the type of the current pointer which we are traversing through.
// We always start out from a struct type which is the block.
@ -6085,10 +6098,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
#define GLSL_BOP_CAST(op, type) \
emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, glsl_opcode_is_sign_invariant(opcode))
#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define GLSL_GLSL_BFOP_CAST(op, type) \
#define GLSL_BFOP_CAST(op, type) \
emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, glsl_opcode_is_sign_invariant(opcode))
#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
@ -6125,6 +6138,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
auto expr = to_expression(ptr);
// We might need to bitcast in order to load from a builtin.
bitcast_from_builtin_load(ptr, expr, get<SPIRType>(result_type));
if (ptr_expression)
ptr_expression->need_transpose = old_need_transpose;
@ -6182,11 +6198,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
else
{
auto rhs = to_expression(ops[1]);
// Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
if (!rhs.empty())
{
auto lhs = to_expression(ops[0]);
// We might need to bitcast in order to store to a builtin.
bitcast_to_builtin_store(ops[0], rhs, expression_type(ops[1]));
// Tries to optimize assignments like "<lhs> = <lhs> op expr".
// While this is purely cosmetic, this is important for legacy ESSL where loop
// variable increments must be in either i++ or i += const-expr.
@ -6852,7 +6872,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpIEqual:
{
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(equal, SPIRType::Int);
GLSL_BFOP_CAST(equal, SPIRType::Int);
else
GLSL_BOP_CAST(==, SPIRType::Int);
break;
@ -6871,7 +6891,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpINotEqual:
{
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(notEqual, SPIRType::Int);
GLSL_BFOP_CAST(notEqual, SPIRType::Int);
else
GLSL_BOP_CAST(!=, SPIRType::Int);
break;
@ -6892,7 +6912,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(greaterThan, type);
GLSL_BFOP_CAST(greaterThan, type);
else
GLSL_BOP_CAST(>, type);
break;
@ -6912,7 +6932,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(greaterThanEqual, type);
GLSL_BFOP_CAST(greaterThanEqual, type);
else
GLSL_BOP_CAST(>=, type);
break;
@ -6932,7 +6952,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(lessThan, type);
GLSL_BFOP_CAST(lessThan, type);
else
GLSL_BOP_CAST(<, type);
break;
@ -6952,7 +6972,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
GLSL_GLSL_BFOP_CAST(lessThanEqual, type);
GLSL_BFOP_CAST(lessThanEqual, type);
else
GLSL_BOP_CAST(<=, type);
break;
@ -7126,7 +7146,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
// Bitfield
case OpBitFieldInsert:
// TODO: The signedness of inputs is strict in GLSL, but not in SPIR-V, bitcast if necessary.
QFOP(bitfieldInsert);
GLSL_QFOP(bitfieldInsert);
break;
case OpBitFieldSExtract:
@ -7987,6 +8007,30 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
emit_subgroup_op(instruction);
break;
case OpFUnordEqual:
GLSL_BFOP(unsupported_FUnordEqual);
break;
case OpFUnordNotEqual:
GLSL_BFOP(unsupported_FUnordNotEqual);
break;
case OpFUnordLessThan:
GLSL_BFOP(unsupported_FUnordLessThan);
break;
case OpFUnordGreaterThan:
GLSL_BFOP(unsupported_FUnordGreaterThan);
break;
case OpFUnordLessThanEqual:
GLSL_BFOP(unsupported_FUnordLessThanEqual);
break;
case OpFUnordGreaterThanEqual:
GLSL_BFOP(unsupported_FUnordGreaterThanEqual);
break;
default:
statement("// unimplemented op ", instruction.op);
break;
@ -8375,7 +8419,7 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
}
}
string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */)
string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id)
{
auto &imagetype = get<SPIRType>(type.image.type);
string res;
@ -8448,8 +8492,11 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */)
}
// "Shadow" state in GLSL only exists for samplers and combined image samplers.
if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) && type.image.depth)
if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) &&
image_is_comparison(type, id))
{
res += "Shadow";
}
return res;
}
@ -8495,7 +8542,7 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
case SPIRType::Sampler:
// The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
// this distinction into the type system.
return comparison_samplers.count(id) ? "samplerShadow" : "sampler";
return comparison_ids.count(id) ? "samplerShadow" : "sampler";
case SPIRType::Void:
return "void";
@ -8713,13 +8760,8 @@ void CompilerGLSL::add_function_overload(const SPIRFunction &func)
// Parameters can vary with pointer type or not,
// but that will not change the signature in GLSL/HLSL,
// so strip the pointer type before hashing.
uint32_t type_id = arg.type;
auto *type = &get<SPIRType>(type_id);
while (type->pointer)
{
type_id = type->parent_type;
type = &get<SPIRType>(type_id);
}
uint32_t type_id = get_non_pointer_type_id(arg.type);
auto &type = get<SPIRType>(type_id);
if (!combined_image_samplers.empty())
{
@ -8727,8 +8769,8 @@ void CompilerGLSL::add_function_overload(const SPIRFunction &func)
// we pass down to callees, because they may be shuffled around.
// Ignore these arguments, to make sure that functions need to differ in some other way
// to be considered different overloads.
if (type->basetype == SPIRType::SampledImage ||
(type->basetype == SPIRType::Image && type->image.sampled == 1) || type->basetype == SPIRType::Sampler)
if (type.basetype == SPIRType::SampledImage ||
(type.basetype == SPIRType::Image && type.image.sampled == 1) || type.basetype == SPIRType::Sampler)
{
continue;
}
@ -9123,6 +9165,7 @@ void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uin
if (true_sub)
{
emit_block_hints(get<SPIRBlock>(from));
statement("if (", to_expression(cond), ")");
begin_scope();
branch(from, true_block);
@ -9146,6 +9189,7 @@ void CompilerGLSL::branch(uint32_t from, uint32_t cond, uint32_t true_block, uin
else if (false_sub && !true_sub)
{
// Only need false path, use negative conditional.
emit_block_hints(get<SPIRBlock>(from));
statement("if (!", to_enclosed_expression(cond), ")");
begin_scope();
branch(from, false_block);
@ -9374,6 +9418,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
{
// This block may be a dominating block, so make sure we flush undeclared variables before building the for loop header.
flush_undeclared_variables(block);
emit_block_hints(block);
// Important that we do this in this order because
// emitting the continue block can invalidate the condition expression.
@ -9392,6 +9437,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
case SPIRBlock::WhileLoop:
// This block may be a dominating block, so make sure we flush undeclared variables before building the while loop header.
flush_undeclared_variables(block);
emit_block_hints(block);
statement("while (", to_expression(block.condition), ")");
break;
@ -9439,11 +9485,13 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method
auto initializer = emit_for_loop_initializers(block);
auto condition = to_expression(child.condition);
auto continue_block = emit_continue_block(block.continue_block);
emit_block_hints(block);
statement("for (", initializer, "; ", condition, "; ", continue_block, ")");
break;
}
case SPIRBlock::WhileLoop:
emit_block_hints(block);
statement("while (", to_expression(child.condition), ")");
break;
@ -9654,35 +9702,65 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
auto &type = expression_type(block.condition);
bool uint32_t_case = type.basetype == SPIRType::UInt;
emit_block_hints(block);
statement("switch (", to_expression(block.condition), ")");
begin_scope();
// Multiple case labels can branch to same block, so find all unique blocks.
bool emitted_default = false;
unordered_set<uint32_t> emitted_blocks;
for (auto &c : block.cases)
{
auto case_value =
uint32_t_case ? convert_to_string(uint32_t(c.value)) : convert_to_string(int32_t(c.value));
statement("case ", case_value, ":");
if (emitted_blocks.count(c.block) != 0)
continue;
// Emit all case labels which branch to our target.
// FIXME: O(n^2), revisit if we hit shaders with 100++ case labels ...
for (auto &other_case : block.cases)
{
if (other_case.block == c.block)
{
auto case_value = uint32_t_case ? convert_to_string(uint32_t(other_case.value)) :
convert_to_string(int32_t(other_case.value));
statement("case ", case_value, ":");
}
}
// Maybe we share with default block?
if (block.default_block == c.block)
{
statement("default:");
emitted_default = true;
}
// Complete the target.
emitted_blocks.insert(c.block);
begin_scope();
branch(block.self, c.block);
end_scope();
}
if (block.default_block != block.next_block)
if (!emitted_default)
{
statement("default:");
begin_scope();
if (is_break(block.default_block))
SPIRV_CROSS_THROW("Cannot break; out of a switch statement and out of a loop at the same time ...");
branch(block.self, block.default_block);
end_scope();
}
else if (flush_phi_required(block.self, block.next_block))
{
statement("default:");
begin_scope();
flush_phi(block.self, block.next_block);
statement("break;");
end_scope();
if (block.default_block != block.next_block)
{
statement("default:");
begin_scope();
if (is_break(block.default_block))
SPIRV_CROSS_THROW("Cannot break; out of a switch statement and out of a loop at the same time ...");
branch(block.self, block.default_block);
end_scope();
}
else if (flush_phi_required(block.self, block.next_block))
{
statement("default:");
begin_scope();
flush_phi(block.self, block.next_block);
statement("break;");
end_scope();
}
}
end_scope();
@ -9874,3 +9952,70 @@ void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t rhs_id)
{
statement(lhs, " = ", to_expression(rhs_id), ";");
}
void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr,
const spirv_cross::SPIRType &expr_type)
{
// Only interested in standalone builtin variables.
if (!has_decoration(source_id, DecorationBuiltIn))
return;
auto builtin = static_cast<BuiltIn>(get_decoration(source_id, DecorationBuiltIn));
auto expected_type = expr_type.basetype;
// TODO: Fill in for more builtins.
switch (builtin)
{
case BuiltInLayer:
case BuiltInPrimitiveId:
case BuiltInViewportIndex:
case BuiltInInstanceId:
case BuiltInInstanceIndex:
case BuiltInVertexId:
case BuiltInVertexIndex:
case BuiltInSampleId:
expected_type = SPIRType::Int;
break;
default:
break;
}
if (expected_type != expr_type.basetype)
expr = bitcast_expression(expr_type, expected_type, expr);
}
void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr,
const spirv_cross::SPIRType &expr_type)
{
// Only interested in standalone builtin variables.
if (!has_decoration(target_id, DecorationBuiltIn))
return;
auto builtin = static_cast<BuiltIn>(get_decoration(target_id, DecorationBuiltIn));
auto expected_type = expr_type.basetype;
// TODO: Fill in for more builtins.
switch (builtin)
{
case BuiltInLayer:
case BuiltInPrimitiveId:
case BuiltInViewportIndex:
expected_type = SPIRType::Int;
break;
default:
break;
}
if (expected_type != expr_type.basetype)
{
auto type = expr_type;
type.basetype = expected_type;
expr = bitcast_expression(type, expr_type.basetype, expr);
}
}
void CompilerGLSL::emit_block_hints(const SPIRBlock &)
{
}

View File

@ -106,6 +106,11 @@ public:
// Inverts gl_Position.y or equivalent.
bool flip_vert_y = false;
// If true, the backend will assume that InstanceIndex will need to apply
// a base instance offset. Set to false if you know you will never use base instance
// functionality as it might remove some internal uniforms.
bool support_nonzero_base_instance = true;
} vertex;
struct
@ -277,7 +282,6 @@ protected:
{
for (uint32_t i = 0; i < indent; i++)
(*buffer) << " ";
statement_inner(std::forward<Ts>(ts)...);
(*buffer) << '\n';
}
@ -405,6 +409,9 @@ protected:
SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type,
uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type);
std::string to_ternary_expression(const SPIRType &result_type, uint32_t select, uint32_t true_value,
uint32_t false_value);
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
bool expression_is_forwarded(uint32_t id);
SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
@ -452,11 +459,11 @@ protected:
const char *format_to_glsl(spv::ImageFormat format);
virtual std::string layout_for_member(const SPIRType &type, uint32_t index);
virtual std::string to_interpolation_qualifiers(const Bitset &flags);
Bitset combined_decoration_for_member(const SPIRType &type, uint32_t index);
std::string layout_for_variable(const SPIRVariable &variable);
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
virtual bool skip_argument(uint32_t id) const;
virtual void emit_array_copy(const std::string &lhs, uint32_t rhs_id);
virtual void emit_block_hints(const SPIRBlock &block);
bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, uint32_t start_offset = 0,
uint32_t end_offset = UINT32_MAX);
@ -485,7 +492,7 @@ protected:
void replace_fragment_output(SPIRVariable &var);
void replace_fragment_outputs();
bool check_explicit_lod_allowed(uint32_t lod);
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod);
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t lod, uint32_t id);
uint32_t indent = 0;
@ -563,6 +570,12 @@ protected:
std::string convert_separate_image_to_combined(uint32_t id);
// Builtins in GLSL are always specific signedness, but the SPIR-V can declare them
// as either unsigned or signed.
// Sometimes we will need to automatically perform bitcasts on load and store to make this work.
virtual void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type);
virtual void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type);
private:
void init()
{

View File

@ -224,7 +224,7 @@ static bool hlsl_opcode_is_sign_invariant(Op opcode)
}
}
string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type)
string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t)
{
auto &imagetype = get<SPIRType>(type.image.type);
const char *dim = nullptr;
@ -275,7 +275,7 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type)
">");
}
string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type)
string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type, uint32_t id)
{
auto &imagetype = get<SPIRType>(type.image.type);
string res;
@ -338,18 +338,18 @@ string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type)
res += "MS";
if (type.image.arrayed)
res += "Array";
if (type.image.depth)
if (image_is_comparison(type, id))
res += "Shadow";
return res;
}
string CompilerHLSL::image_type_hlsl(const SPIRType &type)
string CompilerHLSL::image_type_hlsl(const SPIRType &type, uint32_t id)
{
if (hlsl_options.shader_model <= 30)
return image_type_hlsl_legacy(type);
return image_type_hlsl_legacy(type, id);
else
return image_type_hlsl_modern(type);
return image_type_hlsl_modern(type, id);
}
// The optional id parameter indicates the object whose type we are trying
@ -370,10 +370,10 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
case SPIRType::Image:
case SPIRType::SampledImage:
return image_type_hlsl(type);
return image_type_hlsl(type, id);
case SPIRType::Sampler:
return comparison_samplers.count(id) ? "SamplerComparisonState" : "SamplerState";
return comparison_ids.count(id) ? "SamplerComparisonState" : "SamplerState";
case SPIRType::Void:
return "void";
@ -1838,9 +1838,10 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
{
Bitset flags = get_buffer_block_flags(var);
bool is_readonly = flags.get(DecorationNonWritable);
bool is_coherent = flags.get(DecorationCoherent);
add_resource_name(var.self);
statement(is_readonly ? "ByteAddressBuffer " : "RWByteAddressBuffer ", to_name(var.self),
type_to_array_glsl(type), to_resource_binding(var), ";");
statement(is_coherent ? "globallycoherent " : "", is_readonly ? "ByteAddressBuffer " : "RWByteAddressBuffer ",
to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";");
}
else
{
@ -2059,7 +2060,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret
{
// Manufacture automatic sampler arg for SampledImage texture
decl += ", ";
decl += join(arg_type.image.depth ? "SamplerComparisonState " : "SamplerState ",
decl += join(image_is_comparison(arg_type, arg.id) ? "SamplerComparisonState " : "SamplerState ",
to_sampler_expression(arg.id), type_to_array_glsl(arg_type));
}
@ -2574,7 +2575,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
{
texop += img_expr;
if (imgtype.image.depth)
if (image_is_comparison(imgtype, img))
{
if (gather)
{
@ -2922,13 +2923,17 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var)
case SPIRType::SampledImage:
case SPIRType::Image:
{
statement(image_type_hlsl_modern(type), " ", to_name(var.self), type_to_array_glsl(type),
to_resource_binding(var), ";");
bool is_coherent = false;
if (type.basetype == SPIRType::Image && type.image.sampled == 2)
is_coherent = has_decoration(var.self, DecorationCoherent);
statement(is_coherent ? "globallycoherent " : "", image_type_hlsl_modern(type, var.self), " ",
to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";");
if (type.basetype == SPIRType::SampledImage && type.image.dim != DimBuffer)
{
// For combined image samplers, also emit a combined image sampler.
if (type.image.depth)
if (image_is_comparison(type, var.self))
statement("SamplerComparisonState ", to_sampler_expression(var.self), type_to_array_glsl(type),
to_resource_binding_sampler(var), ";");
else
@ -2939,7 +2944,7 @@ void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var)
}
case SPIRType::Sampler:
if (comparison_samplers.count(var.self))
if (comparison_ids.count(var.self))
statement("SamplerComparisonState ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var),
";");
else
@ -3524,14 +3529,8 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
else
base = to_expression(ops[2]);
auto *basetype = &type;
// Start traversing type hierarchy at the proper non-pointer types.
while (basetype->pointer)
{
assert(basetype->parent_type);
basetype = &get<SPIRType>(basetype->parent_type);
}
auto *basetype = &get_non_pointer_type(type);
// Traverse the type hierarchy down to the actual buffer types.
for (uint32_t i = 0; i < to_plain_buffer_length; i++)
@ -3767,7 +3766,7 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i)
}
// clang-format off
#define GROUP_OP(op, hlsl_op, supports_scan) \
#define HLSL_GROUP_OP(op, hlsl_op, supports_scan) \
case OpGroupNonUniform##op: \
{ \
auto operation = static_cast<GroupOperation>(ops[3]); \
@ -3787,20 +3786,20 @@ case OpGroupNonUniform##op: \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
GROUP_OP(FAdd, Sum, true)
GROUP_OP(FMul, Product, true)
GROUP_OP(FMin, Min, false)
GROUP_OP(FMax, Max, false)
GROUP_OP(IAdd, Sum, true)
GROUP_OP(IMul, Product, true)
GROUP_OP(SMin, Min, false)
GROUP_OP(SMax, Max, false)
GROUP_OP(UMin, Min, false)
GROUP_OP(UMax, Max, false)
GROUP_OP(BitwiseAnd, BitAnd, false)
GROUP_OP(BitwiseOr, BitOr, false)
GROUP_OP(BitwiseXor, BitXor, false)
#undef GROUP_OP
HLSL_GROUP_OP(FAdd, Sum, true)
HLSL_GROUP_OP(FMul, Product, true)
HLSL_GROUP_OP(FMin, Min, false)
HLSL_GROUP_OP(FMax, Max, false)
HLSL_GROUP_OP(IAdd, Sum, true)
HLSL_GROUP_OP(IMul, Product, true)
HLSL_GROUP_OP(SMin, Min, false)
HLSL_GROUP_OP(SMax, Max, false)
HLSL_GROUP_OP(UMin, Min, false)
HLSL_GROUP_OP(UMax, Max, false)
HLSL_GROUP_OP(BitwiseAnd, BitAnd, false)
HLSL_GROUP_OP(BitwiseOr, BitOr, false)
HLSL_GROUP_OP(BitwiseXor, BitXor, false)
#undef HLSL_GROUP_OP
// clang-format on
case OpGroupNonUniformQuadSwap:
@ -3839,7 +3838,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
#define HLSL_BOP_CAST(op, type) \
emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, hlsl_opcode_is_sign_invariant(opcode))
#define HLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define HLS_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define HLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define HLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define HLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define HLSL_BFOP_CAST(op, type) \
@ -4605,3 +4604,24 @@ string CompilerHLSL::compile()
return buffer->str();
}
void CompilerHLSL::emit_block_hints(const SPIRBlock &block)
{
switch (block.hint)
{
case SPIRBlock::HintFlatten:
statement("[flatten]");
break;
case SPIRBlock::HintDontFlatten:
statement("[branch]");
break;
case SPIRBlock::HintUnroll:
statement("[unroll]");
break;
case SPIRBlock::HintDontUnroll:
statement("[loop]");
break;
default:
break;
}
}

View File

@ -118,9 +118,9 @@ public:
private:
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string image_type_hlsl(const SPIRType &type);
std::string image_type_hlsl_modern(const SPIRType &type);
std::string image_type_hlsl_legacy(const SPIRType &type);
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
std::string image_type_hlsl_modern(const SPIRType &type, uint32_t id);
std::string image_type_hlsl_legacy(const SPIRType &type, uint32_t id);
void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override;
void emit_hlsl_entry_point();
void emit_header() override;
@ -158,6 +158,7 @@ private:
void emit_store(const Instruction &instruction);
void emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op);
void emit_subgroup_op(const Instruction &i) override;
void emit_block_hints(const SPIRBlock &block) override;
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier,
uint32_t base_offset = 0) override;

View File

@ -534,19 +534,44 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
// Add the global variables as arguments to the function
if (func_id != entry_point)
{
uint32_t next_id = increase_bound_by(uint32_t(added_arg_ids.size()));
for (uint32_t arg_id : added_arg_ids)
{
auto var = get<SPIRVariable>(arg_id);
auto &var = get<SPIRVariable>(arg_id);
uint32_t type_id = var.basetype;
func.add_parameter(type_id, next_id, true);
set<SPIRVariable>(next_id, type_id, StorageClassFunction, 0, arg_id);
auto *p_type = &get<SPIRType>(type_id);
// Ensure the existing variable has a valid name and the new variable has all the same meta info
set_name(arg_id, ensure_valid_name(to_name(arg_id), "v"));
meta[next_id] = meta[arg_id];
if (is_builtin_variable(var) && p_type->basetype == SPIRType::Struct)
{
// Get the non-pointer type
type_id = get_non_pointer_type_id(type_id);
p_type = &get<SPIRType>(type_id);
next_id++;
uint32_t mbr_idx = 0;
for (auto &mbr_type_id : p_type->member_types)
{
BuiltIn builtin;
bool is_builtin = is_member_builtin(*p_type, mbr_idx, &builtin);
if (is_builtin && has_active_builtin(builtin, var.storage))
{
// Add a arg variable with the same type and decorations as the member
uint32_t next_id = increase_bound_by(1);
func.add_parameter(mbr_type_id, next_id, true);
set<SPIRVariable>(next_id, mbr_type_id, StorageClassFunction);
meta[next_id].decoration = meta[type_id].members[mbr_idx];
}
mbr_idx++;
}
}
else
{
uint32_t next_id = increase_bound_by(1);
func.add_parameter(type_id, next_id, true);
set<SPIRVariable>(next_id, type_id, StorageClassFunction, 0, arg_id);
// Ensure the existing variable has a valid name and the new variable has all the same meta info
set_name(arg_id, ensure_valid_name(to_name(arg_id), "v"));
meta[next_id] = meta[arg_id];
}
}
}
}
@ -1148,6 +1173,18 @@ void CompilerMSL::emit_custom_functions()
statement("");
break;
case SPVFuncImplTexelBufferCoords:
{
string tex_width_str = convert_to_string(msl_options.texel_buffer_texture_width);
statement("// Returns 2D texture coords corresponding to 1D texel buffer coords");
statement("uint2 spvTexelBufferCoord(uint tc)");
begin_scope();
statement(join("return uint2(tc % ", tex_width_str, ", tc / ", tex_width_str, ");"));
end_scope();
statement("");
break;
}
case SPVFuncImplInverse4x4:
statement("// Returns the determinant of a 2x2 matrix.");
statement("inline float spvDet2x2(float a1, float a2, float b1, float b2)");
@ -1505,23 +1542,17 @@ void CompilerMSL::emit_specialization_constants()
// Override for MSL-specific syntax instructions
void CompilerMSL::emit_instruction(const Instruction &instruction)
{
#undef BOP
#undef BOP_CAST
#undef UOP
#undef QFOP
#undef TFOP
#undef BFOP
#undef BFOP_CAST
#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BOP_CAST(op, type) \
#define MSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define MSL_BOP_CAST(op, type) \
emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BFOP_CAST(op, type) \
#define MSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define MSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define MSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define MSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define MSL_BFOP_CAST(op, type) \
emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
#define MSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
auto ops = stream(instruction);
auto opcode = static_cast<Op>(instruction.op);
@ -1533,81 +1564,81 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
case OpIEqual:
case OpLogicalEqual:
case OpFOrdEqual:
BOP(==);
MSL_BOP(==);
break;
case OpINotEqual:
case OpLogicalNotEqual:
case OpFOrdNotEqual:
BOP(!=);
MSL_BOP(!=);
break;
case OpUGreaterThan:
case OpSGreaterThan:
case OpFOrdGreaterThan:
BOP(>);
MSL_BOP(>);
break;
case OpUGreaterThanEqual:
case OpSGreaterThanEqual:
case OpFOrdGreaterThanEqual:
BOP(>=);
MSL_BOP(>=);
break;
case OpULessThan:
case OpSLessThan:
case OpFOrdLessThan:
BOP(<);
MSL_BOP(<);
break;
case OpULessThanEqual:
case OpSLessThanEqual:
case OpFOrdLessThanEqual:
BOP(<=);
MSL_BOP(<=);
break;
// Derivatives
case OpDPdx:
case OpDPdxFine:
case OpDPdxCoarse:
UFOP(dfdx);
MSL_UFOP(dfdx);
register_control_dependent_expression(ops[1]);
break;
case OpDPdy:
case OpDPdyFine:
case OpDPdyCoarse:
UFOP(dfdy);
MSL_UFOP(dfdy);
register_control_dependent_expression(ops[1]);
break;
case OpFwidth:
case OpFwidthCoarse:
case OpFwidthFine:
UFOP(fwidth);
MSL_UFOP(fwidth);
register_control_dependent_expression(ops[1]);
break;
// Bitfield
case OpBitFieldInsert:
QFOP(insert_bits);
MSL_QFOP(insert_bits);
break;
case OpBitFieldSExtract:
case OpBitFieldUExtract:
TFOP(extract_bits);
MSL_TFOP(extract_bits);
break;
case OpBitReverse:
UFOP(reverse_bits);
MSL_UFOP(reverse_bits);
break;
case OpBitCount:
UFOP(popcount);
MSL_UFOP(popcount);
break;
case OpFRem:
BFOP(fmod);
MSL_BFOP(fmod);
break;
// Atomics
@ -1660,7 +1691,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
break;
}
#define AFMOImpl(op, valsrc) \
#define MSL_AFMO_IMPL(op, valsrc) \
do \
{ \
uint32_t result_type = ops[0]; \
@ -1671,45 +1702,45 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
emit_atomic_func_op(result_type, id, "atomic_fetch_" #op "_explicit", mem_sem, mem_sem, false, ptr, val); \
} while (false)
#define AFMO(op) AFMOImpl(op, ops[5])
#define AFMIO(op) AFMOImpl(op, 1)
#define MSL_AFMO(op) MSL_AFMO_IMPL(op, ops[5])
#define MSL_AFMIO(op) MSL_AFMO_IMPL(op, 1)
case OpAtomicIIncrement:
AFMIO(add);
MSL_AFMIO(add);
break;
case OpAtomicIDecrement:
AFMIO(sub);
MSL_AFMIO(sub);
break;
case OpAtomicIAdd:
AFMO(add);
MSL_AFMO(add);
break;
case OpAtomicISub:
AFMO(sub);
MSL_AFMO(sub);
break;
case OpAtomicSMin:
case OpAtomicUMin:
AFMO(min);
MSL_AFMO(min);
break;
case OpAtomicSMax:
case OpAtomicUMax:
AFMO(max);
MSL_AFMO(max);
break;
case OpAtomicAnd:
AFMO(and);
MSL_AFMO(and);
break;
case OpAtomicOr:
AFMO(or);
MSL_AFMO(or);
break;
case OpAtomicXor:
AFMO (xor);
MSL_AFMO (xor);
break;
// Images
@ -1833,7 +1864,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
break;
}
#define ImgQry(qrytype) \
#define MSL_ImgQry(qrytype) \
do \
{ \
uint32_t rslt_type_id = ops[0]; \
@ -1846,11 +1877,11 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
} while (false)
case OpImageQueryLevels:
ImgQry(mip_levels);
MSL_ImgQry(mip_levels);
break;
case OpImageQuerySamples:
ImgQry(samples);
MSL_ImgQry(samples);
break;
// Casting
@ -1932,7 +1963,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
e->need_transpose = true;
}
else
BOP(*);
MSL_BOP(*);
break;
}
@ -2435,8 +2466,9 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool
if (coord_type.vecsize > 1)
tex_coords += ".x";
// Metal texel buffer textures are 2D, so convert 1D coord to 2D.
if (is_fetch)
tex_coords = "uint2(" + round_fp_tex_coords(tex_coords, coord_is_fp) + ", 0)"; // Metal textures are 2D
tex_coords = "spvTexelBufferCoord(" + round_fp_tex_coords(tex_coords, coord_is_fp) + ")";
alt_coord = ".y";
@ -3559,17 +3591,13 @@ std::string CompilerMSL::sampler_type(const SPIRType &type)
SPIRV_CROSS_THROW("MSL 2.0 or greater is required for arrays of samplers.");
// Arrays of samplers in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
auto *parent = &type;
while (parent->pointer)
parent = &get<SPIRType>(parent->parent_type);
parent = &get<SPIRType>(parent->parent_type);
uint32_t array_size =
type.array_size_literal.back() ? type.array.back() : get<SPIRConstant>(type.array.back()).scalar();
if (array_size == 0)
SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL.");
return join("array<", sampler_type(*parent), ", ", array_size, ">");
auto &parent = get<SPIRType>(get_non_pointer_type(type).parent_type);
return join("array<", sampler_type(parent), ", ", array_size, ">");
}
else
return "sampler";
@ -3592,25 +3620,20 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
SPIRV_CROSS_THROW("MSL 2.0 or greater is required for arrays of textures.");
// Arrays of images in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
auto *parent = &type;
while (parent->pointer)
parent = &get<SPIRType>(parent->parent_type);
parent = &get<SPIRType>(parent->parent_type);
uint32_t array_size =
type.array_size_literal.back() ? type.array.back() : get<SPIRConstant>(type.array.back()).scalar();
if (array_size == 0)
SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL.");
return join("array<", image_type_glsl(*parent, id), ", ", array_size, ">");
auto &parent = get<SPIRType>(get_non_pointer_type(type).parent_type);
return join("array<", image_type_glsl(parent, id), ", ", array_size, ">");
}
string img_type_name;
// Bypass pointers because we need the real image struct
auto &img_type = get<SPIRType>(type.self).image;
bool shadow_image = comparison_images.count(id) != 0;
if (img_type.depth || shadow_image)
if (image_is_comparison(type, id))
{
switch (img_type.dim)
{
@ -4041,8 +4064,8 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o
auto &return_type = compiler.get<SPIRType>(args[0]);
if (!return_type.array.empty())
return SPVFuncImplArrayCopy;
else
return SPVFuncImplNone;
break;
}
case OpStore:
@ -4060,14 +4083,24 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o
else
{
// Or ... an expression.
if (result_types[id_rhs] != 0)
type = &compiler.get<SPIRType>(result_types[id_rhs]);
uint32_t tid = result_types[id_rhs];
if (tid)
type = &compiler.get<SPIRType>(tid);
}
if (type && compiler.is_array(*type))
return SPVFuncImplArrayCopy;
else
return SPVFuncImplNone;
break;
}
case OpImageFetch:
{
// Retrieve the image type, and if it's a Buffer, emit a texel coordinate function
uint32_t tid = result_types[args[2]];
if (tid && compiler.get<SPIRType>(tid).image.dim == DimBuffer)
return SPVFuncImplTexelBufferCoords;
break;
}
@ -4185,3 +4218,12 @@ void CompilerMSL::remap_constexpr_sampler(uint32_t id, const spirv_cross::MSLCon
SPIRV_CROSS_THROW("Can not remap array of samplers.");
constexpr_samplers[id] = sampler;
}
// MSL always declares builtins with their SPIR-V type.
void CompilerMSL::bitcast_from_builtin_load(uint32_t, std::string &, const spirv_cross::SPIRType &)
{
}
void CompilerMSL::bitcast_to_builtin_store(uint32_t, std::string &, const spirv_cross::SPIRType &)
{
}

View File

@ -153,6 +153,7 @@ public:
Platform platform = macOS;
uint32_t msl_version = make_msl_version(1, 2);
uint32_t texel_buffer_texture_width = 4096; // Width of 2D Metal textures used as 1D texel buffers
bool enable_point_size_builtin = true;
bool resolve_specialized_array_lengths = true;
@ -216,6 +217,7 @@ public:
SPVFuncImplFindSMsb,
SPVFuncImplFindUMsb,
SPVFuncImplArrayCopy,
SPVFuncImplTexelBufferCoords,
SPVFuncImplInverse4x4,
SPVFuncImplInverse3x3,
SPVFuncImplInverse2x2,
@ -357,6 +359,9 @@ protected:
void emit_entry_point_declarations() override;
uint32_t builtin_frag_coord_id = 0;
void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override;
Options msl_options;
std::set<SPVFuncImpl> spv_function_implementations;
std::unordered_map<uint32_t, MSLVertexAttr *> vtx_attrs_by_location;

573
deps/SPIRV-Cross/spirv_reflect.cpp vendored Normal file
View File

@ -0,0 +1,573 @@
/*
* Copyright 2018 Bradley Austin Davis
*
* 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.
*/
#include "spirv_reflect.hpp"
#include "spirv_glsl.hpp"
#include <iomanip>
using namespace spv;
using namespace spirv_cross;
using namespace std;
namespace simple_json
{
enum class Type
{
Object,
Array,
};
using State = std::pair<Type, bool>;
using Stack = std::stack<State>;
class Stream
{
Stack stack;
std::ostringstream buffer;
uint32_t indent{ 0 };
public:
void begin_json_object();
void end_json_object();
void emit_json_key(const std::string &key);
void emit_json_key_value(const std::string &key, const std::string &value);
void emit_json_key_value(const std::string &key, bool value);
void emit_json_key_value(const std::string &key, uint32_t value);
void emit_json_key_value(const std::string &key, int32_t value);
void emit_json_key_value(const std::string &key, float value);
void emit_json_key_object(const std::string &key);
void emit_json_key_array(const std::string &key);
void begin_json_array();
void end_json_array();
void emit_json_array_value(const std::string &value);
void emit_json_array_value(uint32_t value);
std::string str() const
{
return buffer.str();
}
private:
inline void statement_indent()
{
for (uint32_t i = 0; i < indent; i++)
buffer << " ";
}
template <typename T>
inline void statement_inner(T &&t)
{
buffer << std::forward<T>(t);
}
template <typename T, typename... Ts>
inline void statement_inner(T &&t, Ts &&... ts)
{
buffer << std::forward<T>(t);
statement_inner(std::forward<Ts>(ts)...);
}
template <typename... Ts>
inline void statement(Ts &&... ts)
{
statement_indent();
statement_inner(std::forward<Ts>(ts)...);
buffer << '\n';
}
template <typename... Ts>
void statement_no_return(Ts &&... ts)
{
statement_indent();
statement_inner(std::forward<Ts>(ts)...);
}
};
} // namespace simple_json
using namespace simple_json;
// Hackery to emit JSON without using nlohmann/json C++ library (which requires a
// higher level of compiler compliance than is required by SPIRV-Cross
void Stream::begin_json_array()
{
if (!stack.empty() && stack.top().second)
{
statement_inner(",\n");
}
statement("[");
++indent;
stack.emplace(Type::Array, false);
}
void Stream::end_json_array()
{
if (stack.empty() || stack.top().first != Type::Array)
SPIRV_CROSS_THROW("Invalid JSON state");
if (stack.top().second)
{
statement_inner("\n");
}
--indent;
statement_no_return("]");
stack.pop();
if (!stack.empty())
{
stack.top().second = true;
}
}
void Stream::emit_json_array_value(const std::string &value)
{
if (stack.empty() || stack.top().first != Type::Array)
SPIRV_CROSS_THROW("Invalid JSON state");
if (stack.top().second)
statement_inner(",\n");
statement_no_return("\"", value, "\"");
stack.top().second = true;
}
void Stream::emit_json_array_value(uint32_t value)
{
if (stack.empty() || stack.top().first != Type::Array)
SPIRV_CROSS_THROW("Invalid JSON state");
if (stack.top().second)
statement_inner(",\n");
statement_no_return(std::to_string(value));
stack.top().second = true;
}
void Stream::begin_json_object()
{
if (!stack.empty() && stack.top().second)
{
statement_inner(",\n");
}
statement("{");
++indent;
stack.emplace(Type::Object, false);
}
void Stream::end_json_object()
{
if (stack.empty() || stack.top().first != Type::Object)
SPIRV_CROSS_THROW("Invalid JSON state");
if (stack.top().second)
{
statement_inner("\n");
}
--indent;
statement_no_return("}");
stack.pop();
if (!stack.empty())
{
stack.top().second = true;
}
}
void Stream::emit_json_key(const std::string &key)
{
if (stack.empty() || stack.top().first != Type::Object)
SPIRV_CROSS_THROW("Invalid JSON state");
if (stack.top().second)
statement_inner(",\n");
statement_no_return("\"", key, "\" : ");
stack.top().second = true;
}
void Stream::emit_json_key_value(const std::string &key, const std::string &value)
{
emit_json_key(key);
statement_inner("\"", value, "\"");
}
void Stream::emit_json_key_value(const std::string &key, uint32_t value)
{
emit_json_key(key);
statement_inner(value);
}
void Stream::emit_json_key_value(const std::string &key, int32_t value)
{
emit_json_key(key);
statement_inner(value);
}
void Stream::emit_json_key_value(const std::string &key, float value)
{
emit_json_key(key);
statement_inner(value);
}
void Stream::emit_json_key_value(const std::string &key, bool value)
{
emit_json_key(key);
statement_inner(value ? "true" : "false");
}
void Stream::emit_json_key_object(const std::string &key)
{
emit_json_key(key);
statement_inner("{\n");
++indent;
stack.emplace(Type::Object, false);
}
void Stream::emit_json_key_array(const std::string &key)
{
emit_json_key(key);
statement_inner("[\n");
++indent;
stack.emplace(Type::Array, false);
}
void CompilerReflection::set_format(const std::string &format)
{
if (format != "json")
{
SPIRV_CROSS_THROW("Unsupported format");
}
}
string CompilerReflection::compile()
{
// Force a classic "C" locale, reverts when function returns
ClassicLocale classic_locale;
// Move constructor for this type is broken on GCC 4.9 ...
json_stream = std::make_shared<simple_json::Stream>();
json_stream->begin_json_object();
emit_entry_points();
emit_types();
emit_resources();
emit_specialization_constants();
json_stream->end_json_object();
return json_stream->str();
}
void CompilerReflection::emit_types()
{
bool emitted_open_tag = false;
for (auto &id : ids)
{
auto idType = id.get_type();
if (idType == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Struct && !type.pointer && type.array.empty())
{
emit_type(type, emitted_open_tag);
}
}
}
if (emitted_open_tag)
{
json_stream->end_json_object();
}
}
void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag)
{
auto name = type_to_glsl(type);
if (type.type_alias != 0)
return;
if (!emitted_open_tag)
{
json_stream->emit_json_key_object("types");
emitted_open_tag = true;
}
json_stream->emit_json_key_object("_" + std::to_string(type.self));
json_stream->emit_json_key_value("name", name);
json_stream->emit_json_key_array("members");
// FIXME ideally we'd like to emit the size of a structure as a
// convenience to people parsing the reflected JSON. The problem
// is that there's no implicit size for a type. It's final size
// will be determined by the top level declaration in which it's
// included. So there might be one size for the struct if it's
// included in a std140 uniform block and another if it's included
// in a std430 uniform block.
// The solution is to include *all* potential sizes as a map of
// layout type name to integer, but that will probably require
// some additional logic being written in this class, or in the
// parent CompilerGLSL class.
auto size = type.member_types.size();
for (uint32_t i = 0; i < size; ++i)
{
emit_type_member(type, i);
}
json_stream->end_json_array();
json_stream->end_json_object();
}
void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index)
{
auto &membertype = get<SPIRType>(type.member_types[index]);
json_stream->begin_json_object();
auto name = to_member_name(type, index);
// FIXME we'd like to emit the offset of each member, but such offsets are
// context dependent. See the comment above regarding structure sizes
json_stream->emit_json_key_value("name", name);
if (membertype.basetype == SPIRType::Struct)
{
json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self));
}
else
{
json_stream->emit_json_key_value("type", type_to_glsl(membertype));
}
emit_type_member_qualifiers(type, index);
json_stream->end_json_object();
}
void CompilerReflection::emit_type_array(const SPIRType &type)
{
if (!type.array.empty())
{
json_stream->emit_json_key_array("array");
// Note that we emit the zeros here as a means of identifying
// unbounded arrays. This is necessary as otherwise there would
// be no way of differentiating between float[4] and float[4][]
for (const auto &value : type.array)
json_stream->emit_json_array_value(value);
json_stream->end_json_array();
}
}
void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index)
{
auto flags = combined_decoration_for_member(type, index);
if (flags.get(DecorationRowMajor))
json_stream->emit_json_key_value("row_major", true);
auto &membertype = get<SPIRType>(type.member_types[index]);
emit_type_array(membertype);
auto &memb = meta[type.self].members;
if (index < memb.size())
{
auto &dec = memb[index];
if (dec.decoration_flags.get(DecorationLocation))
json_stream->emit_json_key_value("location", dec.location);
if (dec.decoration_flags.get(DecorationOffset))
json_stream->emit_json_key_value("offset", dec.offset);
}
}
string CompilerReflection::execution_model_to_str(spv::ExecutionModel model)
{
switch (model)
{
case spv::ExecutionModelVertex:
return "vert";
case spv::ExecutionModelTessellationControl:
return "tesc";
case ExecutionModelTessellationEvaluation:
return "tese";
case ExecutionModelGeometry:
return "geom";
case ExecutionModelFragment:
return "frag";
case ExecutionModelGLCompute:
return "comp";
default:
return "???";
}
}
// FIXME include things like the local_size dimensions, geometry output vertex count, etc
void CompilerReflection::emit_entry_points()
{
auto entries = get_entry_points_and_stages();
if (!entries.empty())
{
json_stream->emit_json_key_array("entryPoints");
for (auto &e : entries)
{
json_stream->begin_json_object();
json_stream->emit_json_key_value("name", e.name);
json_stream->emit_json_key_value("mode", execution_model_to_str(e.execution_model));
json_stream->end_json_object();
}
json_stream->end_json_array();
}
}
void CompilerReflection::emit_resources()
{
auto res = get_shader_resources();
emit_resources("subpass_inputs", res.subpass_inputs);
emit_resources("inputs", res.stage_inputs);
emit_resources("outputs", res.stage_outputs);
emit_resources("textures", res.sampled_images);
emit_resources("separate_images", res.separate_images);
emit_resources("separate_samplers", res.separate_samplers);
emit_resources("images", res.storage_images);
emit_resources("ssbos", res.storage_buffers);
emit_resources("ubos", res.uniform_buffers);
emit_resources("push_constants", res.push_constant_buffers);
emit_resources("counters", res.atomic_counters);
}
void CompilerReflection::emit_resources(const char *tag, const vector<Resource> &resources)
{
if (resources.empty())
{
return;
}
json_stream->emit_json_key_array(tag);
for (auto &res : resources)
{
auto &type = get_type(res.type_id);
auto typeflags = meta[type.self].decoration.decoration_flags;
auto &mask = get_decoration_bitset(res.id);
// If we don't have a name, use the fallback for the type instead of the variable
// for SSBOs and UBOs since those are the only meaningful names to use externally.
// Push constant blocks are still accessed by name and not block name, even though they are technically Blocks.
bool is_push_constant = get_storage_class(res.id) == StorageClassPushConstant;
bool is_block = get_decoration_bitset(type.self).get(DecorationBlock) ||
get_decoration_bitset(type.self).get(DecorationBufferBlock);
uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id;
json_stream->begin_json_object();
if (type.basetype == SPIRType::Struct)
{
json_stream->emit_json_key_value("type", "_" + std::to_string(res.base_type_id));
}
else
{
json_stream->emit_json_key_value("type", type_to_glsl(type));
}
json_stream->emit_json_key_value("name", !res.name.empty() ? res.name : get_fallback_name(fallback_id));
{
bool ssbo_block = type.storage == StorageClassStorageBuffer ||
(type.storage == StorageClassUniform && typeflags.get(DecorationBufferBlock));
if (ssbo_block)
{
auto buffer_flags = get_buffer_block_flags(res.id);
if (buffer_flags.get(DecorationNonReadable))
json_stream->emit_json_key_value("writeonly", true);
if (buffer_flags.get(DecorationNonWritable))
json_stream->emit_json_key_value("readonly", true);
if (buffer_flags.get(DecorationRestrict))
json_stream->emit_json_key_value("restrict", true);
if (buffer_flags.get(DecorationCoherent))
json_stream->emit_json_key_value("coherent", true);
}
}
emit_type_array(type);
{
bool is_sized_block = is_block && (get_storage_class(res.id) == StorageClassUniform ||
get_storage_class(res.id) == StorageClassUniformConstant);
if (is_sized_block)
{
uint32_t block_size = uint32_t(get_declared_struct_size(get_type(res.base_type_id)));
json_stream->emit_json_key_value("block_size", block_size);
}
}
if (type.storage == StorageClassPushConstant)
json_stream->emit_json_key_value("push_constant", true);
if (mask.get(DecorationLocation))
json_stream->emit_json_key_value("location", get_decoration(res.id, DecorationLocation));
if (mask.get(DecorationRowMajor))
json_stream->emit_json_key_value("row_major", true);
if (mask.get(DecorationColMajor))
json_stream->emit_json_key_value("column_major", true);
if (mask.get(DecorationIndex))
json_stream->emit_json_key_value("index", get_decoration(res.id, DecorationIndex));
if (type.storage != StorageClassPushConstant && mask.get(DecorationDescriptorSet))
json_stream->emit_json_key_value("set", get_decoration(res.id, DecorationDescriptorSet));
if (mask.get(DecorationBinding))
json_stream->emit_json_key_value("binding", get_decoration(res.id, DecorationBinding));
if (mask.get(DecorationInputAttachmentIndex))
json_stream->emit_json_key_value("input_attachment_index",
get_decoration(res.id, DecorationInputAttachmentIndex));
if (mask.get(DecorationOffset))
json_stream->emit_json_key_value("offset", get_decoration(res.id, DecorationOffset));
// For images, the type itself adds a layout qualifer.
// Only emit the format for storage images.
if (type.basetype == SPIRType::Image && type.image.sampled == 2)
{
const char *fmt = format_to_glsl(type.image.format);
if (fmt != nullptr)
json_stream->emit_json_key_value("format", std::string(fmt));
}
json_stream->end_json_object();
}
json_stream->end_json_array();
}
void CompilerReflection::emit_specialization_constants()
{
auto specialization_constants = get_specialization_constants();
if (specialization_constants.empty())
return;
json_stream->emit_json_key_array("specialization_constants");
for (const auto spec_const : specialization_constants)
{
auto &c = get<SPIRConstant>(spec_const.id);
auto type = get<SPIRType>(c.constant_type);
json_stream->begin_json_object();
json_stream->emit_json_key_value("id", spec_const.constant_id);
json_stream->emit_json_key_value("type", type_to_glsl(type));
switch (type.basetype)
{
case SPIRType::UInt:
json_stream->emit_json_key_value("default_value", c.scalar());
break;
case SPIRType::Int:
json_stream->emit_json_key_value("default_value", c.scalar_i32());
break;
case SPIRType::Float:
json_stream->emit_json_key_value("default_value", c.scalar_f32());
break;
case SPIRType::Boolean:
json_stream->emit_json_key_value("default_value", c.scalar() != 0);
break;
default:
break;
}
json_stream->end_json_object();
}
json_stream->end_json_array();
}
string CompilerReflection::to_member_name(const SPIRType &type, uint32_t index) const
{
auto &memb = meta[type.self].members;
if (index < memb.size() && !memb[index].alias.empty())
return memb[index].alias;
else
return join("_m", index);
}

72
deps/SPIRV-Cross/spirv_reflect.hpp vendored Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright 2018 Bradley Austin Davis
*
* 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 SPIRV_CROSS_REFLECT_HPP
#define SPIRV_CROSS_REFLECT_HPP
#include "spirv_glsl.hpp"
#include <utility>
#include <vector>
namespace simple_json
{
class Stream;
}
namespace spirv_cross
{
class CompilerReflection : public CompilerGLSL
{
using Parent = CompilerGLSL;
public:
CompilerReflection(std::vector<uint32_t> spirv_)
: Parent(move(spirv_))
{
options.vulkan_semantics = true;
}
CompilerReflection(const uint32_t *ir, size_t word_count)
: Parent(ir, word_count)
{
options.vulkan_semantics = true;
}
void set_format(const std::string &format);
std::string compile() override;
private:
static std::string execution_model_to_str(spv::ExecutionModel model);
void emit_entry_points();
void emit_types();
void emit_resources();
void emit_specialization_constants();
void emit_type(const SPIRType &type, bool &emitted_open_tag);
void emit_type_member(const SPIRType &type, uint32_t index);
void emit_type_member_qualifiers(const SPIRType &type, uint32_t index);
void emit_type_array(const SPIRType &type);
void emit_resources(const char *tag, const std::vector<Resource> &resources);
std::string to_member_name(const SPIRType &type, uint32_t index) const;
std::shared_ptr<simple_json::Stream> json_stream;
};
} // namespace spirv_cross
#endif

View File

@ -11,8 +11,13 @@ import hashlib
import shutil
import argparse
import codecs
import json
import multiprocessing
import errno
from functools import partial
force_no_external_validation = False
backend = 'glsl'
args = {}
def remove_file(path):
#print('Removing file:', path)
@ -78,7 +83,7 @@ def print_msl_compiler_version():
subprocess.check_call(['xcrun', '--sdk', 'iphoneos', 'metal', '--version'])
print('...are the Metal compiler characteristics.\n') # display after so xcrun FNF is silent
except OSError as e:
if (e.errno != os.errno.ENOENT): # Ignore xcrun not found error
if (e.errno != errno.ENOENT): # Ignore xcrun not found error
raise
def validate_shader_msl(shader, opt):
@ -90,7 +95,7 @@ def validate_shader_msl(shader, opt):
subprocess.check_call(['xcrun', '--sdk', msl_os, 'metal', '-x', 'metal', '-std=osx-metal{}'.format('2.0' if msl2 else '1.2'), '-Werror', '-Wno-unused-variable', msl_path])
print('Compiled Metal shader: ' + msl_path) # display after so xcrun FNF is silent
except OSError as oe:
if (oe.errno != os.errno.ENOENT): # Ignore xcrun not found error
if (oe.errno != errno.ENOENT): # Ignore xcrun not found error
raise
except subprocess.CalledProcessError:
print('Error compiling Metal shader: ' + msl_path)
@ -140,7 +145,7 @@ def shader_to_win_path(shader):
stdout_data, stderr_data = f.communicate()
return stdout_data.decode('utf-8')
except OSError as oe:
if (oe.errno != os.errno.ENOENT): # Ignore not found errors
if (oe.errno != errno.ENOENT): # Ignore not found errors
return shader
except subprocess.CalledProcessError:
raise
@ -152,12 +157,12 @@ def validate_shader_hlsl(shader):
subprocess.check_call(['glslangValidator', '-e', 'main', '-D', '--target-env', 'vulkan1.1', '-V', shader])
is_no_fxc = '.nofxc.' in shader
global ignore_fxc
if (not ignore_fxc) and (not force_no_external_validation) and (not is_no_fxc):
if (not ignore_fxc) and (not args.force_no_external_validation) and (not is_no_fxc):
try:
win_path = shader_to_win_path(shader)
subprocess.check_call(['fxc', '-nologo', shader_model_hlsl(shader), win_path])
except OSError as oe:
if (oe.errno != os.errno.ENOENT): # Ignore not found errors
if (oe.errno != errno.ENOENT): # Ignore not found errors
raise
else:
ignore_fxc = True
@ -199,6 +204,24 @@ def cross_compile_hlsl(shader, spirv, opt):
return (spirv_path, hlsl_path)
def cross_compile_reflect(shader, spirv, opt):
spirv_path = create_temporary()
reflect_path = create_temporary(os.path.basename(shader))
if spirv:
subprocess.check_call(['spirv-as', '-o', spirv_path, shader])
else:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', '-o', spirv_path, shader])
if opt:
subprocess.check_call(['spirv-opt', '-O', '-o', spirv_path, spirv_path])
spirv_cross_path = './spirv-cross'
sm = shader_to_sm(shader)
subprocess.check_call([spirv_cross_path, '--entry', 'main', '--output', reflect_path, spirv_path, '--reflect'])
return (spirv_path, reflect_path)
def validate_shader(shader, vulkan):
if vulkan:
subprocess.check_call(['glslangValidator', '--target-env', 'vulkan1.1', '-V', shader])
@ -277,6 +300,58 @@ def reference_path(directory, relpath, opt):
reference_dir = os.path.join(reference_dir, split_paths[1])
return os.path.join(reference_dir, relpath)
def json_ordered(obj):
if isinstance(obj, dict):
return sorted((k, json_ordered(v)) for k, v in obj.items())
if isinstance(obj, list):
return sorted(json_ordered(x) for x in obj)
else:
return obj
def json_compare(json_a, json_b):
return json_ordered(json_a) == json_ordered(json_b)
def regression_check_reflect(shader, json_file, update, keep, opt):
reference = reference_path(shader[0], shader[1], opt) + '.json'
joined_path = os.path.join(shader[0], shader[1])
print('Reference shader reflection path:', reference)
if os.path.exists(reference):
actual = ''
expected = ''
with open(json_file) as f:
actual_json = f.read();
actual = json.loads(actual_json)
with open(reference) as f:
expected = json.load(f)
if (json_compare(actual, expected) != True):
if update:
print('Generated reflection json has changed for {}!'.format(reference))
# If we expect changes, update the reference file.
if os.path.exists(reference):
remove_file(reference)
make_reference_dir(reference)
shutil.move(json_file, reference)
else:
print('Generated reflection json in {} does not match reference {}!'.format(json_file, reference))
with open(json_file, 'r') as f:
print('')
print('Generated:')
print('======================')
print(f.read())
print('======================')
print('')
# Otherwise, fail the test. Keep the shader file around so we can inspect.
if not keep:
remove_file(json_file)
sys.exit(1)
else:
remove_file(json_file)
else:
print('Found new shader {}. Placing generated source code in {}'.format(joined_path, reference))
make_reference_dir(reference)
shutil.move(json_file, reference)
def regression_check(shader, glsl, update, keep, opt):
reference = reference_path(shader[0], shader[1], opt)
joined_path = os.path.join(shader[0], shader[1])
@ -396,7 +471,7 @@ def test_shader_msl(stats, shader, update, keep, opt):
# executable from Xcode using args: `--msl --entry main --output msl_path spirv_path`.
# print('SPRIV shader: ' + spirv)
if not force_no_external_validation:
if not args.force_no_external_validation:
validate_shader_msl(shader, opt)
remove_file(spirv)
@ -410,26 +485,50 @@ def test_shader_hlsl(stats, shader, update, keep, opt):
regression_check(shader, hlsl, update, keep, opt)
remove_file(spirv)
def test_shaders_helper(stats, shader_dir, update, malisc, keep, opt, backend):
for root, dirs, files in os.walk(os.path.join(shader_dir)):
def test_shader_reflect(stats, shader, update, keep, opt):
joined_path = os.path.join(shader[0], shader[1])
print('Testing shader reflection:', joined_path)
is_spirv = shader_is_spirv(shader[1])
noopt = shader_is_noopt(shader[1])
spirv, reflect = cross_compile_reflect(joined_path, is_spirv, opt and (not noopt))
regression_check_reflect(shader, reflect, update, keep, opt)
remove_file(spirv)
def test_shader_file(relpath, stats, shader_dir, update, keep, opt, backend):
if backend == 'msl':
test_shader_msl(stats, (shader_dir, relpath), update, keep, opt)
elif backend == 'hlsl':
test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt)
elif backend == 'reflect':
test_shader_reflect(stats, (shader_dir, relpath), update, keep, opt)
else:
test_shader(stats, (shader_dir, relpath), update, keep, opt)
def test_shaders_helper(stats):
all_files = []
for root, dirs, files in os.walk(os.path.join(args.folder)):
files = [ f for f in files if not f.startswith(".") ] #ignore system files (esp OSX)
for i in files:
path = os.path.join(root, i)
relpath = os.path.relpath(path, shader_dir)
if backend == 'msl':
test_shader_msl(stats, (shader_dir, relpath), update, keep, opt)
elif backend == 'hlsl':
test_shader_hlsl(stats, (shader_dir, relpath), update, keep, opt)
else:
test_shader(stats, (shader_dir, relpath), update, keep, opt)
relpath = os.path.relpath(path, args.folder)
all_files.append(relpath)
def test_shaders(shader_dir, update, malisc, keep, opt, backend):
if malisc:
# The child processes in parallel execution mode don't have the proper state for the global args variable, so
# at this point we need to switch to explicit arguments
if args.parallel:
pool = multiprocessing.Pool(multiprocessing.cpu_count())
pool.map(partial(test_shader_file, stats=stats, shader_dir=args.folder, update=args.update, keep=args.keep, opt=args.opt, backend=backend), all_files)
else:
for i in all_files:
test_shader_file(i, stats, args.folder, args.update, args.keep, args.opt, backend)
def test_shaders():
if args.malisc:
with open('stats.csv', 'w') as stats:
print('Shader,OrigRegs,OrigUniRegs,OrigALUShort,OrigLSShort,OrigTEXShort,OrigALULong,OrigLSLong,OrigTEXLong,CrossRegs,CrossUniRegs,CrossALUShort,CrossLSShort,CrossTEXShort,CrossALULong,CrossLSLong,CrossTEXLong', file = stats)
test_shaders_helper(stats, shader_dir, update, malisc, keep, backend)
test_shaders_helper(stats)
else:
test_shaders_helper(None, shader_dir, update, malisc, keep, opt, backend)
test_shaders_helper(None)
def main():
parser = argparse.ArgumentParser(description = 'Script for regression testing.')
@ -459,19 +558,35 @@ def main():
parser.add_argument('--opt',
action = 'store_true',
help = 'Run SPIRV-Tools optimization passes as well.')
parser.add_argument('--reflect',
action = 'store_true',
help = 'Test reflection backend.')
parser.add_argument('--parallel',
action = 'store_true',
help = 'Execute tests in parallel. Useful for doing regression quickly, but bad for debugging and stat output.')
global args
args = parser.parse_args()
if not args.folder:
sys.stderr.write('Need shader folder.\n')
sys.exit(1)
if (args.parallel and (args.malisc or args.force_no_external_validation or args.update)):
sys.stderr.write('Parallel execution is disabled when using the flags --update, --malisc or --force-no-external-validation\n')
args.parallel = False
if args.msl:
print_msl_compiler_version()
global force_no_external_validation
force_no_external_validation = args.force_no_external_validation
global backend
if (args.msl or args.metal):
backend = 'msl'
elif args.hlsl:
backend = 'hlsl'
elif args.reflect:
backend = 'reflect'
test_shaders(args.folder, args.update, args.malisc, args.keep, args.opt, 'msl' if (args.msl or args.metal) else ('hlsl' if args.hlsl else 'glsl'))
test_shaders()
if args.malisc:
print('Stats in stats.csv!')
print('Tests completed!')

View File

@ -16,4 +16,5 @@ echo "Using spirv-opt in: $(which spirv-opt)."
./test_shaders.py shaders-hlsl --hlsl || exit 1
./test_shaders.py shaders-hlsl --hlsl --opt || exit 1
./test_shaders.py shaders-hlsl-no-opt --hlsl || exit 1
./test_shaders.py shaders-reflection --reflect || exit 1

View File

@ -16,5 +16,6 @@ echo "Using spirv-opt in: $(which spirv-opt)."
./test_shaders.py shaders-hlsl --update --hlsl || exit 1
./test_shaders.py shaders-hlsl --update --hlsl --opt || exit 1
./test_shaders.py shaders-hlsl-no-opt --update --hlsl || exit 1
./test_shaders.py shaders-reflection --reflect --update || exit 1