Propagate NonUniformEXT to dependent expressions.

This decoration might only be present for the very last ID which is
consumed by a sampling or Load/Store instruction. To make sure our
access chains are emitted correctly, we have to back-propagate this
decoration.
This commit is contained in:
Hans-Kristian Arntzen 2019-07-08 11:19:38 +02:00
parent 13378ad1ac
commit d12b54bbb4
3 changed files with 74 additions and 4 deletions

View File

@ -832,8 +832,6 @@ void CompilerGLSL::emit_struct(SPIRType &type)
string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags)
{
string res;
if (flags.get(DecorationNonUniformEXT))
res += "nonuniformEXT ";
//if (flags & (1ull << DecorationSmooth))
// res += "smooth ";
if (flags.get(DecorationFlat))
@ -4617,6 +4615,10 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
inherited_expressions.push_back(coord);
// Make sure non-uniform decoration is back-propagated to where it needs to be.
if (has_decoration(img, DecorationNonUniformEXT))
propagate_nonuniform_qualifier(img);
switch (op)
{
case OpImageSampleDrefImplicitLod:
@ -7567,8 +7569,13 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
unroll_array_from_complex_load(id, ptr, expr);
auto &type = get<SPIRType>(result_type);
if (has_decoration(id, DecorationNonUniformEXT))
// Shouldn't need to check for ID, but current glslang codegen requires it in some cases
// when loading Image/Sampler descriptors. It does not hurt to check ID as well.
if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ptr, DecorationNonUniformEXT))
{
propagate_nonuniform_qualifier(ptr);
convert_non_uniform_expression(type, expr);
}
if (ptr_expression)
ptr_expression->need_transpose = old_need_transpose;
@ -7650,6 +7657,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto *var = maybe_get<SPIRVariable>(ops[0]);
if (has_decoration(ops[0], DecorationNonUniformEXT))
propagate_nonuniform_qualifier(ops[0]);
if (var && var->statically_assigned)
var->static_expression = ops[1];
else if (var && var->loop_variable && !var->loop_variable_enable)
@ -8032,7 +8042,14 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t rhs = ops[2];
bool pointer = get<SPIRType>(result_type).pointer;
if (expression_is_lvalue(rhs) && !pointer)
auto *chain = maybe_get<SPIRAccessChain>(rhs);
if (chain)
{
// Cannot lower to a SPIRExpression, just copy the object.
auto &e = set<SPIRAccessChain>(id, *chain);
e.self = id;
}
else if (expression_is_lvalue(rhs) && !pointer)
{
// Need a copy.
// For pointer types, we copy the pointer itself.
@ -8051,6 +8068,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
auto *var = maybe_get_backing_variable(rhs);
e.loaded_from = var ? var->self : 0;
}
// If we're copying an access chain, need to inherit the read expressions.
auto *rhs_expr = maybe_get<SPIRExpression>(rhs);
if (rhs_expr)
e.implied_read_expressions = rhs_expr->implied_read_expressions;
}
break;
}
@ -8985,6 +9007,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t result_type = ops[0];
uint32_t id = ops[1];
emit_sampled_image_op(result_type, id, ops[2], ops[3]);
inherit_expression_dependencies(id, ops[2]);
inherit_expression_dependencies(id, ops[3]);
break;
}
@ -12232,3 +12256,37 @@ void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal)
statement_no_indent("#line ", line_literal, " \"", get<SPIRString>(file_id).str, "\"");
}
}
void CompilerGLSL::propagate_nonuniform_qualifier(uint32_t id)
{
// SPIR-V might only tag the very last ID with NonUniformEXT, but for codegen,
// we need to know NonUniformEXT a little earlier, when the resource is actually loaded.
// Back-propagate the qualifier based on the expression dependency chain.
if (!has_decoration(id, DecorationNonUniformEXT))
{
set_decoration(id, DecorationNonUniformEXT);
force_recompile();
}
auto *e = maybe_get<SPIRExpression>(id);
auto *combined = maybe_get<SPIRCombinedImageSampler>(id);
auto *chain = maybe_get<SPIRAccessChain>(id);
if (e)
{
for (auto &expr : e->expression_dependencies)
propagate_nonuniform_qualifier(expr);
for (auto &expr : e->implied_read_expressions)
propagate_nonuniform_qualifier(expr);
}
else if (combined)
{
propagate_nonuniform_qualifier(combined->image);
propagate_nonuniform_qualifier(combined->sampler);
}
else if (chain)
{
for (auto &expr : chain->implied_read_expressions)
propagate_nonuniform_qualifier(expr);
}
}

View File

@ -672,6 +672,8 @@ protected:
void fixup_type_alias();
void reorder_type_alias();
void propagate_nonuniform_qualifier(uint32_t id);
private:
void init();
};

View File

@ -2479,6 +2479,10 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
inherited_expressions.push_back(coord);
// Make sure non-uniform decoration is back-propagated to where it needs to be.
if (has_decoration(img, DecorationNonUniformEXT))
propagate_nonuniform_qualifier(img);
switch (op)
{
case OpImageSampleDrefImplicitLod:
@ -3458,6 +3462,9 @@ void CompilerHLSL::emit_load(const Instruction &instruction)
uint32_t id = ops[1];
uint32_t ptr = ops[2];
if (has_decoration(ptr, DecorationNonUniformEXT))
propagate_nonuniform_qualifier(ptr);
auto load_expr = read_access_chain(*chain);
bool forward = should_forward(ptr) && forced_temporaries.find(id) == end(forced_temporaries);
@ -3491,6 +3498,9 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
// Make sure we trigger a read of the constituents in the access chain.
track_expression_read(chain.self);
if (has_decoration(chain.self, DecorationNonUniformEXT))
propagate_nonuniform_qualifier(chain.self);
SPIRType target_type;
target_type.basetype = SPIRType::UInt;
target_type.vecsize = type.vecsize;