Merge pull request #8 from KhronosGroup/integer-bitcast-ops

Better handling of bitcasts within integer operations
This commit is contained in:
Hans-Kristian Arntzen 2016-05-13 15:35:22 +02:00
commit 5c16c885c0
20 changed files with 924 additions and 40 deletions

View File

@ -13,9 +13,9 @@ DEPS := $(OBJECTS:.o=.d) $(CLI_OBJECTS:.o=.d)
CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow CXXFLAGS += -std=c++11 -Wall -Wextra -Wshadow
ifeq ($(DEBUG), 1) ifeq ($(DEBUG), 1)
CXXFLAGS += -O0 CXXFLAGS += -O0 -g
else else
CXXFLAGS += -O2 CXXFLAGS += -O2 -g
endif endif
all: $(TARGET) all: $(TARGET)

View File

@ -17,8 +17,6 @@ The goal is to emit GLSL or MSL that looks like it was written by a human and no
NOTE: Individual features are expected to be mostly complete, but it is possible that certain obscure GLSL features are not yet supported. NOTE: Individual features are expected to be mostly complete, but it is possible that certain obscure GLSL features are not yet supported.
However, most missing features are expected to be "trivial" improvements at this stage. However, most missing features are expected to be "trivial" improvements at this stage.
Occasionally, missing features is due to glslangValidator's lack of proper support for that feature making testing hard.
## Building ## Building
SPIRV-Cross has been tested on Linux, OSX and Windows. SPIRV-Cross has been tested on Linux, OSX and Windows.
@ -125,7 +123,7 @@ glslangValidator then back through SPIRV-Cross again. The reference files are st
All pull requests should ensure that test output does not change unexpectedly. This can be tested with `./test_shaders.py shaders`. All pull requests should ensure that test output does not change unexpectedly. This can be tested with `./test_shaders.py shaders`.
However, when improving SPIRV-Cross there are of course legitimate cases where reference output should change. However, when improving SPIRV-Cross there are of course legitimate cases where reference output should change.
In these cases, run `./test_shaders.py shaders --update` to update the reference files and include these changes as part of the pull request. In these cases, run `./test_shaders.py shaders --update` to update the reference files and include these changes as part of the pull request.
Always make sure you are running up to date glslangValidator when updating reference files. Always make sure you are running up to date glslangValidator as well as SPIRV-Tools when updating reference files.
In short, the master branch should always be able to run `./test_shaders.py shaders` without failure. In short, the master branch should always be able to run `./test_shaders.py shaders` without failure.

View File

@ -0,0 +1,27 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
_6._0 = (_5._1 + uvec4(_5._0));
_6._0 = (uvec4(_5._0) + _5._1);
_6._0 = (_5._1 + _5._1);
_6._0 = uvec4(_5._0 + _5._0);
_6._1 = ivec4(_5._1 + _5._1);
_6._1 = (_5._0 + _5._0);
_6._1 = (ivec4(_5._1) + _5._0);
_6._1 = (_5._0 + ivec4(_5._1));
}

View File

@ -0,0 +1,31 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
bvec4 _34 = equal(ivec4(_5._1), _5._0);
bvec4 _35 = equal(_5._0, ivec4(_5._1));
bvec4 _36 = equal(_5._1, _5._1);
bvec4 _37 = equal(_5._0, _5._0);
_6._0 = mix(uvec4(0u), uvec4(1u), _34);
_6._0 = mix(uvec4(0u), uvec4(1u), _35);
_6._0 = mix(uvec4(0u), uvec4(1u), _36);
_6._0 = mix(uvec4(0u), uvec4(1u), _37);
_6._1 = mix(ivec4(0), ivec4(1), _34);
_6._1 = mix(ivec4(0), ivec4(1), _35);
_6._1 = mix(ivec4(0), ivec4(1), _36);
_6._1 = mix(ivec4(0), ivec4(1), _37);
}

View File

@ -0,0 +1,27 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
_6._0 = uvec4(ivec4(_5._1) >> _5._0);
_6._0 = uvec4(_5._0 >> ivec4(_5._1));
_6._0 = uvec4(ivec4(_5._1) >> ivec4(_5._1));
_6._0 = uvec4(_5._0 >> _5._0);
_6._1 = (ivec4(_5._1) >> ivec4(_5._1));
_6._1 = (_5._0 >> _5._0);
_6._1 = (ivec4(_5._1) >> _5._0);
_6._1 = (_5._0 >> ivec4(_5._1));
}

View File

@ -0,0 +1,27 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
_6._0 = uvec4(ivec4(_5._1) / _5._0);
_6._0 = uvec4(_5._0 / ivec4(_5._1));
_6._0 = uvec4(ivec4(_5._1) / ivec4(_5._1));
_6._0 = uvec4(_5._0 / _5._0);
_6._1 = (ivec4(_5._1) / ivec4(_5._1));
_6._1 = (_5._0 / _5._0);
_6._1 = (ivec4(_5._1) / _5._0);
_6._1 = (_5._0 / ivec4(_5._1));
}

View File

@ -0,0 +1,27 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
_6._0 = (_5._1 >> uvec4(_5._0));
_6._0 = (uvec4(_5._0) >> _5._1);
_6._0 = (_5._1 >> _5._1);
_6._0 = (uvec4(_5._0) >> uvec4(_5._0));
_6._1 = ivec4(_5._1 >> _5._1);
_6._1 = ivec4(uvec4(_5._0) >> uvec4(_5._0));
_6._1 = ivec4(_5._1 >> uvec4(_5._0));
_6._1 = ivec4(uvec4(_5._0) >> _5._1);
}

View File

@ -0,0 +1,27 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 0, std430) buffer _3
{
ivec4 _0;
uvec4 _1;
} _5;
layout(binding = 1, std430) buffer _4
{
uvec4 _0;
ivec4 _1;
} _6;
void main()
{
_6._0 = (_5._1 / uvec4(_5._0));
_6._0 = (uvec4(_5._0) / _5._1);
_6._0 = (_5._1 / _5._1);
_6._0 = (uvec4(_5._0) / uvec4(_5._0));
_6._1 = ivec4(_5._1 / _5._1);
_6._1 = ivec4(uvec4(_5._0) / uvec4(_5._0));
_6._1 = ivec4(_5._1 / uvec4(_5._0));
_6._1 = ivec4(uvec4(_5._0) / _5._1);
}

View File

@ -0,0 +1,19 @@
#version 310 es
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(binding = 1, std430) buffer SSBO1
{
ivec4 outputs[];
} _21;
layout(binding = 0, std430) buffer SSBO0
{
ivec4 inputs[];
} _27;
void main()
{
uint ident = gl_GlobalInvocationID.x;
_21.outputs[ident] = mix(ivec4(0), ivec4(1), notEqual((_27.inputs[ident] & ivec4(3)), ivec4(uvec4(0u))));
}

View File

@ -0,0 +1,77 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of IAdd
%result_iadd_0 = OpIAdd %uvec4 %input0 %input1
%result_iadd_1 = OpIAdd %uvec4 %input1 %input0
%result_iadd_2 = OpIAdd %uvec4 %input0 %input0
%result_iadd_3 = OpIAdd %uvec4 %input1 %input1
%result_iadd_4 = OpIAdd %ivec4 %input0 %input0
%result_iadd_5 = OpIAdd %ivec4 %input1 %input1
%result_iadd_6 = OpIAdd %ivec4 %input0 %input1
%result_iadd_7 = OpIAdd %ivec4 %input1 %input0
OpStore %output_ptr_uvec4 %result_iadd_0
OpStore %output_ptr_uvec4 %result_iadd_1
OpStore %output_ptr_uvec4 %result_iadd_2
OpStore %output_ptr_uvec4 %result_iadd_3
OpStore %output_ptr_ivec4 %result_iadd_4
OpStore %output_ptr_ivec4 %result_iadd_5
OpStore %output_ptr_ivec4 %result_iadd_6
OpStore %output_ptr_ivec4 %result_iadd_7
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,90 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%bool = OpTypeBool
%bvec4 = OpTypeVector %bool 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%uone = OpConstant %uint 1
%uzero = OpConstant %uint 0
%uvec41 = OpConstantComposite %uvec4 %uone %uone %uone %uone
%ivec41 = OpConstantComposite %ivec4 %one %one %one %one
%uvec40 = OpConstantComposite %uvec4 %uzero %uzero %uzero %uzero
%ivec40 = OpConstantComposite %ivec4 %zero %zero %zero %zero
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of IEqual
%result_iequal0 = OpIEqual %bvec4 %input0 %input1
%result_iequal1 = OpIEqual %bvec4 %input1 %input0
%result_iequal2 = OpIEqual %bvec4 %input0 %input0
%result_iequal3 = OpIEqual %bvec4 %input1 %input1
%result_0 = OpSelect %uvec4 %result_iequal0 %uvec41 %uvec40
%result_1 = OpSelect %uvec4 %result_iequal1 %uvec41 %uvec40
%result_2 = OpSelect %uvec4 %result_iequal2 %uvec41 %uvec40
%result_3 = OpSelect %uvec4 %result_iequal3 %uvec41 %uvec40
%result_4 = OpSelect %ivec4 %result_iequal0 %ivec41 %ivec40
%result_5 = OpSelect %ivec4 %result_iequal1 %ivec41 %ivec40
%result_6 = OpSelect %ivec4 %result_iequal2 %ivec41 %ivec40
%result_7 = OpSelect %ivec4 %result_iequal3 %ivec41 %ivec40
OpStore %output_ptr_uvec4 %result_0
OpStore %output_ptr_uvec4 %result_1
OpStore %output_ptr_uvec4 %result_2
OpStore %output_ptr_uvec4 %result_3
OpStore %output_ptr_ivec4 %result_4
OpStore %output_ptr_ivec4 %result_5
OpStore %output_ptr_ivec4 %result_6
OpStore %output_ptr_ivec4 %result_7
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,77 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of ShiftRightArithmetic
%result_iadd_0 = OpShiftRightArithmetic %uvec4 %input0 %input1
%result_iadd_1 = OpShiftRightArithmetic %uvec4 %input1 %input0
%result_iadd_2 = OpShiftRightArithmetic %uvec4 %input0 %input0
%result_iadd_3 = OpShiftRightArithmetic %uvec4 %input1 %input1
%result_iadd_4 = OpShiftRightArithmetic %ivec4 %input0 %input0
%result_iadd_5 = OpShiftRightArithmetic %ivec4 %input1 %input1
%result_iadd_6 = OpShiftRightArithmetic %ivec4 %input0 %input1
%result_iadd_7 = OpShiftRightArithmetic %ivec4 %input1 %input0
OpStore %output_ptr_uvec4 %result_iadd_0
OpStore %output_ptr_uvec4 %result_iadd_1
OpStore %output_ptr_uvec4 %result_iadd_2
OpStore %output_ptr_uvec4 %result_iadd_3
OpStore %output_ptr_ivec4 %result_iadd_4
OpStore %output_ptr_ivec4 %result_iadd_5
OpStore %output_ptr_ivec4 %result_iadd_6
OpStore %output_ptr_ivec4 %result_iadd_7
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,77 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of SDiv
%result_iadd_0 = OpSDiv %uvec4 %input0 %input1
%result_iadd_1 = OpSDiv %uvec4 %input1 %input0
%result_iadd_2 = OpSDiv %uvec4 %input0 %input0
%result_iadd_3 = OpSDiv %uvec4 %input1 %input1
%result_iadd_4 = OpSDiv %ivec4 %input0 %input0
%result_iadd_5 = OpSDiv %ivec4 %input1 %input1
%result_iadd_6 = OpSDiv %ivec4 %input0 %input1
%result_iadd_7 = OpSDiv %ivec4 %input1 %input0
OpStore %output_ptr_uvec4 %result_iadd_0
OpStore %output_ptr_uvec4 %result_iadd_1
OpStore %output_ptr_uvec4 %result_iadd_2
OpStore %output_ptr_uvec4 %result_iadd_3
OpStore %output_ptr_ivec4 %result_iadd_4
OpStore %output_ptr_ivec4 %result_iadd_5
OpStore %output_ptr_ivec4 %result_iadd_6
OpStore %output_ptr_ivec4 %result_iadd_7
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,77 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of ShiftRightLogical
%result_iadd_0 = OpShiftRightLogical %uvec4 %input0 %input1
%result_iadd_1 = OpShiftRightLogical %uvec4 %input1 %input0
%result_iadd_2 = OpShiftRightLogical %uvec4 %input0 %input0
%result_iadd_3 = OpShiftRightLogical %uvec4 %input1 %input1
%result_iadd_4 = OpShiftRightLogical %ivec4 %input0 %input0
%result_iadd_5 = OpShiftRightLogical %ivec4 %input1 %input1
%result_iadd_6 = OpShiftRightLogical %ivec4 %input0 %input1
%result_iadd_7 = OpShiftRightLogical %ivec4 %input1 %input0
OpStore %output_ptr_uvec4 %result_iadd_0
OpStore %output_ptr_uvec4 %result_iadd_1
OpStore %output_ptr_uvec4 %result_iadd_2
OpStore %output_ptr_uvec4 %result_iadd_3
OpStore %output_ptr_ivec4 %result_iadd_4
OpStore %output_ptr_ivec4 %result_iadd_5
OpStore %output_ptr_ivec4 %result_iadd_6
OpStore %output_ptr_ivec4 %result_iadd_7
OpReturn
OpFunctionEnd

View File

@ -0,0 +1,77 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 1
; Bound: 30
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %func "main"
OpExecutionMode %func LocalSize 1 1 1
OpSource ESSL 310
OpSourceExtension "GL_GOOGLE_cpp_style_line_directive"
OpSourceExtension "GL_GOOGLE_include_directive"
OpMemberDecorate %input_struct 0 Offset 0
OpMemberDecorate %input_struct 1 Offset 16
OpMemberDecorate %output_struct 0 Offset 0
OpMemberDecorate %output_struct 1 Offset 16
OpDecorate %input_struct BufferBlock
OpDecorate %inputs DescriptorSet 0
OpDecorate %inputs Binding 0
OpDecorate %output_struct BufferBlock
OpDecorate %outputs DescriptorSet 0
OpDecorate %outputs Binding 1
%void = OpTypeVoid
%main_func = OpTypeFunction %void
%uint = OpTypeInt 32 0
%uvec4 = OpTypeVector %uint 4
%int = OpTypeInt 32 1
%ivec4 = OpTypeVector %int 4
%ivec4_ptr = OpTypePointer Uniform %ivec4
%uvec4_ptr = OpTypePointer Uniform %uvec4
%zero = OpConstant %int 0
%one = OpConstant %int 1
%input_struct = OpTypeStruct %ivec4 %uvec4
%input_struct_ptr = OpTypePointer Uniform %input_struct
%inputs = OpVariable %input_struct_ptr Uniform
%output_struct = OpTypeStruct %uvec4 %ivec4
%output_struct_ptr = OpTypePointer Uniform %output_struct
%outputs = OpVariable %output_struct_ptr Uniform
%func = OpFunction %void None %main_func
%block = OpLabel
%input1_ptr = OpAccessChain %ivec4_ptr %inputs %zero
%input0_ptr = OpAccessChain %uvec4_ptr %inputs %one
%input1 = OpLoad %ivec4 %input1_ptr
%input0 = OpLoad %uvec4 %input0_ptr
%output_ptr_uvec4 = OpAccessChain %uvec4_ptr %outputs %zero
%output_ptr_ivec4 = OpAccessChain %ivec4_ptr %outputs %one
; Test all variants of UDiv
%result_iadd_0 = OpUDiv %uvec4 %input0 %input1
%result_iadd_1 = OpUDiv %uvec4 %input1 %input0
%result_iadd_2 = OpUDiv %uvec4 %input0 %input0
%result_iadd_3 = OpUDiv %uvec4 %input1 %input1
%result_iadd_4 = OpUDiv %ivec4 %input0 %input0
%result_iadd_5 = OpUDiv %ivec4 %input1 %input1
%result_iadd_6 = OpUDiv %ivec4 %input0 %input1
%result_iadd_7 = OpUDiv %ivec4 %input1 %input0
OpStore %output_ptr_uvec4 %result_iadd_0
OpStore %output_ptr_uvec4 %result_iadd_1
OpStore %output_ptr_uvec4 %result_iadd_2
OpStore %output_ptr_uvec4 %result_iadd_3
OpStore %output_ptr_ivec4 %result_iadd_4
OpStore %output_ptr_ivec4 %result_iadd_5
OpStore %output_ptr_ivec4 %result_iadd_6
OpStore %output_ptr_ivec4 %result_iadd_7
OpReturn
OpFunctionEnd

18
shaders/comp/casts.comp Normal file
View File

@ -0,0 +1,18 @@
#version 310 es
layout(local_size_x = 1) in;
layout(binding = 0, std430) buffer SSBO0
{
ivec4 inputs[];
};
layout(binding = 1, std430) buffer SSBO1
{
ivec4 outputs[];
};
void main()
{
uint ident = gl_GlobalInvocationID.x;
outputs[ident] = ivec4(bvec4(inputs[ident] & 0x3));
}

View File

@ -487,6 +487,21 @@ static string extract_string(const vector<uint32_t> &spirv, uint32_t offset)
throw CompilerError("String was not terminated before EOF"); throw CompilerError("String was not terminated before EOF");
} }
static bool is_valid_spirv_version(uint32_t version)
{
switch (version)
{
// Allow v99 since it tends to just work.
case 99:
case 0x10000: // SPIR-V 1.0
case 0x10100: // SPIR-V 1.1
return true;
default:
return false;
}
}
void Compiler::parse() void Compiler::parse()
{ {
auto len = spirv.size(); auto len = spirv.size();
@ -502,17 +517,9 @@ void Compiler::parse()
return swap_endian(c); return swap_endian(c);
}); });
// Allow v99 since it tends to just work, but warn about this. if (s[0] != MagicNumber || !is_valid_spirv_version(s[1]))
if (s[0] != MagicNumber || (s[1] != Version && s[1] != 99))
throw CompilerError("Invalid SPIRV format."); throw CompilerError("Invalid SPIRV format.");
if (s[1] != Version)
{
fprintf(stderr, "SPIRV-Cross was compiled against SPIR-V version %d, but SPIR-V uses version %u. Buggy "
"behavior due to ABI incompatibility might occur.\n",
Version, s[1]);
}
uint32_t bound = s[3]; uint32_t bound = s[3];
ids.resize(bound); ids.resize(bound);
meta.resize(bound); meta.resize(bound);

View File

@ -1330,10 +1330,74 @@ void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint3
void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op)
{ {
emit_op(result_type, result_id, join(bitcast_glsl(result_type, op0), " ", op, " ", bitcast_glsl(result_type, op1)), emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)),
should_forward(op0) && should_forward(op1), true); should_forward(op0) && should_forward(op1), true);
} }
SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type)
{
auto &type0 = expression_type(op0);
auto &type1 = expression_type(op1);
// We have to bitcast if our inputs are of different type, or if our types are not equal to expected inputs.
// For some functions like OpIEqual and INotEqual, we don't care if inputs are of different types than expected
// since equality test is exactly the same.
bool cast = (type0.basetype != type1.basetype) || (!skip_cast_if_equal_type && type0.basetype != input_type);
// Create a fake type so we can bitcast to it.
// We only deal with regular arithmetic types here like int, uints and so on.
SPIRType expected_type;
expected_type.basetype = input_type;
expected_type.vecsize = type0.vecsize;
expected_type.columns = type0.columns;
expected_type.width = type0.width;
if (cast)
{
cast_op0 = bitcast_glsl(expected_type, op0);
cast_op1 = bitcast_glsl(expected_type, op1);
}
else
{
// If we don't cast, our actual input type is that of the first (or second) argument.
cast_op0 = to_expression(op0);
cast_op1 = to_expression(op1);
input_type = type0.basetype;
}
return expected_type;
}
void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
{
string cast_op0, cast_op1;
auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
auto &out_type = get<SPIRType>(result_type);
// We might have casted away from the result type, so bitcast again.
// For example, arithmetic right shift with uint inputs.
// Special case boolean outputs since relational opcodes output booleans instead of int/uint.
bool extra_parens = true;
string expr;
if (out_type.basetype != input_type && out_type.basetype != SPIRType::Bool)
{
expected_type.basetype = input_type;
expr = bitcast_glsl_op(out_type, expected_type);
expr += '(';
expr += join(cast_op0, " ", op, " ", cast_op1);
expr += ')';
extra_parens = false;
}
else
{
expr += join(cast_op0, " ", op, " ", cast_op1);
}
emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), extra_parens);
}
void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op) void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op)
{ {
emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), should_forward(op0), false); emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), should_forward(op0), false);
@ -1346,6 +1410,31 @@ void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id,
should_forward(op0) && should_forward(op1), false); should_forward(op0) && should_forward(op1), false);
} }
void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type)
{
string cast_op0, cast_op1;
auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type);
auto &out_type = get<SPIRType>(result_type);
// Special case boolean outputs since relational opcodes output booleans instead of int/uint.
string expr;
if (out_type.basetype != input_type && out_type.basetype != SPIRType::Bool)
{
expected_type.basetype = input_type;
expr = bitcast_glsl_op(out_type, expected_type);
expr += '(';
expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
expr += ')';
}
else
{
expr += join(op, "(", cast_op0, ", ", cast_op1, ")");
}
emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1), false);
}
void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, void CompilerGLSL::emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
uint32_t op2, const char *op) uint32_t op2, const char *op)
{ {
@ -1955,11 +2044,8 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
} }
} }
string CompilerGLSL::bitcast_glsl_op(uint32_t result_type, uint32_t argument) string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
{ {
auto &out_type = get<SPIRType>(result_type);
auto &in_type = expression_type(argument);
if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int) if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
return type_to_glsl(out_type); return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float) else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
@ -1976,9 +2062,9 @@ string CompilerGLSL::bitcast_glsl_op(uint32_t result_type, uint32_t argument)
return ""; return "";
} }
string CompilerGLSL::bitcast_glsl(uint32_t result_type, uint32_t argument) string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
{ {
auto op = bitcast_glsl_op(result_type, argument); auto op = bitcast_glsl_op(result_type, expression_type(argument));
if (op.empty()) if (op.empty())
return to_expression(argument); return to_expression(argument);
else else
@ -2438,10 +2524,13 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t length = instruction.length; uint32_t length = instruction.length;
#define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op) #define BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BOP_CAST(op, type, skip_cast) emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
#define UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op) #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 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 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(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define BFOP_CAST(op, type, skip_cast) emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, skip_cast)
#define BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op) #define UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
switch (opcode) switch (opcode)
@ -2809,16 +2898,35 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break; break;
case OpIAdd: case OpIAdd:
{
// For simple arith ops, prefer the output type if there's a mismatch to avoid extra bitcasts.
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(+, type, true);
break;
}
case OpFAdd: case OpFAdd:
BOP(+); BOP(+);
break; break;
case OpISub: case OpISub:
{
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(-, type, true);
break;
}
case OpFSub: case OpFSub:
BOP(-); BOP(-);
break; break;
case OpIMul: case OpIMul:
{
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(*, type, true);
break;
}
case OpFMul: case OpFMul:
case OpMatrixTimesVector: case OpMatrixTimesVector:
case OpMatrixTimesScalar: case OpMatrixTimesScalar:
@ -2841,40 +2949,63 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break; break;
case OpSDiv: case OpSDiv:
BOP_CAST(/, SPIRType::Int, false);
break;
case OpUDiv: case OpUDiv:
BOP_CAST(/, SPIRType::UInt, false);
break;
case OpFDiv: case OpFDiv:
BOP(/ ); BOP(/ );
break; break;
// Might need workaround if RightLocal can be used on signed types ...
case OpShiftRightLogical: case OpShiftRightLogical:
BOP_CAST(>>, SPIRType::UInt, false);
break;
case OpShiftRightArithmetic: case OpShiftRightArithmetic:
BOP(>> ); BOP_CAST(>>, SPIRType::Int, false);
break; break;
case OpShiftLeftLogical: case OpShiftLeftLogical:
BOP(<< ); {
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(<<, type, true);
break; break;
}
case OpBitwiseOr: case OpBitwiseOr:
BOP(| ); {
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(|, type, true);
break; break;
}
case OpBitwiseXor: case OpBitwiseXor:
BOP (^); {
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST (^, type, true);
break; break;
}
case OpBitwiseAnd: case OpBitwiseAnd:
BOP(&); {
auto type = get<SPIRType>(ops[0]).basetype;
BOP_CAST(&, type, true);
break; break;
}
case OpNot: case OpNot:
UOP(~); UOP(~);
break; break;
case OpUMod: case OpUMod:
BOP_CAST(%, SPIRType::UInt, false);
break;
case OpSMod: case OpSMod:
BOP(% ); BOP_CAST(%, SPIRType::Int, false);
break; break;
case OpFMod: case OpFMod:
@ -2906,8 +3037,16 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
UOP(!); UOP(!);
break; break;
case OpLogicalEqual:
case OpIEqual: case OpIEqual:
{
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(equal, SPIRType::Int, true);
else
BOP_CAST(==, SPIRType::Int, true);
break;
}
case OpLogicalEqual:
case OpFOrdEqual: case OpFOrdEqual:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2917,8 +3056,16 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break; break;
} }
case OpLogicalNotEqual:
case OpINotEqual: case OpINotEqual:
{
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(notEqual, SPIRType::Int, true);
else
BOP_CAST(!=, SPIRType::Int, true);
break;
}
case OpLogicalNotEqual:
case OpFOrdNotEqual: case OpFOrdNotEqual:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2930,6 +3077,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpUGreaterThan: case OpUGreaterThan:
case OpSGreaterThan: case OpSGreaterThan:
{
auto type = opcode == OpUGreaterThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(greaterThan, type, false);
else
BOP_CAST(>, type, false);
break;
}
case OpFOrdGreaterThan: case OpFOrdGreaterThan:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2941,6 +3097,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpUGreaterThanEqual: case OpUGreaterThanEqual:
case OpSGreaterThanEqual: case OpSGreaterThanEqual:
{
auto type = opcode == OpUGreaterThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(greaterThanEqual, type, false);
else
BOP_CAST(>=, type, false);
break;
}
case OpFOrdGreaterThanEqual: case OpFOrdGreaterThanEqual:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2952,6 +3117,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpULessThan: case OpULessThan:
case OpSLessThan: case OpSLessThan:
{
auto type = opcode == OpULessThan ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(lessThan, type, false);
else
BOP_CAST(<, type, false);
break;
}
case OpFOrdLessThan: case OpFOrdLessThan:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2963,6 +3137,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpULessThanEqual: case OpULessThanEqual:
case OpSLessThanEqual: case OpSLessThanEqual:
{
auto type = opcode == OpULessThanEqual ? SPIRType::UInt : SPIRType::Int;
if (expression_type(ops[2]).vecsize > 1)
BFOP_CAST(lessThanEqual, type, false);
else
BOP_CAST(<=, type, false);
break;
}
case OpFOrdLessThanEqual: case OpFOrdLessThanEqual:
{ {
if (expression_type(ops[2]).vecsize > 1) if (expression_type(ops[2]).vecsize > 1)
@ -2995,7 +3178,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t id = ops[1]; uint32_t id = ops[1];
uint32_t arg = ops[2]; uint32_t arg = ops[2];
auto op = bitcast_glsl_op(result_type, arg); auto op = bitcast_glsl_op(get<SPIRType>(result_type), expression_type(arg));
emit_unary_func_op(result_type, id, arg, op.c_str()); emit_unary_func_op(result_type, id, arg, op.c_str());
break; break;
} }

View File

@ -236,8 +236,16 @@ protected:
void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
const char *op); const char *op);
void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op);
void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
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);
void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); 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); 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, SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs,
@ -265,8 +273,8 @@ protected:
uint32_t type_to_std430_array_stride(const SPIRType &type, uint64_t flags); uint32_t type_to_std430_array_stride(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags); uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags);
std::string bitcast_glsl(uint32_t result_type, uint32_t arg); std::string bitcast_glsl(const SPIRType &result_type, uint32_t arg);
std::string bitcast_glsl_op(uint32_t result_type, uint32_t arg); std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type);
std::string build_composite_combiner(const uint32_t *elems, uint32_t length); std::string build_composite_combiner(const uint32_t *elems, uint32_t length);
bool remove_duplicate_swizzle(std::string &op); bool remove_duplicate_swizzle(std::string &op);
bool remove_unity_swizzle(uint32_t base, std::string &op); bool remove_unity_swizzle(uint32_t base, std::string &op);

View File

@ -66,26 +66,32 @@ def validate_shader(shader, vulkan):
else: else:
subprocess.check_call(['glslangValidator', shader]) subprocess.check_call(['glslangValidator', shader])
def cross_compile(shader, vulkan): def cross_compile(shader, vulkan, spirv):
spirv_f, spirv_path = tempfile.mkstemp() spirv_f, spirv_path = tempfile.mkstemp()
glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader)) glsl_f, glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
os.close(spirv_f) os.close(spirv_f)
os.close(glsl_f) os.close(glsl_f)
if vulkan: if vulkan or spirv:
vulkan_glsl_f, vulkan_glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader)) vulkan_glsl_f, vulkan_glsl_path = tempfile.mkstemp(suffix = os.path.basename(shader))
os.close(vulkan_glsl_f) os.close(vulkan_glsl_f)
if spirv:
subprocess.check_call(['spirv-as', '-o', spirv_path, shader])
else:
subprocess.check_call(['glslangValidator', '-V' if vulkan else '-G', '-o', spirv_path, shader]) subprocess.check_call(['glslangValidator', '-V' if vulkan else '-G', '-o', spirv_path, shader])
if spirv:
subprocess.check_call(['spirv-val', spirv_path])
spirv_cross_path = './spirv-cross' spirv_cross_path = './spirv-cross'
subprocess.check_call([spirv_cross_path, '--output', glsl_path, spirv_path]) subprocess.check_call([spirv_cross_path, '--output', glsl_path, spirv_path])
# A shader might not be possible to make valid GLSL from, skip validation for this case. # A shader might not be possible to make valid GLSL from, skip validation for this case.
if not ('nocompat' in glsl_path): if (not ('nocompat' in glsl_path)) and (not spirv):
validate_shader(glsl_path, False) validate_shader(glsl_path, False)
if vulkan: if vulkan or spirv:
subprocess.check_call([spirv_cross_path, '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path]) subprocess.check_call([spirv_cross_path, '--vulkan-semantics', '--output', vulkan_glsl_path, spirv_path])
validate_shader(vulkan_glsl_path, vulkan) validate_shader(vulkan_glsl_path, vulkan)
@ -139,15 +145,19 @@ def regression_check(shader, glsl, update, keep):
def shader_is_vulkan(shader): def shader_is_vulkan(shader):
return '.vk.' in shader return '.vk.' in shader
def shader_is_spirv(shader):
return '.asm.' in shader
def test_shader(stats, shader, update, keep): def test_shader(stats, shader, update, keep):
joined_path = os.path.join(shader[0], shader[1]) joined_path = os.path.join(shader[0], shader[1])
vulkan = shader_is_vulkan(shader[1]) vulkan = shader_is_vulkan(shader[1])
spirv = shader_is_spirv(shader[1])
print('Testing shader:', joined_path) print('Testing shader:', joined_path)
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan) spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, spirv)
# Only test GLSL stats if we have a shader following GL semantics. # Only test GLSL stats if we have a shader following GL semantics.
if stats and (not vulkan): if stats and (not vulkan) and (not spirv):
cross_stats = get_shader_stats(glsl) cross_stats = get_shader_stats(glsl)
regression_check(shader, glsl, update, keep) regression_check(shader, glsl, update, keep)