Preserve arguments with inout unless complete writes are made.
This commit is contained in:
parent
14cd000f3d
commit
744d0405b0
78
reference/shaders-hlsl/frag/partial-write-preserve.frag
Normal file
78
reference/shaders-hlsl/frag/partial-write-preserve.frag
Normal file
@ -0,0 +1,78 @@
|
||||
struct B
|
||||
{
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
|
||||
struct _UBO
|
||||
{
|
||||
int some_value;
|
||||
};
|
||||
|
||||
cbuffer UBO : register(c0)
|
||||
{
|
||||
_UBO _42;
|
||||
};
|
||||
|
||||
void partial_inout(inout float4 x)
|
||||
{
|
||||
x.x = 10.0f;
|
||||
}
|
||||
|
||||
void complete_inout(out float4 x)
|
||||
{
|
||||
x = float4(50.0f, 50.0f, 50.0f, 50.0f);
|
||||
}
|
||||
|
||||
void branchy_inout(inout float4 v)
|
||||
{
|
||||
v.y = 20.0f;
|
||||
if (_42.some_value == 20)
|
||||
{
|
||||
v = float4(50.0f, 50.0f, 50.0f, 50.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout_2(out float4 v)
|
||||
{
|
||||
if (_42.some_value == 20)
|
||||
{
|
||||
v = float4(50.0f, 50.0f, 50.0f, 50.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = float4(70.0f, 70.0f, 70.0f, 70.0f);
|
||||
}
|
||||
v.y = 20.0f;
|
||||
}
|
||||
|
||||
void partial_inout(inout B b)
|
||||
{
|
||||
b.b = 40.0f;
|
||||
}
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
float4 a = float4(10.0f, 10.0f, 10.0f, 10.0f);
|
||||
float4 param = a;
|
||||
partial_inout(param);
|
||||
a = param;
|
||||
float4 param_1;
|
||||
complete_inout(param_1);
|
||||
a = param_1;
|
||||
float4 param_2 = a;
|
||||
branchy_inout(param_2);
|
||||
a = param_2;
|
||||
float4 param_3;
|
||||
branchy_inout_2(param_3);
|
||||
a = param_3;
|
||||
B b = { 10.0f, 20.0f };
|
||||
B param_4 = b;
|
||||
partial_inout(param_4);
|
||||
b = param_4;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
frag_main();
|
||||
}
|
@ -24,7 +24,7 @@ layout(binding = 2, std430) readonly buffer SSBO3
|
||||
Foo foos[];
|
||||
} foobar;
|
||||
|
||||
void baz(out Foo foo)
|
||||
void baz(inout Foo foo)
|
||||
{
|
||||
uint ident = gl_GlobalInvocationID.x;
|
||||
foo.a = indata.data[(4u * ident) + 0u];
|
||||
|
@ -9,7 +9,7 @@ struct Structy
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void foo2(out Structy f)
|
||||
void foo2(inout Structy f)
|
||||
{
|
||||
f.c = vec4(10.0);
|
||||
}
|
||||
|
109
reference/shaders/frag/partial-write-preserve.frag
Normal file
109
reference/shaders/frag/partial-write-preserve.frag
Normal file
@ -0,0 +1,109 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
struct B
|
||||
{
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
|
||||
layout(binding = 0, std140) uniform UBO
|
||||
{
|
||||
mediump int some_value;
|
||||
} _51;
|
||||
|
||||
void partial_inout(inout vec4 x)
|
||||
{
|
||||
x.x = 10.0;
|
||||
}
|
||||
|
||||
void complete_inout(out vec4 x)
|
||||
{
|
||||
x = vec4(50.0);
|
||||
}
|
||||
|
||||
void branchy_inout(inout vec4 v)
|
||||
{
|
||||
v.y = 20.0;
|
||||
if (_51.some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout_2(out vec4 v)
|
||||
{
|
||||
if (_51.some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = vec4(70.0);
|
||||
}
|
||||
v.y = 20.0;
|
||||
}
|
||||
|
||||
void partial_inout(inout B b)
|
||||
{
|
||||
b.b = 40.0;
|
||||
}
|
||||
|
||||
void complete_inout(out B b)
|
||||
{
|
||||
b = B(100.0, 200.0);
|
||||
}
|
||||
|
||||
void branchy_inout(inout B b)
|
||||
{
|
||||
b.b = 20.0;
|
||||
if (_51.some_value == 20)
|
||||
{
|
||||
b = B(10.0, 40.0);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout_2(out B b)
|
||||
{
|
||||
if (_51.some_value == 20)
|
||||
{
|
||||
b = B(10.0, 40.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = B(70.0, 70.0);
|
||||
}
|
||||
b.b = 20.0;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 a = vec4(10.0);
|
||||
highp vec4 param = a;
|
||||
partial_inout(param);
|
||||
a = param;
|
||||
highp vec4 param_1;
|
||||
complete_inout(param_1);
|
||||
a = param_1;
|
||||
highp vec4 param_2 = a;
|
||||
branchy_inout(param_2);
|
||||
a = param_2;
|
||||
highp vec4 param_3;
|
||||
branchy_inout_2(param_3);
|
||||
a = param_3;
|
||||
B b = B(10.0, 20.0);
|
||||
B param_4 = b;
|
||||
partial_inout(param_4);
|
||||
b = param_4;
|
||||
B param_5;
|
||||
complete_inout(param_5);
|
||||
b = param_5;
|
||||
B param_6 = b;
|
||||
branchy_inout(param_6);
|
||||
b = param_6;
|
||||
B param_7;
|
||||
branchy_inout_2(param_7);
|
||||
b = param_7;
|
||||
}
|
||||
|
64
shaders-hlsl/frag/partial-write-preserve.frag
Normal file
64
shaders-hlsl/frag/partial-write-preserve.frag
Normal file
@ -0,0 +1,64 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(std140, binding = 0) uniform UBO
|
||||
{
|
||||
int some_value;
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
|
||||
void partial_inout(inout vec4 x)
|
||||
{
|
||||
x.x = 10.0;
|
||||
}
|
||||
|
||||
void partial_inout(inout B b)
|
||||
{
|
||||
b.b = 40.0;
|
||||
}
|
||||
|
||||
// Make a complete write, but only conditionally ...
|
||||
void branchy_inout(inout vec4 v)
|
||||
{
|
||||
v.y = 20.0;
|
||||
if (some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout_2(out vec4 v)
|
||||
{
|
||||
if (some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = vec4(70.0);
|
||||
}
|
||||
v.y = 20.0;
|
||||
}
|
||||
|
||||
void complete_inout(out vec4 x)
|
||||
{
|
||||
x = vec4(50.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 a = vec4(10.0);
|
||||
partial_inout(a);
|
||||
complete_inout(a);
|
||||
branchy_inout(a);
|
||||
branchy_inout_2(a);
|
||||
|
||||
B b = B(10.0, 20.0);
|
||||
partial_inout(b);
|
||||
}
|
||||
|
95
shaders/frag/partial-write-preserve.frag
Normal file
95
shaders/frag/partial-write-preserve.frag
Normal file
@ -0,0 +1,95 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(std140, binding = 0) uniform UBO
|
||||
{
|
||||
int some_value;
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
float a;
|
||||
float b;
|
||||
};
|
||||
|
||||
void partial_inout(inout vec4 x)
|
||||
{
|
||||
x.x = 10.0;
|
||||
}
|
||||
|
||||
void partial_inout(inout B b)
|
||||
{
|
||||
b.b = 40.0;
|
||||
}
|
||||
|
||||
// Make a complete write, but only conditionally ...
|
||||
void branchy_inout(inout vec4 v)
|
||||
{
|
||||
v.y = 20.0;
|
||||
if (some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout(inout B b)
|
||||
{
|
||||
b.b = 20.0;
|
||||
if (some_value == 20)
|
||||
{
|
||||
b = B(10.0, 40.0);
|
||||
}
|
||||
}
|
||||
|
||||
void branchy_inout_2(out vec4 v)
|
||||
{
|
||||
if (some_value == 20)
|
||||
{
|
||||
v = vec4(50.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
v = vec4(70.0);
|
||||
}
|
||||
v.y = 20.0;
|
||||
}
|
||||
|
||||
void branchy_inout_2(out B b)
|
||||
{
|
||||
if (some_value == 20)
|
||||
{
|
||||
b = B(10.0, 40.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
b = B(70.0, 70.0);
|
||||
}
|
||||
b.b = 20.0;
|
||||
}
|
||||
|
||||
|
||||
void complete_inout(out vec4 x)
|
||||
{
|
||||
x = vec4(50.0);
|
||||
}
|
||||
|
||||
void complete_inout(out B b)
|
||||
{
|
||||
b = B(100.0, 200.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 a = vec4(10.0);
|
||||
partial_inout(a);
|
||||
complete_inout(a);
|
||||
branchy_inout(a);
|
||||
branchy_inout_2(a);
|
||||
|
||||
B b = B(10.0, 20.0);
|
||||
partial_inout(b);
|
||||
complete_inout(b);
|
||||
branchy_inout(b);
|
||||
branchy_inout_2(b);
|
||||
}
|
||||
|
@ -2923,7 +2923,8 @@ static bool exists_unaccessed_path_to_return(const CFG &cfg, uint32_t block, con
|
||||
}
|
||||
|
||||
void Compiler::analyze_parameter_preservation(
|
||||
SPIRFunction &entry, const CFG &cfg, const unordered_map<uint32_t, unordered_set<uint32_t>> &variable_to_blocks)
|
||||
SPIRFunction &entry, const CFG &cfg, const unordered_map<uint32_t, unordered_set<uint32_t>> &variable_to_blocks,
|
||||
const unordered_map<uint32_t, unordered_set<uint32_t>> &complete_write_blocks)
|
||||
{
|
||||
for (auto &arg : entry.arguments)
|
||||
{
|
||||
@ -2958,7 +2959,16 @@ void Compiler::analyze_parameter_preservation(
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is a path through the CFG where no block writes to the variable, the variable will be in an undefined state
|
||||
// We have accessed a variable, but there was no complete writes to that variable.
|
||||
// We deduce that we must preserve the argument.
|
||||
itr = complete_write_blocks.find(arg.id);
|
||||
if (itr == end(complete_write_blocks))
|
||||
{
|
||||
arg.read_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If there is a path through the CFG where no block completely writes to the variable, the variable will be in an undefined state
|
||||
// when the function returns. We therefore need to implicitly preserve the variable in case there are writers in the function.
|
||||
// Major case here is if a function is
|
||||
// void foo(int &var) { if (cond) var = 10; }
|
||||
@ -3036,6 +3046,10 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
auto *var = compiler.maybe_get_backing_variable(ptr);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
|
||||
// If we store through an access chain, we have a partial write.
|
||||
if (var && var->self == ptr && var->storage == StorageClassFunction)
|
||||
complete_write_variables_to_block[var->self].insert(current_block->self);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3063,6 +3077,10 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
|
||||
// If we store through an access chain, we have a partial write.
|
||||
if (var->self == lhs)
|
||||
complete_write_variables_to_block[var->self].insert(current_block->self);
|
||||
|
||||
var = compiler.maybe_get_backing_variable(rhs);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
@ -3103,6 +3121,10 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
auto *var = compiler.maybe_get_backing_variable(args[i]);
|
||||
if (var && var->storage == StorageClassFunction)
|
||||
accessed_variables_to_block[var->self].insert(current_block->self);
|
||||
|
||||
// Cannot easily prove if argument we pass to a function is completely written.
|
||||
// Usually, functions write to a dummy variable,
|
||||
// which is then copied to in full to the real argument.
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3128,6 +3150,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
|
||||
Compiler &compiler;
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> accessed_variables_to_block;
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> complete_write_variables_to_block;
|
||||
const SPIRBlock *current_block = nullptr;
|
||||
} handler(*this);
|
||||
|
||||
@ -3139,7 +3162,8 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry)
|
||||
CFG cfg(*this, entry);
|
||||
|
||||
// Analyze if there are parameters which need to be implicitly preserved with an "in" qualifier.
|
||||
analyze_parameter_preservation(entry, cfg, handler.accessed_variables_to_block);
|
||||
analyze_parameter_preservation(entry, cfg, handler.accessed_variables_to_block,
|
||||
handler.complete_write_variables_to_block);
|
||||
|
||||
unordered_map<uint32_t, uint32_t> potential_loop_variables;
|
||||
|
||||
|
@ -644,7 +644,8 @@ protected:
|
||||
|
||||
void analyze_parameter_preservation(
|
||||
SPIRFunction &entry, const CFG &cfg,
|
||||
const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &variable_to_blocks);
|
||||
const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &variable_to_blocks,
|
||||
const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &complete_write_blocks);
|
||||
|
||||
// If a variable ID or parameter ID is found in this set, a sampler is actually a shadow/comparison sampler.
|
||||
// SPIR-V does not support this distinction, so we must keep track of this information outside the type system.
|
||||
|
Loading…
Reference in New Issue
Block a user