Skip to content

Commit

Permalink
Updated spirv-cross.
Browse files Browse the repository at this point in the history
  • Loading branch information
bkaradzic committed Dec 29, 2024
1 parent b0ef2b8 commit 3434a17
Show file tree
Hide file tree
Showing 8 changed files with 780 additions and 54 deletions.
10 changes: 9 additions & 1 deletion 3rdparty/spirv-cross/spirv_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,9 @@ struct SPIRType : IVariant
// Keep internal types at the end.
ControlPointArray,
Interpolant,
Char
Char,
// MSL specific type, that is used by 'object'(analog of 'task' from glsl) shader.
MeshGridProperties
};

// Scalar/vector/matrix support.
Expand Down Expand Up @@ -746,6 +748,10 @@ struct SPIRExpression : IVariant
// A list of expressions which this expression depends on.
SmallVector<ID> expression_dependencies;

// Similar as expression dependencies, but does not stop the tracking for force-temporary variables.
// We need to know the full chain from store back to any SSA variable.
SmallVector<ID> invariance_dependencies;

// By reading this expression, we implicitly read these expressions as well.
// Used by access chain Store and Load since we read multiple expressions in this case.
SmallVector<ID> implied_read_expressions;
Expand Down Expand Up @@ -1598,6 +1604,8 @@ struct AccessChainMeta
bool flattened_struct = false;
bool relaxed_precision = false;
bool access_meshlet_position_y = false;
bool chain_is_builtin = false;
spv::BuiltIn builtin = {};
};

enum ExtendedDecorations
Expand Down
11 changes: 10 additions & 1 deletion 3rdparty/spirv-cross/spirv_cross.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2569,6 +2569,15 @@ void Compiler::add_active_interface_variable(uint32_t var_id)

void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_expression)
{
auto *ptr_e = maybe_get<SPIRExpression>(dst);

if (is_position_invariant() && ptr_e && maybe_get<SPIRExpression>(source_expression))
{
auto &deps = ptr_e->invariance_dependencies;
if (std::find(deps.begin(), deps.end(), source_expression) == deps.end())
deps.push_back(source_expression);
}

// Don't inherit any expression dependencies if the expression in dst
// is not a forwarded temporary.
if (forwarded_temporaries.find(dst) == end(forwarded_temporaries) ||
Expand All @@ -2577,7 +2586,7 @@ void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_exp
return;
}

auto &e = get<SPIRExpression>(dst);
auto &e = *ptr_e;
auto *phi = maybe_get<SPIRVariable>(source_expression);
if (phi && phi->phi_variable)
{
Expand Down
4 changes: 4 additions & 0 deletions 3rdparty/spirv-cross/spirv_cross_parsed_ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,8 @@ void ParsedIR::reset_all_of_type(Types type)

void ParsedIR::add_typed_id(Types type, ID id)
{
assert(id < ids.size());

if (loop_iteration_depth_hard != 0)
SPIRV_CROSS_THROW("Cannot add typed ID while looping over it.");

Expand Down Expand Up @@ -1030,6 +1032,8 @@ ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_

void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
{
assert(id < ids.size());

auto &constant_type = get<SPIRType>(type);

if (constant_type.pointer)
Expand Down
56 changes: 45 additions & 11 deletions 3rdparty/spirv-cross/spirv_glsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6438,7 +6438,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
if (splat)
{
res += convert_to_string(c.scalar(vector, 0));
if (is_legacy())
if (is_legacy() && !has_extension("GL_EXT_gpu_shader4"))
{
// Fake unsigned constant literals with signed ones if possible.
// Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
Expand All @@ -6457,7 +6457,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
else
{
res += convert_to_string(c.scalar(vector, i));
if (is_legacy())
if (is_legacy() && !has_extension("GL_EXT_gpu_shader4"))
{
// Fake unsigned constant literals with signed ones if possible.
// Things like array sizes, etc, tend to be unsigned even though they could just as easily be signed.
Expand Down Expand Up @@ -10210,6 +10210,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
bool pending_array_enclose = false;
bool dimension_flatten = false;
bool access_meshlet_position_y = false;
bool chain_is_builtin = false;
spv::BuiltIn chained_builtin = {};

if (auto *base_expr = maybe_get<SPIRExpression>(base))
{
Expand Down Expand Up @@ -10367,6 +10369,9 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
auto builtin = ir.meta[base].decoration.builtin_type;
bool mesh_shader = get_execution_model() == ExecutionModelMeshEXT;

chain_is_builtin = true;
chained_builtin = builtin;

switch (builtin)
{
case BuiltInCullDistance:
Expand Down Expand Up @@ -10502,6 +10507,9 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
{
access_meshlet_position_y = true;
}

chain_is_builtin = true;
chained_builtin = builtin;
}
else
{
Expand Down Expand Up @@ -10721,6 +10729,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
meta->storage_physical_type = physical_type;
meta->relaxed_precision = relaxed_precision;
meta->access_meshlet_position_y = access_meshlet_position_y;
meta->chain_is_builtin = chain_is_builtin;
meta->builtin = chained_builtin;
}

return expr;
Expand Down Expand Up @@ -11766,13 +11776,13 @@ void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression
// Allow trivially forwarded expressions like OpLoad or trivial shuffles,
// these will be marked as having suppressed usage tracking.
// Our only concern is to make sure arithmetic operations are done in similar ways.
if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) &&
forced_invariant_temporaries.count(expr.self) == 0)
if (forced_invariant_temporaries.count(expr.self) == 0)
{
force_temporary_and_recompile(expr.self);
if (!expression_suppresses_usage_tracking(expr.self))
force_temporary_and_recompile(expr.self);
forced_invariant_temporaries.insert(expr.self);

for (auto &dependent : expr.expression_dependencies)
for (auto &dependent : expr.invariance_dependencies)
disallow_forwarding_in_expression_chain(get<SPIRExpression>(dependent));
}
}
Expand Down Expand Up @@ -12336,6 +12346,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
flattened_structs[ops[1]] = true;
if (meta.relaxed_precision && backend.requires_relaxed_precision_analysis)
set_decoration(ops[1], DecorationRelaxedPrecision);
if (meta.chain_is_builtin)
set_decoration(ops[1], DecorationBuiltIn, meta.builtin);

// If we have some expression dependencies in our access chain, this access chain is technically a forwarded
// temporary which could be subject to invalidation.
Expand Down Expand Up @@ -13229,13 +13241,24 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
uint32_t op0 = ops[2];
uint32_t op1 = ops[3];

// Needs special handling.
auto &out_type = get<SPIRType>(result_type);

bool forward = should_forward(op0) && should_forward(op1);
auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(",
to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")");
string cast_op0, cast_op1;
auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, int_type, op0, op1, false);

// Needs special handling.
auto expr = join(cast_op0, " - ", cast_op1, " * ", "(", cast_op0, " / ", cast_op1, ")");

if (implicit_integer_promotion)
{
expr = join(type_to_glsl(get<SPIRType>(result_type)), '(', expr, ')');
}
else if (out_type.basetype != int_type)
{
expected_type.basetype = int_type;
expr = join(bitcast_glsl_op(out_type, expected_type), '(', expr, ')');
}

emit_op(result_type, result_id, expr, forward);
inherit_expression_dependencies(result_id, op0);
Expand Down Expand Up @@ -15668,7 +15691,16 @@ string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)

if (type.pointer)
{
if (arg.write_count && arg.read_count)
// If we're passing around block types to function, we really mean reference in a pointer sense,
// but DXC does not like inout for mesh blocks, so workaround that. out is technically not correct,
// but it works in practice due to legalization. It's ... not great, but you gotta do what you gotta do.
// GLSL will never hit this case since it's not valid.
if (type.storage == StorageClassOutput && get_execution_model() == ExecutionModelMeshEXT &&
has_decoration(type.self, DecorationBlock) && is_builtin_type(type) && arg.write_count)
{
direction = "out ";
}
else if (arg.write_count && arg.read_count)
direction = "inout ";
else if (arg.write_count)
direction = "out ";
Expand Down Expand Up @@ -15945,7 +15977,7 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id, bool /*m
case DimBuffer:
if (options.es && options.version < 320)
require_extension_internal("GL_EXT_texture_buffer");
else if (!options.es && options.version < 300)
else if (!options.es && options.version < 140)
require_extension_internal("GL_EXT_texture_buffer_object");
res += "Buffer";
break;
Expand Down Expand Up @@ -16488,6 +16520,8 @@ void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags)
{
auto &var = get<SPIRVariable>(v);
var.deferred_declaration = false;
if (var.storage == StorageClassTaskPayloadWorkgroupEXT)
continue;

if (variable_decl_is_remapped_storage(var, StorageClassWorkgroup))
{
Expand Down
88 changes: 82 additions & 6 deletions 3rdparty/spirv-cross/spirv_hlsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4775,13 +4775,13 @@ void CompilerHLSL::emit_load(const Instruction &instruction)
{
auto ops = stream(instruction);

auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
uint32_t result_type = ops[0];
uint32_t id = ops[1];
uint32_t ptr = ops[2];

auto *chain = maybe_get<SPIRAccessChain>(ptr);
if (chain)
{
uint32_t result_type = ops[0];
uint32_t id = ops[1];
uint32_t ptr = ops[2];

auto &type = get<SPIRType>(result_type);
bool composite_load = !type.array.empty() || type.basetype == SPIRType::Struct;

Expand Down Expand Up @@ -4819,7 +4819,36 @@ void CompilerHLSL::emit_load(const Instruction &instruction)
}
}
else
CompilerGLSL::emit_instruction(instruction);
{
// Very special case where we cannot rely on IO lowering.
// Mesh shader clip/cull arrays ... Cursed.
auto &res_type = get<SPIRType>(result_type);
if (get_execution_model() == ExecutionModelMeshEXT &&
has_decoration(ptr, DecorationBuiltIn) &&
(get_decoration(ptr, DecorationBuiltIn) == BuiltInClipDistance ||
get_decoration(ptr, DecorationBuiltIn) == BuiltInCullDistance) &&
is_array(res_type) && !is_array(get<SPIRType>(res_type.parent_type)) &&
to_array_size_literal(res_type) > 1)
{
track_expression_read(ptr);
string load_expr = "{ ";
uint32_t num_elements = to_array_size_literal(res_type);
for (uint32_t i = 0; i < num_elements; i++)
{
load_expr += join(to_expression(ptr), ".", index_to_swizzle(i));
if (i + 1 < num_elements)
load_expr += ", ";
}
load_expr += " }";
emit_op(result_type, id, load_expr, false);
register_read(id, ptr, false);
inherit_expression_dependencies(id, ptr);
}
else
{
CompilerGLSL::emit_instruction(instruction);
}
}
}

void CompilerHLSL::write_access_chain_array(const SPIRAccessChain &chain, uint32_t value,
Expand Down Expand Up @@ -6903,3 +6932,50 @@ bool CompilerHLSL::is_user_type_structured(uint32_t id) const
}
return false;
}

void CompilerHLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
{
// Loading a full array of ClipDistance needs special consideration in mesh shaders
// since we cannot lower them by wrapping the variables in global statics.
// Fortunately, clip/cull is a proper vector in HLSL so we can lower with simple rvalue casts.
if (get_execution_model() != ExecutionModelMeshEXT ||
!has_decoration(target_id, DecorationBuiltIn) ||
!is_array(expr_type))
{
CompilerGLSL::cast_to_variable_store(target_id, expr, expr_type);
return;
}

auto builtin = BuiltIn(get_decoration(target_id, DecorationBuiltIn));
if (builtin != BuiltInClipDistance && builtin != BuiltInCullDistance)
{
CompilerGLSL::cast_to_variable_store(target_id, expr, expr_type);
return;
}

// Array of array means one thread is storing clip distance for all vertices. Nonsensical?
if (is_array(get<SPIRType>(expr_type.parent_type)))
SPIRV_CROSS_THROW("Attempting to store all mesh vertices in one go. This is not supported.");

uint32_t num_clip = to_array_size_literal(expr_type);
if (num_clip > 4)
SPIRV_CROSS_THROW("Number of clip or cull distances exceeds 4, this will not work with mesh shaders.");

if (num_clip == 1)
{
// We already emit array here.
CompilerGLSL::cast_to_variable_store(target_id, expr, expr_type);
return;
}

auto unrolled_expr = join("float", num_clip, "(");
for (uint32_t i = 0; i < num_clip; i++)
{
unrolled_expr += join(expr, "[", i, "]");
if (i + 1 < num_clip)
unrolled_expr += ", ";
}

unrolled_expr += ")";
expr = std::move(unrolled_expr);
}
2 changes: 2 additions & 0 deletions 3rdparty/spirv-cross/spirv_hlsl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,8 @@ class CompilerHLSL : public CompilerGLSL
std::vector<TypeID> composite_selection_workaround_types;

std::string get_inner_entry_point_name() const;

void cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
};
} // namespace SPIRV_CROSS_NAMESPACE

Expand Down
Loading

0 comments on commit 3434a17

Please sign in to comment.