Updated spirv-cross.

This commit is contained in:
Бранимир Караџић
2024-12-28 22:41:09 -08:00
parent b0ef2b8c4b
commit 3434a173a2
8 changed files with 780 additions and 54 deletions

View File

@@ -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.
@@ -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;
@@ -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

View File

@@ -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) ||
@@ -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)
{

View File

@@ -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.");
@@ -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)

View File

@@ -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.
@@ -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.
@@ -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))
{
@@ -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:
@@ -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
{
@@ -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;
@@ -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));
}
}
@@ -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.
@@ -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);
@@ -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 ";
@@ -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;
@@ -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))
{

View File

@@ -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;
@@ -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,
@@ -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);
}

View File

@@ -408,6 +408,8 @@ private:
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

File diff suppressed because it is too large Load Diff

View File

@@ -840,6 +840,7 @@ protected:
SPVFuncImplImageFence,
SPVFuncImplTextureCast,
SPVFuncImplMulExtended,
SPVFuncImplSetMeshOutputsEXT,
};
// If the underlying resource has been used for comparison then duplicate loads of that resource must be too
@@ -868,6 +869,9 @@ protected:
std::string type_to_glsl(const SPIRType &type, uint32_t id, bool member);
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
void emit_block_hints(const SPIRBlock &block) override;
void emit_mesh_entry_point();
void emit_mesh_outputs();
void emit_mesh_tasks(SPIRBlock &block) override;
// Allow Metal to use the array<T> template to make arrays a value type
std::string type_to_array_glsl(const SPIRType &type, uint32_t variable_id) override;
@@ -919,6 +923,7 @@ protected:
bool is_tesc_shader() const;
bool is_tese_shader() const;
bool is_mesh_shader() const;
void preprocess_op_codes();
void localize_global_variables();
@@ -933,6 +938,7 @@ protected:
std::unordered_set<uint32_t> &processed_func_ids);
uint32_t add_interface_block(spv::StorageClass storage, bool patch = false);
uint32_t add_interface_block_pointer(uint32_t ib_var_id, spv::StorageClass storage);
uint32_t add_meshlet_block(bool per_primitive);
struct InterfaceBlockMeta
{
@@ -1104,12 +1110,17 @@ protected:
uint32_t builtin_stage_input_size_id = 0;
uint32_t builtin_local_invocation_index_id = 0;
uint32_t builtin_workgroup_size_id = 0;
uint32_t builtin_mesh_primitive_indices_id = 0;
uint32_t builtin_mesh_sizes_id = 0;
uint32_t builtin_task_grid_id = 0;
uint32_t builtin_frag_depth_id = 0;
uint32_t swizzle_buffer_id = 0;
uint32_t buffer_size_buffer_id = 0;
uint32_t view_mask_buffer_id = 0;
uint32_t dynamic_offsets_buffer_id = 0;
uint32_t uint_type_id = 0;
uint32_t shared_uint_type_id = 0;
uint32_t meshlet_type_id = 0;
uint32_t argument_buffer_padding_buffer_type_id = 0;
uint32_t argument_buffer_padding_image_type_id = 0;
uint32_t argument_buffer_padding_sampler_type_id = 0;
@@ -1174,6 +1185,8 @@ protected:
VariableID stage_out_ptr_var_id = 0;
VariableID tess_level_inner_var_id = 0;
VariableID tess_level_outer_var_id = 0;
VariableID mesh_out_per_vertex = 0;
VariableID mesh_out_per_primitive = 0;
VariableID stage_out_masked_builtin_type_id = 0;
// Handle HLSL-style 0-based vertex/instance index.