Merged with upstream
This commit is contained in:
commit
7c255dde4d
12
main.cpp
12
main.cpp
@ -196,10 +196,14 @@ static void print_resources(const Compiler &compiler, const char *tag, const vec
|
||||
bool is_push_constant = compiler.get_storage_class(res.id) == StorageClassPushConstant;
|
||||
bool is_block = (compiler.get_decoration_mask(type.self) &
|
||||
((1ull << DecorationBlock) | (1ull << DecorationBufferBlock))) != 0;
|
||||
uint32_t fallback_id = !is_push_constant && is_block ? res.type_id : res.id;
|
||||
uint32_t fallback_id = !is_push_constant && is_block ? res.base_type_id : res.id;
|
||||
|
||||
fprintf(stderr, " ID %03u : %s", res.id,
|
||||
!res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str());
|
||||
string array;
|
||||
for (auto arr : type.array)
|
||||
array = join("[", arr ? convert_to_string(arr) : "", "]") + array;
|
||||
|
||||
fprintf(stderr, " ID %03u : %s%s", res.id,
|
||||
!res.name.empty() ? res.name.c_str() : compiler.get_fallback_name(fallback_id).c_str(), array.c_str());
|
||||
|
||||
if (mask & (1ull << DecorationLocation))
|
||||
fprintf(stderr, " (Location : %u)", compiler.get_decoration(res.id, DecorationLocation));
|
||||
@ -304,7 +308,7 @@ static void print_push_constant_resources(const Compiler &compiler, const vector
|
||||
fprintf(stderr, "==================\n\n");
|
||||
for (auto &range : ranges)
|
||||
{
|
||||
const auto &name = compiler.get_member_name(block.type_id, range.index);
|
||||
const auto &name = compiler.get_member_name(block.base_type_id, range.index);
|
||||
|
||||
fprintf(stderr, "Member #%3u (%s): Offset: %4u, Range: %4u\n", range.index,
|
||||
!name.empty() ? name.c_str() : compiler.get_fallback_member_name(range.index).c_str(),
|
||||
|
@ -1,13 +1,13 @@
|
||||
#version 310 es
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(binding = 0, std430) buffer _3
|
||||
layout(binding = 0, std430) restrict buffer _3
|
||||
{
|
||||
ivec4 _0;
|
||||
uvec4 _1;
|
||||
} _5;
|
||||
|
||||
layout(binding = 1, std430) buffer _4
|
||||
layout(binding = 1, std430) restrict buffer _4
|
||||
{
|
||||
uvec4 _0;
|
||||
ivec4 _1;
|
||||
|
15
reference/shaders/asm/frag/invalidation.asm.frag
Normal file
15
reference/shaders/asm/frag/invalidation.asm.frag
Normal file
@ -0,0 +1,15 @@
|
||||
#version 450
|
||||
|
||||
in float v0;
|
||||
in float v1;
|
||||
out float FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
float a = v0;
|
||||
float b = v1;
|
||||
float _17 = a;
|
||||
a = v1;
|
||||
FragColor = ((_17 + b) * b);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ uvec2 workaround_mix(uvec2 a, uvec2 b, bvec2 sel)
|
||||
{
|
||||
_137 = a.x;
|
||||
}
|
||||
uint _147 = _137;
|
||||
if (sel.y)
|
||||
{
|
||||
_148 = b.y;
|
||||
@ -36,7 +37,7 @@ uvec2 workaround_mix(uvec2 a, uvec2 b, bvec2 sel)
|
||||
{
|
||||
_148 = a.y;
|
||||
}
|
||||
return uvec2(_137, _148);
|
||||
return uvec2(_147, _148);
|
||||
}
|
||||
|
||||
vec2 alias(vec2 i, vec2 N)
|
||||
|
@ -21,7 +21,8 @@ void main()
|
||||
uint j;
|
||||
for (;;)
|
||||
{
|
||||
int _40 = k + 1;
|
||||
int _39 = k;
|
||||
int _40 = _39 + 1;
|
||||
k = _40;
|
||||
if ((_40 < 10))
|
||||
{
|
||||
|
@ -0,0 +1,47 @@
|
||||
#version 450
|
||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
layout(binding = 0, rgba32f) uniform readonly writeonly image2D uImg00;
|
||||
layout(binding = 1, rgba16f) uniform readonly writeonly image2D uImg01;
|
||||
layout(binding = 2, rg32f) uniform readonly writeonly image2D uImg02;
|
||||
layout(binding = 3, rg16f) uniform readonly writeonly image2D uImg03;
|
||||
layout(binding = 4, r11f_g11f_b10f) uniform readonly writeonly image2D uImg04;
|
||||
layout(binding = 5, r32f) uniform readonly writeonly image2D uImg05;
|
||||
layout(binding = 6, r16f) uniform readonly writeonly image2D uImg06;
|
||||
layout(binding = 7, rgba16) uniform readonly writeonly image2D uImg07;
|
||||
layout(binding = 8, rgb10_a2) uniform readonly writeonly image2D uImg08;
|
||||
layout(binding = 9, rgba8) uniform readonly writeonly image2D uImg09;
|
||||
layout(binding = 10, rg16) uniform readonly writeonly image2D uImg10;
|
||||
layout(binding = 11, rg8) uniform readonly writeonly image2D uImg11;
|
||||
layout(binding = 12, r16) uniform readonly writeonly image2D uImg12;
|
||||
layout(binding = 13, r8) uniform readonly writeonly image2D uImg13;
|
||||
layout(binding = 14, rgba16_snorm) uniform readonly writeonly image2D uImg14;
|
||||
layout(binding = 15, rgba8_snorm) uniform readonly writeonly image2D uImg15;
|
||||
layout(binding = 16, rg16_snorm) uniform readonly writeonly image2D uImg16;
|
||||
layout(binding = 17, rg8_snorm) uniform readonly writeonly image2D uImg17;
|
||||
layout(binding = 18, r16_snorm) uniform readonly writeonly image2D uImg18;
|
||||
layout(binding = 19, r8_snorm) uniform readonly writeonly image2D uImg19;
|
||||
layout(binding = 20, rgba32i) uniform readonly writeonly iimage2D uImage20;
|
||||
layout(binding = 21, rgba16i) uniform readonly writeonly iimage2D uImage21;
|
||||
layout(binding = 22, rgba8i) uniform readonly writeonly iimage2D uImage22;
|
||||
layout(binding = 23, rg32i) uniform readonly writeonly iimage2D uImage23;
|
||||
layout(binding = 24, rg16i) uniform readonly writeonly iimage2D uImage24;
|
||||
layout(binding = 25, rg8i) uniform readonly writeonly iimage2D uImage25;
|
||||
layout(binding = 26, r32i) uniform readonly writeonly iimage2D uImage26;
|
||||
layout(binding = 27, r16i) uniform readonly writeonly iimage2D uImage27;
|
||||
layout(binding = 28, r8i) uniform readonly writeonly iimage2D uImage28;
|
||||
layout(binding = 29, rgba32ui) uniform readonly writeonly uimage2D uImage29;
|
||||
layout(binding = 30, rgba16ui) uniform readonly writeonly uimage2D uImage30;
|
||||
layout(binding = 31, rgb10_a2ui) uniform readonly writeonly uimage2D uImage31;
|
||||
layout(binding = 32, rgba8ui) uniform readonly writeonly uimage2D uImage32;
|
||||
layout(binding = 33, rg32ui) uniform readonly writeonly uimage2D uImage33;
|
||||
layout(binding = 34, rg16ui) uniform readonly writeonly uimage2D uImage34;
|
||||
layout(binding = 35, rg8ui) uniform readonly writeonly uimage2D uImage35;
|
||||
layout(binding = 36, r32ui) uniform readonly writeonly uimage2D uImage36;
|
||||
layout(binding = 37, r16ui) uniform readonly writeonly uimage2D uImage37;
|
||||
layout(binding = 38, r8ui) uniform readonly writeonly uimage2D uImage38;
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
||||
|
13
reference/shaders/desktop-only/frag/image-ms.desktop.frag
Normal file
13
reference/shaders/desktop-only/frag/image-ms.desktop.frag
Normal file
@ -0,0 +1,13 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0, rgba8) uniform image2DMS uImage;
|
||||
layout(binding = 1, rgba8) uniform image2DMSArray uImageArray;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 a = imageLoad(uImage, ivec2(1, 2), 2);
|
||||
vec4 b = imageLoad(uImageArray, ivec3(1, 2, 4), 3);
|
||||
imageStore(uImage, ivec2(2, 3), 1, a);
|
||||
imageStore(uImageArray, ivec3(2, 3, 7), 1, b);
|
||||
}
|
||||
|
11
reference/shaders/desktop-only/frag/query-levels.frag
Normal file
11
reference/shaders/desktop-only/frag/query-levels.frag
Normal file
@ -0,0 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2D uSampler;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(float(textureQueryLevels(uSampler)));
|
||||
}
|
||||
|
12
reference/shaders/desktop-only/frag/query-lod.frag
Normal file
12
reference/shaders/desktop-only/frag/query-lod.frag
Normal file
@ -0,0 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2D uSampler;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = textureQueryLod(uSampler, vTexCoord).xyxy;
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2DMS uSampler;
|
||||
layout(binding = 1) uniform sampler2DMSArray uSamplerArray;
|
||||
layout(binding = 2, rgba8) uniform readonly writeonly image2DMS uImage;
|
||||
layout(binding = 3, rgba8) uniform readonly writeonly image2DMSArray uImageArray;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(float((((textureSamples(uSampler) + textureSamples(uSamplerArray)) + imageSamples(uImage)) + imageSamples(uImageArray))));
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ bool frustum_cull(vec2 p0)
|
||||
float radius = (0.5 * length((bb_max - bb_min)));
|
||||
vec3 f0 = vec3(dot(_41.uFrustum[0], vec4(center, 1.0)), dot(_41.uFrustum[1], vec4(center, 1.0)), dot(_41.uFrustum[2], vec4(center, 1.0)));
|
||||
vec3 f1 = vec3(dot(_41.uFrustum[3], vec4(center, 1.0)), dot(_41.uFrustum[4], vec4(center, 1.0)), dot(_41.uFrustum[5], vec4(center, 1.0)));
|
||||
bool _205 = any(lessThanEqual(f0, vec3((-radius))));
|
||||
vec3 _199 = f0;
|
||||
bool _205 = any(lessThanEqual(_199, vec3((-radius))));
|
||||
bool _215;
|
||||
if ((!_205))
|
||||
{
|
||||
|
@ -69,6 +69,7 @@ vec2 warp_position()
|
||||
{
|
||||
_332 = 0u;
|
||||
}
|
||||
uint _342 = _332;
|
||||
if ((uPosition.y < 32u))
|
||||
{
|
||||
_343 = mask.y;
|
||||
@ -77,7 +78,7 @@ vec2 warp_position()
|
||||
{
|
||||
_343 = 0u;
|
||||
}
|
||||
rounding = uvec2(_332, _343);
|
||||
rounding = uvec2(_342, _343);
|
||||
lower_upper_snapped = vec4(((uPosition + rounding).xyxy & (~mask).xxyy));
|
||||
return mix(lower_upper_snapped.xy, lower_upper_snapped.zw, vec2(fract_lod));
|
||||
}
|
||||
|
14
reference/shaders/vulkan/frag/input-attachment-ms.vk.frag
Normal file
14
reference/shaders/vulkan/frag/input-attachment-ms.vk.frag
Normal file
@ -0,0 +1,14 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(binding = 0) uniform mediump sampler2DMS uSubpass0;
|
||||
layout(binding = 1) uniform mediump sampler2DMS uSubpass1;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = (texelFetch(uSubpass0, ivec2(gl_FragCoord.xy), 1) + texelFetch(uSubpass1, ivec2(gl_FragCoord.xy), 2));
|
||||
}
|
||||
|
14
reference/shaders/vulkan/frag/input-attachment-ms.vk.frag.vk
Normal file
14
reference/shaders/vulkan/frag/input-attachment-ms.vk.frag.vk
Normal file
@ -0,0 +1,14 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInputMS uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInputMS uSubpass1;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = (subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2));
|
||||
}
|
||||
|
@ -18,9 +18,11 @@
|
||||
OpDecorate %input_struct BufferBlock
|
||||
OpDecorate %inputs DescriptorSet 0
|
||||
OpDecorate %inputs Binding 0
|
||||
OpDecorate %inputs Restrict
|
||||
OpDecorate %output_struct BufferBlock
|
||||
OpDecorate %outputs DescriptorSet 0
|
||||
OpDecorate %outputs Binding 1
|
||||
OpDecorate %outputs Restrict
|
||||
|
||||
%void = OpTypeVoid
|
||||
%main_func = OpTypeFunction %void
|
||||
|
43
shaders/asm/frag/invalidation.asm.frag
Normal file
43
shaders/asm/frag/invalidation.asm.frag
Normal file
@ -0,0 +1,43 @@
|
||||
; SPIR-V
|
||||
; Version: 1.0
|
||||
; Generator: Khronos Glslang Reference Front End; 1
|
||||
; Bound: 28
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Fragment %4 "main" %v0 %v1 %FragColor
|
||||
OpExecutionMode %4 OriginUpperLeft
|
||||
OpSource GLSL 450
|
||||
OpName %4 "main"
|
||||
OpName %a "a"
|
||||
OpName %v0 "v0"
|
||||
OpName %b "b"
|
||||
OpName %v1 "v1"
|
||||
OpName %FragColor "FragColor"
|
||||
%2 = OpTypeVoid
|
||||
%3 = OpTypeFunction %2
|
||||
%float = OpTypeFloat 32
|
||||
%pfloat = OpTypePointer Function %float
|
||||
%9 = OpTypePointer Input %float
|
||||
%v0 = OpVariable %9 Input
|
||||
%v1 = OpVariable %9 Input
|
||||
%25 = OpTypePointer Output %float
|
||||
%FragColor = OpVariable %25 Output
|
||||
%4 = OpFunction %2 None %3
|
||||
%5 = OpLabel
|
||||
%a = OpVariable %pfloat Function
|
||||
%b = OpVariable %pfloat Function
|
||||
%v0_tmp = OpLoad %float %v0
|
||||
%v1_tmp = OpLoad %float %v1
|
||||
OpStore %a %v0_tmp
|
||||
OpStore %b %v1_tmp
|
||||
|
||||
%a_tmp = OpLoad %float %a
|
||||
%b_tmp = OpLoad %float %b
|
||||
%res = OpFAdd %float %a_tmp %b_tmp
|
||||
%res1 = OpFMul %float %res %b_tmp
|
||||
OpStore %a %v1_tmp
|
||||
OpStore %FragColor %res1
|
||||
OpReturn
|
||||
OpFunctionEnd
|
48
shaders/desktop-only/comp/image-formats.desktop.comp
Normal file
48
shaders/desktop-only/comp/image-formats.desktop.comp
Normal file
@ -0,0 +1,48 @@
|
||||
#version 450
|
||||
layout(local_size_x = 1) in;
|
||||
|
||||
layout(rgba32f, binding = 0) uniform image2D uImg00;
|
||||
layout(rgba16f, binding = 1) uniform image2D uImg01;
|
||||
layout(rg32f, binding = 2) uniform image2D uImg02;
|
||||
layout(rg16f, binding = 3) uniform image2D uImg03;
|
||||
layout(r11f_g11f_b10f, binding = 4) uniform image2D uImg04;
|
||||
layout(r32f, binding = 5) uniform image2D uImg05;
|
||||
layout(r16f, binding = 6) uniform image2D uImg06;
|
||||
layout(rgba16, binding = 7) uniform image2D uImg07;
|
||||
layout(rgb10_a2, binding = 8) uniform image2D uImg08;
|
||||
layout(rgba8, binding = 9) uniform image2D uImg09;
|
||||
layout(rg16, binding = 10) uniform image2D uImg10;
|
||||
layout(rg8, binding = 11) uniform image2D uImg11;
|
||||
layout(r16, binding = 12) uniform image2D uImg12;
|
||||
layout(r8, binding = 13) uniform image2D uImg13;
|
||||
layout(rgba16_snorm, binding = 14) uniform image2D uImg14;
|
||||
layout(rgba8_snorm, binding = 15) uniform image2D uImg15;
|
||||
layout(rg16_snorm, binding = 16) uniform image2D uImg16;
|
||||
layout(rg8_snorm, binding = 17) uniform image2D uImg17;
|
||||
layout(r16_snorm, binding = 18) uniform image2D uImg18;
|
||||
layout(r8_snorm, binding = 19) uniform image2D uImg19;
|
||||
|
||||
layout(rgba32i, binding = 20) uniform iimage2D uImage20;
|
||||
layout(rgba16i, binding = 21) uniform iimage2D uImage21;
|
||||
layout(rgba8i, binding = 22) uniform iimage2D uImage22;
|
||||
layout(rg32i, binding = 23) uniform iimage2D uImage23;
|
||||
layout(rg16i, binding = 24) uniform iimage2D uImage24;
|
||||
layout(rg8i, binding = 25) uniform iimage2D uImage25;
|
||||
layout(r32i, binding = 26) uniform iimage2D uImage26;
|
||||
layout(r16i, binding = 27) uniform iimage2D uImage27;
|
||||
layout(r8i, binding = 28) uniform iimage2D uImage28;
|
||||
|
||||
layout(rgba32ui, binding = 29) uniform uimage2D uImage29;
|
||||
layout(rgba16ui, binding = 30) uniform uimage2D uImage30;
|
||||
layout(rgb10_a2ui, binding = 31) uniform uimage2D uImage31;
|
||||
layout(rgba8ui, binding = 32) uniform uimage2D uImage32;
|
||||
layout(rg32ui, binding = 33) uniform uimage2D uImage33;
|
||||
layout(rg16ui, binding = 34) uniform uimage2D uImage34;
|
||||
layout(rg8ui, binding = 35) uniform uimage2D uImage35;
|
||||
layout(r32ui, binding = 36) uniform uimage2D uImage36;
|
||||
layout(r16ui, binding = 37) uniform uimage2D uImage37;
|
||||
layout(r8ui, binding = 38) uniform uimage2D uImage38;
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
12
shaders/desktop-only/frag/image-ms.desktop.frag
Normal file
12
shaders/desktop-only/frag/image-ms.desktop.frag
Normal file
@ -0,0 +1,12 @@
|
||||
#version 450
|
||||
|
||||
layout(rgba8, binding = 0) uniform image2DMS uImage;
|
||||
layout(rgba8, binding = 1) uniform image2DMSArray uImageArray;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 a = imageLoad(uImage, ivec2(1, 2), 2);
|
||||
vec4 b = imageLoad(uImageArray, ivec3(1, 2, 4), 3);
|
||||
imageStore(uImage, ivec2(2, 3), 1, a);
|
||||
imageStore(uImageArray, ivec3(2, 3, 7), 1, b);
|
||||
}
|
9
shaders/desktop-only/frag/query-levels.frag
Normal file
9
shaders/desktop-only/frag/query-levels.frag
Normal file
@ -0,0 +1,9 @@
|
||||
#version 450
|
||||
|
||||
layout(binding = 0) uniform sampler2D uSampler;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = vec4(textureQueryLevels(uSampler));
|
||||
}
|
10
shaders/desktop-only/frag/query-lod.frag
Normal file
10
shaders/desktop-only/frag/query-lod.frag
Normal file
@ -0,0 +1,10 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(binding = 0) uniform sampler2D uSampler;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = textureQueryLod(uSampler, vTexCoord).xyxy;
|
||||
}
|
17
shaders/desktop-only/frag/sampler-ms-query.desktop.frag
Normal file
17
shaders/desktop-only/frag/sampler-ms-query.desktop.frag
Normal file
@ -0,0 +1,17 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(binding = 0) uniform sampler2DMS uSampler;
|
||||
layout(binding = 1) uniform sampler2DMSArray uSamplerArray;
|
||||
layout(rgba8, binding = 2) uniform image2DMS uImage;
|
||||
layout(rgba8, binding = 3) uniform image2DMSArray uImageArray;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor =
|
||||
vec4(
|
||||
textureSamples(uSampler) +
|
||||
textureSamples(uSamplerArray) +
|
||||
imageSamples(uImage) +
|
||||
imageSamples(uImageArray));
|
||||
}
|
11
shaders/vulkan/frag/input-attachment-ms.vk.frag
Normal file
11
shaders/vulkan/frag/input-attachment-ms.vk.frag
Normal file
@ -0,0 +1,11 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInputMS uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInputMS uSubpass1;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2);
|
||||
}
|
@ -258,13 +258,15 @@ struct SPIRExpression : IVariant
|
||||
|
||||
// If this expression will never change, we can avoid lots of temporaries
|
||||
// in high level source.
|
||||
// An expression being immutable can be speculative,
|
||||
// it is assumed that this is true almost always.
|
||||
bool immutable = false;
|
||||
|
||||
// If this expression has been used while invalidated.
|
||||
bool used_while_invalidated = false;
|
||||
|
||||
// A list of a variables for which this expression was invalidated by.
|
||||
std::vector<uint32_t> invalidated_by;
|
||||
// A list of expressions which this expression depends on.
|
||||
std::vector<uint32_t> expression_dependencies;
|
||||
};
|
||||
|
||||
struct SPIRFunctionPrototype : IVariant
|
||||
|
@ -30,6 +30,10 @@ Instruction::Instruction(const vector<uint32_t> &spirv, uint32_t &index)
|
||||
{
|
||||
op = spirv[index] & 0xffff;
|
||||
count = (spirv[index] >> 16) & 0xffff;
|
||||
|
||||
if (count == 0)
|
||||
throw CompilerError("SPIR-V instructions cannot consume 0 words. Invalid SPIR-V file.");
|
||||
|
||||
offset = index + 1;
|
||||
length = count - 1;
|
||||
|
||||
@ -56,7 +60,8 @@ bool Compiler::variable_storage_is_aliased(const SPIRVariable &v)
|
||||
bool ssbo = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0;
|
||||
bool image = type.basetype == SPIRType::Image;
|
||||
bool counter = type.basetype == SPIRType::AtomicCounter;
|
||||
return ssbo || image || counter;
|
||||
bool is_restrict = (meta[v.self].decoration.decoration_flags & (1ull << DecorationRestrict)) != 0;
|
||||
return !is_restrict && (ssbo || image || counter);
|
||||
}
|
||||
|
||||
bool Compiler::block_is_pure(const SPIRBlock &block)
|
||||
@ -270,10 +275,7 @@ void Compiler::register_write(uint32_t chain)
|
||||
void Compiler::flush_dependees(SPIRVariable &var)
|
||||
{
|
||||
for (auto expr : var.dependees)
|
||||
{
|
||||
invalid_expressions.insert(expr);
|
||||
get<SPIRExpression>(expr).invalidated_by.push_back(var.self);
|
||||
}
|
||||
var.dependees.clear();
|
||||
}
|
||||
|
||||
@ -348,7 +350,7 @@ bool Compiler::is_immutable(uint32_t id) const
|
||||
|
||||
// Anything we load from the UniformConstant address space is guaranteed to be immutable.
|
||||
bool pointer_to_const = var.storage == StorageClassUniformConstant;
|
||||
return pointer_to_const || var.phi_variable || var.forwardable || !expression_is_lvalue(id);
|
||||
return pointer_to_const || var.phi_variable || !expression_is_lvalue(id);
|
||||
}
|
||||
else if (ids[id].get_type() == TypeExpression)
|
||||
return get<SPIRExpression>(id).immutable;
|
||||
@ -420,56 +422,56 @@ ShaderResources Compiler::get_shader_resources() const
|
||||
if (var.storage == StorageClassInput)
|
||||
{
|
||||
if (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock))
|
||||
res.stage_inputs.push_back({ var.self, type.self, meta[type.self].decoration.alias });
|
||||
res.stage_inputs.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
else
|
||||
res.stage_inputs.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.stage_inputs.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// Subpass inputs
|
||||
else if (var.storage == StorageClassUniformConstant && type.image.dim == DimSubpassData)
|
||||
{
|
||||
res.subpass_inputs.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.subpass_inputs.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// Outputs
|
||||
else if (var.storage == StorageClassOutput)
|
||||
{
|
||||
if (meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock))
|
||||
res.stage_outputs.push_back({ var.self, type.self, meta[type.self].decoration.alias });
|
||||
res.stage_outputs.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
else
|
||||
res.stage_outputs.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.stage_outputs.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// UBOs
|
||||
else if (type.storage == StorageClassUniform &&
|
||||
(meta[type.self].decoration.decoration_flags & (1ull << DecorationBlock)))
|
||||
{
|
||||
res.uniform_buffers.push_back({ var.self, type.self, meta[type.self].decoration.alias });
|
||||
res.uniform_buffers.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
}
|
||||
// SSBOs
|
||||
else if (type.storage == StorageClassUniform &&
|
||||
(meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)))
|
||||
{
|
||||
res.storage_buffers.push_back({ var.self, type.self, meta[type.self].decoration.alias });
|
||||
res.storage_buffers.push_back({ var.self, var.basetype, type.self, meta[type.self].decoration.alias });
|
||||
}
|
||||
// Push constant blocks
|
||||
else if (type.storage == StorageClassPushConstant)
|
||||
{
|
||||
// There can only be one push constant block, but keep the vector in case this restriction is lifted
|
||||
// in the future.
|
||||
res.push_constant_buffers.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.push_constant_buffers.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// Images
|
||||
else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::Image)
|
||||
{
|
||||
res.storage_images.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.storage_images.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// Textures
|
||||
else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::SampledImage)
|
||||
{
|
||||
res.sampled_images.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.sampled_images.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
// Atomic counters
|
||||
else if (type.storage == StorageClassAtomicCounter)
|
||||
{
|
||||
res.atomic_counters.push_back({ var.self, type.self, meta[var.self].decoration.alias });
|
||||
res.atomic_counters.push_back({ var.self, var.basetype, type.self, meta[var.self].decoration.alias });
|
||||
}
|
||||
}
|
||||
|
||||
@ -2026,3 +2028,21 @@ uint32_t Compiler::get_subpass_input_remapped_components(uint32_t id) const
|
||||
{
|
||||
return get<SPIRVariable>(id).remapped_components;
|
||||
}
|
||||
|
||||
void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_expression)
|
||||
{
|
||||
auto &e = get<SPIRExpression>(dst);
|
||||
auto *s = maybe_get<SPIRExpression>(source_expression);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
auto &e_deps = e.expression_dependencies;
|
||||
auto &s_deps = s->expression_dependencies;
|
||||
|
||||
// If we depend on a expression, we also depend on all sub-dependencies from source.
|
||||
e_deps.push_back(source_expression);
|
||||
e_deps.insert(end(e_deps), begin(s_deps), end(s_deps));
|
||||
|
||||
// Eliminate duplicated dependencies.
|
||||
e_deps.erase(unique(begin(e_deps), end(e_deps)), end(e_deps));
|
||||
}
|
||||
|
@ -36,15 +36,23 @@ struct Resource
|
||||
// This is the ID of the OpVariable.
|
||||
uint32_t id;
|
||||
|
||||
// The type of the declared resource.
|
||||
// The type ID of the variable which includes arrays and all type modifications.
|
||||
// This type ID is not suitable for parsing OpMemberDecoration of a struct and other decorations in general
|
||||
// since these modifications typically happen on the base_type_id.
|
||||
uint32_t type_id;
|
||||
|
||||
// The base type of the declared resource.
|
||||
// This type is the base type which ignores pointers and arrays of the type_id.
|
||||
// This is mostly useful to parse decorations of the underlying type.
|
||||
// base_type_id can also be obtained with get_type(get_type(type_id).self).
|
||||
uint32_t base_type_id;
|
||||
|
||||
// The declared name (OpName) of the resource.
|
||||
// For Buffer blocks, the name actually reflects the externally
|
||||
// visible Block name.
|
||||
//
|
||||
// This name can be retrieved again by using either
|
||||
// get_name(id) or get_name(type_id) depending if it's a buffer block or not.
|
||||
// get_name(id) or get_name(base_type_id) depending if it's a buffer block or not.
|
||||
//
|
||||
// This name can be an empty string in which case get_fallback_name(id) can be
|
||||
// used which obtains a suitable fallback identifier for an ID.
|
||||
@ -111,7 +119,7 @@ public:
|
||||
void unset_decoration(uint32_t id, spv::Decoration decoration);
|
||||
|
||||
// Gets the SPIR-V associated with ID.
|
||||
// Mostly used with Resource::type_id to parse the underlying type of a resource.
|
||||
// Mostly used with Resource::type_id and Resource::base_type_id to parse the underlying type of a resource.
|
||||
const SPIRType &get_type(uint32_t id) const;
|
||||
|
||||
// Gets the underlying storage class for an OpVariable.
|
||||
@ -352,6 +360,7 @@ protected:
|
||||
uint32_t increase_bound_by(uint32_t incr_amount);
|
||||
|
||||
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
|
||||
void inherit_expression_dependencies(uint32_t dst, uint32_t source);
|
||||
|
||||
private:
|
||||
void parse();
|
||||
|
329
spirv_glsl.cpp
329
spirv_glsl.cpp
@ -460,7 +460,11 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
||||
|
||||
const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
|
||||
{
|
||||
// Only handle GLES 3.1 compliant types for now ...
|
||||
auto check_desktop = [this] {
|
||||
if (options.es)
|
||||
throw CompilerError("Attempting to use image format not supported in ES profile.");
|
||||
};
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ImageFormatRgba32f:
|
||||
@ -504,10 +508,73 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
|
||||
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;
|
||||
default:
|
||||
return "UNSUPPORTED"; // TODO: Fill in rest.
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,7 +872,8 @@ void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var)
|
||||
void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
|
||||
{
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
auto ssbo = meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock);
|
||||
bool ssbo = (meta[type.self].decoration.decoration_flags & (1ull << DecorationBufferBlock)) != 0;
|
||||
bool is_restrict = (meta[var.self].decoration.decoration_flags & (1ull << DecorationRestrict)) != 0;
|
||||
|
||||
add_resource_name(var.self);
|
||||
|
||||
@ -819,7 +887,7 @@ void CompilerGLSL::emit_buffer_block(const SPIRVariable &var)
|
||||
else
|
||||
resource_names.insert(buffer_name);
|
||||
|
||||
statement(layout_for_variable(var) + (ssbo ? "buffer " : "uniform ") + buffer_name);
|
||||
statement(layout_for_variable(var), is_restrict ? "restrict " : "", ssbo ? "buffer " : "uniform ", buffer_name);
|
||||
begin_scope();
|
||||
|
||||
type.member_name_cache.clear();
|
||||
@ -1117,33 +1185,44 @@ string CompilerGLSL::to_func_call_arg(uint32_t id)
|
||||
return to_expression(id);
|
||||
}
|
||||
|
||||
void CompilerGLSL::handle_invalid_expression(uint32_t id)
|
||||
{
|
||||
auto &expr = get<SPIRExpression>(id);
|
||||
|
||||
// This expression has been invalidated in the past.
|
||||
// Be careful with this expression next pass ...
|
||||
// Used for OpCompositeInsert forwarding atm.
|
||||
expr.used_while_invalidated = true;
|
||||
|
||||
// We tried to read an invalidated expression.
|
||||
// This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated.
|
||||
forced_temporaries.insert(id);
|
||||
force_recompile = true;
|
||||
}
|
||||
|
||||
string CompilerGLSL::to_expression(uint32_t id)
|
||||
{
|
||||
auto itr = invalid_expressions.find(id);
|
||||
if (itr != end(invalid_expressions))
|
||||
handle_invalid_expression(id);
|
||||
|
||||
if (ids[id].get_type() == TypeExpression)
|
||||
{
|
||||
// We might have a more complex chain of dependencies.
|
||||
// A possible scenario is that we
|
||||
//
|
||||
// %1 = OpLoad
|
||||
// %2 = OpDoSomething %1 %1. here %2 will have a dependency on %1.
|
||||
// %3 = OpDoSomethingAgain %2 %2. Here %3 will lose the link to %1 since we don't propagate the dependencies like that.
|
||||
// OpStore %1 %foo // Here we can invalidate %1, and hence all expressions which depend on %1. Only %2 will know since it's part of invalid_expressions.
|
||||
// %4 = OpDoSomethingAnotherTime %3 %3 // If we forward all expressions we will see %1 expression after store, not before.
|
||||
//
|
||||
// However, we can propagate up a list of depended expressions when we used %2, so we can check if %2 is invalid when reading %3 after the store,
|
||||
// and see that we should not forward reads of the original variable.
|
||||
auto &expr = get<SPIRExpression>(id);
|
||||
|
||||
// This expression has been invalidated in the past.
|
||||
// Be careful with this expression next pass ...
|
||||
// Used for OpCompositeInsert forwarding atm.
|
||||
expr.used_while_invalidated = true;
|
||||
|
||||
// We tried to read an invalidated expression.
|
||||
// This means we need another pass at compilation, but next time, do not try to forward
|
||||
// the variables which caused invalidation to happen in the first place.
|
||||
for (auto var : expr.invalidated_by)
|
||||
{
|
||||
//fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, var);
|
||||
get<SPIRVariable>(var).forwardable = false;
|
||||
}
|
||||
|
||||
if (expr.invalidated_by.empty() && expr.loaded_from)
|
||||
{
|
||||
//fprintf(stderr, "Expression %u was invalidated due to variable %u being invalid at read time!\n", id, expr.loaded_from);
|
||||
get<SPIRVariable>(expr.loaded_from).forwardable = false;
|
||||
}
|
||||
force_recompile = true;
|
||||
for (uint32_t dep : expr.expression_dependencies)
|
||||
if (invalid_expressions.find(dep) != end(invalid_expressions))
|
||||
handle_invalid_expression(dep);
|
||||
}
|
||||
|
||||
track_expression_read(id);
|
||||
@ -1382,13 +1461,23 @@ SPIRExpression &CompilerGLSL::emit_op(uint32_t result_type, uint32_t result_id,
|
||||
|
||||
void CompilerGLSL::emit_unary_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), true);
|
||||
bool forward = should_forward(op0);
|
||||
emit_op(result_type, result_id, join(op, to_expression(op0)), forward, true);
|
||||
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
}
|
||||
|
||||
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(to_expression(op0), " ", op, " ", to_expression(op1)),
|
||||
should_forward(op0) && should_forward(op1), true);
|
||||
bool forward = should_forward(op0) && should_forward(op1);
|
||||
emit_op(result_type, result_id, join(to_expression(op0), " ", op, " ", to_expression(op1)), forward, true);
|
||||
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
{
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
inherit_expression_dependencies(result_id, op1);
|
||||
}
|
||||
}
|
||||
|
||||
SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_op1, SPIRType::BaseType &input_type,
|
||||
@ -1457,14 +1546,23 @@ void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id,
|
||||
|
||||
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);
|
||||
bool forward = should_forward(op0);
|
||||
emit_op(result_type, result_id, join(op, "(", to_expression(op0), ")"), forward, false);
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_binary_func_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(op, "(", to_expression(op0), ", ", to_expression(op1), ")"),
|
||||
should_forward(op0) && should_forward(op1), false);
|
||||
bool forward = should_forward(op0) && should_forward(op1);
|
||||
emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ")"), forward, false);
|
||||
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
{
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
inherit_expression_dependencies(result_id, op1);
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||
@ -1495,17 +1593,33 @@ void CompilerGLSL::emit_binary_func_op_cast(uint32_t result_type, uint32_t resul
|
||||
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)
|
||||
{
|
||||
bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2);
|
||||
emit_op(result_type, result_id,
|
||||
join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"),
|
||||
should_forward(op0) && should_forward(op1) && should_forward(op2), false);
|
||||
join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ", to_expression(op2), ")"), forward, false);
|
||||
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
{
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
inherit_expression_dependencies(result_id, op1);
|
||||
inherit_expression_dependencies(result_id, op2);
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerGLSL::emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
|
||||
uint32_t op2, uint32_t op3, const char *op)
|
||||
{
|
||||
bool forward = should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3);
|
||||
emit_op(result_type, result_id, join(op, "(", to_expression(op0), ", ", to_expression(op1), ", ",
|
||||
to_expression(op2), ", ", to_expression(op3), ")"),
|
||||
should_forward(op0) && should_forward(op1) && should_forward(op2) && should_forward(op3), false);
|
||||
forward, false);
|
||||
|
||||
if (forward && forced_temporaries.find(result_id) == end(forced_temporaries))
|
||||
{
|
||||
inherit_expression_dependencies(result_id, op0);
|
||||
inherit_expression_dependencies(result_id, op1);
|
||||
inherit_expression_dependencies(result_id, op2);
|
||||
inherit_expression_dependencies(result_id, op3);
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtype)
|
||||
@ -2332,7 +2446,11 @@ string CompilerGLSL::access_chain(uint32_t base, const uint32_t *indices, uint32
|
||||
|
||||
bool CompilerGLSL::should_forward(uint32_t id)
|
||||
{
|
||||
return is_immutable(id) && !options.force_temporary;
|
||||
// Immutable expression can always be forwarded.
|
||||
// If not immutable, we can speculate about it by forwarding potentially mutable variables.
|
||||
auto *var = maybe_get<SPIRVariable>(id);
|
||||
bool forward = var ? var->forwardable : false;
|
||||
return (is_immutable(id) || forward) && !options.force_temporary;
|
||||
}
|
||||
|
||||
void CompilerGLSL::track_expression_read(uint32_t id)
|
||||
@ -2606,18 +2724,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
// If we're loading from memory that cannot be changed by the shader,
|
||||
// just forward the expression directly to avoid needless temporaries.
|
||||
if (should_forward(ptr))
|
||||
{
|
||||
set<SPIRExpression>(id, to_expression(ptr), result_type, true);
|
||||
register_read(id, ptr, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the variable can be modified after this OpLoad, we cannot just forward the expression.
|
||||
// We must read it now and store it in a temporary.
|
||||
emit_op(result_type, id, to_expression(ptr), false, false);
|
||||
register_read(id, ptr, false);
|
||||
}
|
||||
// If an expression is mutable and forwardable, we speculate that it is immutable.
|
||||
bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
|
||||
|
||||
// Suppress usage tracking since using same expression multiple times does not imply any extra work.
|
||||
emit_op(result_type, id, to_expression(ptr), forward, false, true);
|
||||
register_read(id, ptr, forward);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2629,8 +2741,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
flush_variable_declaration(var->self);
|
||||
|
||||
// If the base is immutable, the access chain pointer must also be.
|
||||
// If an expression is mutable and forwardable, we speculate that it is immutable.
|
||||
auto e = access_chain(ops[2], &ops[3], length - 3, false);
|
||||
auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], is_immutable(ops[2]));
|
||||
auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
|
||||
expr.loaded_from = ops[2];
|
||||
break;
|
||||
}
|
||||
@ -2650,8 +2763,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
// For this case, we don't need to invalidate anything and emit any opcode.
|
||||
if (lhs != rhs)
|
||||
{
|
||||
register_write(ops[0]);
|
||||
statement(lhs, " = ", rhs, ";");
|
||||
register_write(ops[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -3507,7 +3620,52 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
emit_op(result_type, id, to_expression(ops[2]), true, false);
|
||||
auto &e = emit_op(result_type, id, to_expression(ops[2]), true, false);
|
||||
|
||||
// When using the image, we need to know which variable it is actually loaded from.
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
e.loaded_from = var ? var->self : 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case OpImageQueryLod:
|
||||
{
|
||||
if (!options.es && options.version < 400)
|
||||
{
|
||||
require_extension("GL_ARB_texture_query_lod");
|
||||
// For some reason, the ARB spec is all-caps.
|
||||
BFOP(textureQueryLOD);
|
||||
}
|
||||
else if (options.es)
|
||||
throw CompilerError("textureQueryLod not supported in ES profile.");
|
||||
else
|
||||
BFOP(textureQueryLod);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpImageQueryLevels:
|
||||
{
|
||||
if (!options.es && options.version < 430)
|
||||
require_extension("GL_ARB_texture_query_levels");
|
||||
if (options.es)
|
||||
throw CompilerError("textureQueryLevels not supported in ES profile.");
|
||||
UFOP(textureQueryLevels);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpImageQuerySamples:
|
||||
{
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
if (!var)
|
||||
throw CompilerError(
|
||||
"Bug. OpImageQuerySamples must have a backing variable so we know if the image is sampled or not.");
|
||||
|
||||
auto &type = get<SPIRType>(var->basetype);
|
||||
bool image = type.image.sampled == 2;
|
||||
if (image)
|
||||
UFOP(imageSamples);
|
||||
else
|
||||
UFOP(textureSamples);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3549,6 +3707,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
|
||||
if (var && var->remapped_variable) // Remapped input, just read as-is without any op-code
|
||||
{
|
||||
if (type.image.ms)
|
||||
throw CompilerError("Trying to remap multisampled image to variable, this is not possible.");
|
||||
|
||||
auto itr =
|
||||
find_if(begin(pls_inputs), end(pls_inputs), [var](const PlsRemap &pls) { return pls.id == var->self; });
|
||||
|
||||
@ -3574,19 +3735,56 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
if (options.vulkan_semantics)
|
||||
{
|
||||
// With Vulkan semantics, use the proper Vulkan GLSL construct.
|
||||
imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
|
||||
if (type.image.ms)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
imgexpr = join("subpassLoad(", to_expression(ops[2]), ", ", to_expression(samples), ")");
|
||||
}
|
||||
else
|
||||
imgexpr = join("subpassLoad(", to_expression(ops[2]), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Implement subpass loads via texture barrier style sampling.
|
||||
imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
|
||||
if (type.image.ms)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), ",
|
||||
to_expression(samples), ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Implement subpass loads via texture barrier style sampling.
|
||||
imgexpr = join("texelFetch(", to_expression(ops[2]), ", ivec2(gl_FragCoord.xy), 0)");
|
||||
}
|
||||
}
|
||||
pure = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Plain image load/store.
|
||||
imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
|
||||
if (type.image.ms)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || length != 6)
|
||||
throw CompilerError(
|
||||
"Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
|
||||
uint32_t samples = ops[5];
|
||||
imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ", ",
|
||||
to_expression(samples), ")");
|
||||
}
|
||||
else
|
||||
imgexpr = join("imageLoad(", to_expression(ops[2]), ", ", to_expression(ops[3]), ")");
|
||||
pure = false;
|
||||
}
|
||||
|
||||
@ -3612,6 +3810,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
uint32_t id = ops[1];
|
||||
auto &e = set<SPIRExpression>(id, join(to_expression(ops[2]), ", ", to_expression(ops[3])), result_type, true);
|
||||
|
||||
// When using the pointer, we need to know which variable it is actually loaded from.
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
e.loaded_from = var ? var->self : 0;
|
||||
break;
|
||||
@ -3633,7 +3832,19 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
||||
}
|
||||
}
|
||||
|
||||
statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ");");
|
||||
auto &type = expression_type(ops[0]);
|
||||
if (type.image.ms)
|
||||
{
|
||||
uint32_t operands = ops[3];
|
||||
if (operands != ImageOperandsSampleMask || length != 5)
|
||||
throw CompilerError("Multisampled image used in OpImageWrite, but unexpected operand mask was used.");
|
||||
uint32_t samples = ops[4];
|
||||
statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(samples),
|
||||
", ", to_expression(ops[2]), ");");
|
||||
}
|
||||
else
|
||||
statement("imageStore(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]),
|
||||
");");
|
||||
|
||||
if (var && variable_storage_is_aliased(*var))
|
||||
flush_all_aliased_variables();
|
||||
@ -3951,7 +4162,7 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
}
|
||||
|
||||
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData && options.vulkan_semantics)
|
||||
return res + "subpassInput";
|
||||
return res + "subpassInput" + (type.image.ms ? "MS" : "");
|
||||
|
||||
// If we're emulating subpassInput with samplers, force sampler2D
|
||||
// so we don't have to specify format.
|
||||
@ -3990,12 +4201,12 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type)
|
||||
throw CompilerError("Only 1D, 2D, 3D, Buffer, InputTarget and Cube textures supported.");
|
||||
}
|
||||
|
||||
if (type.image.ms)
|
||||
res += "MS";
|
||||
if (type.image.arrayed)
|
||||
res += "Array";
|
||||
if (type.image.depth)
|
||||
res += "Shadow";
|
||||
if (type.image.ms)
|
||||
res += "MS";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -347,6 +347,8 @@ protected:
|
||||
void add_variable(std::unordered_set<std::string> &variables, uint32_t id);
|
||||
|
||||
void check_function_call_constraints(const uint32_t *args, uint32_t length);
|
||||
|
||||
void handle_invalid_expression(uint32_t id);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -146,19 +146,23 @@ def regression_check(shader, glsl, update, keep):
|
||||
def shader_is_vulkan(shader):
|
||||
return '.vk.' in shader
|
||||
|
||||
def shader_is_desktop(shader):
|
||||
return '.desktop.' in shader
|
||||
|
||||
def shader_is_spirv(shader):
|
||||
return '.asm.' in shader
|
||||
|
||||
def test_shader(stats, shader, update, keep):
|
||||
joined_path = os.path.join(shader[0], shader[1])
|
||||
vulkan = shader_is_vulkan(shader[1])
|
||||
desktop = shader_is_desktop(shader[1])
|
||||
spirv = shader_is_spirv(shader[1])
|
||||
|
||||
print('Testing shader:', joined_path)
|
||||
spirv, glsl, vulkan_glsl = cross_compile(joined_path, vulkan, spirv)
|
||||
|
||||
# Only test GLSL stats if we have a shader following GL semantics.
|
||||
if stats and (not vulkan) and (not spirv):
|
||||
if stats and (not vulkan) and (not spirv) and (not desktop):
|
||||
cross_stats = get_shader_stats(glsl)
|
||||
|
||||
regression_check(shader, glsl, update, keep)
|
||||
|
Loading…
Reference in New Issue
Block a user