|
|
@@ -37,7 +37,7 @@ static const uint32_t k_unknown_component = ~0u;
|
|
|
static const char *force_inline = "static inline __attribute__((always_inline))";
|
|
|
|
|
|
CompilerMSL::CompilerMSL(std::vector<uint32_t> spirv_)
|
|
|
- : CompilerGLSL(move(spirv_))
|
|
|
+ : CompilerGLSL(std::move(spirv_))
|
|
|
{
|
|
|
}
|
|
|
|
|
|
@@ -1548,6 +1548,14 @@ void CompilerMSL::extract_global_variables_from_functions()
|
|
|
// Uniforms
|
|
|
unordered_set<uint32_t> global_var_ids;
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
|
|
+ // Some builtins resolve directly to a function call which does not need any declared variables.
|
|
|
+ // Skip these.
|
|
|
+ if (var.storage == StorageClassInput && has_decoration(var.self, DecorationBuiltIn) &&
|
|
|
+ BuiltIn(get_decoration(var.self, DecorationBuiltIn)) == BuiltInHelperInvocation)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (var.storage == StorageClassInput || var.storage == StorageClassOutput ||
|
|
|
var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
|
|
|
var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer)
|
|
|
@@ -2508,12 +2516,15 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
|
|
- SPIRType &ib_type, SPIRVariable &var,
|
|
|
- uint32_t mbr_idx, InterfaceBlockMeta &meta)
|
|
|
+void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage,
|
|
|
+ const string &ib_var_ref, SPIRType &ib_type,
|
|
|
+ SPIRVariable &var, SPIRType &var_type,
|
|
|
+ uint32_t mbr_idx, InterfaceBlockMeta &meta,
|
|
|
+ const string &mbr_name_qual,
|
|
|
+ const string &var_chain_qual,
|
|
|
+ uint32_t &location, uint32_t &var_mbr_idx)
|
|
|
{
|
|
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
|
|
- auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
|
|
|
|
|
BuiltIn builtin = BuiltInMax;
|
|
|
bool is_builtin = is_member_builtin(var_type, mbr_idx, &builtin);
|
|
|
@@ -2528,8 +2539,8 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
|
|
|
uint32_t mbr_type_id = var_type.member_types[mbr_idx];
|
|
|
auto &mbr_type = get<SPIRType>(mbr_type_id);
|
|
|
- uint32_t elem_cnt = 0;
|
|
|
|
|
|
+ uint32_t elem_cnt = 1;
|
|
|
if (is_matrix(mbr_type))
|
|
|
{
|
|
|
if (is_array(mbr_type))
|
|
|
@@ -2572,6 +2583,27 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // Recursively handle nested structures.
|
|
|
+ if (mbr_type.basetype == SPIRType::Struct)
|
|
|
+ {
|
|
|
+ for (uint32_t i = 0; i < elem_cnt; i++)
|
|
|
+ {
|
|
|
+ string mbr_name = append_member_name(mbr_name_qual, var_type, mbr_idx) + (elem_cnt == 1 ? "" : join("_", i));
|
|
|
+ string var_chain = join(var_chain_qual, ".", to_member_name(var_type, mbr_idx), (elem_cnt == 1 ? "" : join("[", i, "]")));
|
|
|
+ uint32_t sub_mbr_cnt = uint32_t(mbr_type.member_types.size());
|
|
|
+ for (uint32_t sub_mbr_idx = 0; sub_mbr_idx < sub_mbr_cnt; sub_mbr_idx++)
|
|
|
+ {
|
|
|
+ add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type,
|
|
|
+ var, mbr_type, sub_mbr_idx,
|
|
|
+ meta, mbr_name, var_chain,
|
|
|
+ location, var_mbr_idx);
|
|
|
+ // FIXME: Recursive structs and tessellation breaks here.
|
|
|
+ var_mbr_idx++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
for (uint32_t i = 0; i < elem_cnt; i++)
|
|
|
{
|
|
|
// Add a reference to the variable type to the interface struct.
|
|
|
@@ -2582,26 +2614,40 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
ib_type.member_types.push_back(usable_type->self);
|
|
|
|
|
|
// Give the member a name
|
|
|
- string mbr_name = ensure_valid_name(join(to_qualified_member_name(var_type, mbr_idx), "_", i), "m");
|
|
|
+ string mbr_name = ensure_valid_name(append_member_name(mbr_name_qual, var_type, mbr_idx) + (elem_cnt == 1 ? "" : join("_", i)), "m");
|
|
|
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
|
|
|
|
|
- if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation))
|
|
|
+ // Once we determine the location of the first member within nested structures,
|
|
|
+ // from a var of the topmost structure, the remaining flattened members of
|
|
|
+ // the nested structures will have consecutive location values. At this point,
|
|
|
+ // we've recursively tunnelled into structs, arrays, and matrices, and are
|
|
|
+ // down to a single location for each member now.
|
|
|
+ if (!is_builtin && location != UINT32_MAX)
|
|
|
{
|
|
|
- uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation) + i;
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, *usable_type, storage);
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, *usable_type, storage);
|
|
|
+ location++;
|
|
|
+ }
|
|
|
+ else if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation))
|
|
|
+ {
|
|
|
+ location = get_member_decoration(var_type.self, mbr_idx, DecorationLocation) + i;
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, *usable_type, storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
else if (has_decoration(var.self, DecorationLocation))
|
|
|
{
|
|
|
- uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i;
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, *usable_type, storage);
|
|
|
+ location = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i;
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, *usable_type, storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
|
|
{
|
|
|
- uint32_t locn = inputs_by_builtin[builtin].location + i;
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, *usable_type, storage);
|
|
|
+ location = inputs_by_builtin[builtin].location + i;
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, *usable_type, storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
else if (is_builtin && (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance))
|
|
|
{
|
|
|
@@ -2611,7 +2657,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
}
|
|
|
|
|
|
if (has_member_decoration(var_type.self, mbr_idx, DecorationComponent))
|
|
|
- SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays make little sense.");
|
|
|
+ SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays is not supported.");
|
|
|
|
|
|
if (storage != StorageClassInput || !pull_model_inputs.count(var.self))
|
|
|
{
|
|
|
@@ -2627,47 +2673,36 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
}
|
|
|
|
|
|
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
|
|
- set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
|
|
+ set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, var_mbr_idx);
|
|
|
|
|
|
// Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate.
|
|
|
if (!meta.strip_array && meta.allow_local_declaration)
|
|
|
{
|
|
|
+ string var_chain = join(var_chain_qual, ".", to_member_name(var_type, mbr_idx), (elem_cnt == 1 ? "" : join("[", i, "]")));
|
|
|
switch (storage)
|
|
|
{
|
|
|
case StorageClassInput:
|
|
|
- entry_func.fixup_hooks_in.push_back([=, &var, &var_type]() {
|
|
|
+ entry_func.fixup_hooks_in.push_back([=, &var]() {
|
|
|
+ string lerp_call;
|
|
|
if (pull_model_inputs.count(var.self))
|
|
|
{
|
|
|
- string lerp_call;
|
|
|
if (is_centroid)
|
|
|
lerp_call = ".interpolate_at_centroid()";
|
|
|
else if (is_sample)
|
|
|
lerp_call = join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")");
|
|
|
else
|
|
|
lerp_call = ".interpolate_at_center()";
|
|
|
- statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref,
|
|
|
- ".", mbr_name, lerp_call, ";");
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref,
|
|
|
- ".", mbr_name, ";");
|
|
|
}
|
|
|
+ statement(var_chain, " = ", ib_var_ref, ".", mbr_name, lerp_call, ";");
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
case StorageClassOutput:
|
|
|
- entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() {
|
|
|
+ entry_func.fixup_hooks_out.push_back([=]() {
|
|
|
if (flatten_from_ib_var)
|
|
|
- {
|
|
|
- statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i,
|
|
|
- "];");
|
|
|
- }
|
|
|
+ statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i, "];");
|
|
|
else
|
|
|
- {
|
|
|
- statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), ".",
|
|
|
- to_member_name(var_type, mbr_idx), "[", i, "];");
|
|
|
- }
|
|
|
+ statement(ib_var_ref, ".", mbr_name, " = ", var_chain, ";");
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
@@ -2678,11 +2713,14 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
|
|
|
- SPIRType &ib_type, SPIRVariable &var, uint32_t mbr_idx,
|
|
|
- InterfaceBlockMeta &meta)
|
|
|
+void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage,
|
|
|
+ const string &ib_var_ref, SPIRType &ib_type,
|
|
|
+ SPIRVariable &var, SPIRType &var_type,
|
|
|
+ uint32_t mbr_idx, InterfaceBlockMeta &meta,
|
|
|
+ const string &mbr_name_qual,
|
|
|
+ const string &var_chain_qual,
|
|
|
+ uint32_t &location, uint32_t &var_mbr_idx)
|
|
|
{
|
|
|
- auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
|
|
|
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
|
|
|
|
|
|
BuiltIn builtin = BuiltInMax;
|
|
|
@@ -2707,7 +2745,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
|
|
ib_type.member_types.push_back(mbr_type_id);
|
|
|
|
|
|
// Give the member a name
|
|
|
- string mbr_name = ensure_valid_name(to_qualified_member_name(var_type, mbr_idx), "m");
|
|
|
+ string mbr_name = ensure_valid_name(append_member_name(mbr_name_qual, var_type, mbr_idx), "m");
|
|
|
set_member_name(ib_type.self, ib_mbr_idx, mbr_name);
|
|
|
|
|
|
// Update the original variable reference to include the structure reference
|
|
|
@@ -2724,7 +2762,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
|
|
}
|
|
|
|
|
|
bool flatten_stage_out = false;
|
|
|
-
|
|
|
+ string var_chain = var_chain_qual + "." + to_member_name(var_type, mbr_idx);
|
|
|
if (is_builtin && !meta.strip_array)
|
|
|
{
|
|
|
// For the builtin gl_PerVertex, we cannot treat it as a block anyways,
|
|
|
@@ -2737,15 +2775,15 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
|
|
switch (storage)
|
|
|
{
|
|
|
case StorageClassInput:
|
|
|
- entry_func.fixup_hooks_in.push_back([=, &var, &var_type]() {
|
|
|
- statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), " = ", qual_var_name, ";");
|
|
|
+ entry_func.fixup_hooks_in.push_back([=]() {
|
|
|
+ statement(var_chain, " = ", qual_var_name, ";");
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
case StorageClassOutput:
|
|
|
flatten_stage_out = true;
|
|
|
- entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() {
|
|
|
- statement(qual_var_name, " = ", to_name(var.self), ".", to_member_name(var_type, mbr_idx), ";");
|
|
|
+ entry_func.fixup_hooks_out.push_back([=]() {
|
|
|
+ statement(qual_var_name, " = ", var_chain, ";");
|
|
|
});
|
|
|
break;
|
|
|
|
|
|
@@ -2754,48 +2792,56 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Copy the variable location from the original variable to the member
|
|
|
- if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation))
|
|
|
+ // Once we determine the location of the first member within nested structures,
|
|
|
+ // from a var of the topmost structure, the remaining flattened members of
|
|
|
+ // the nested structures will have consecutive location values. At this point,
|
|
|
+ // we've recursively tunnelled into structs, arrays, and matrices, and are
|
|
|
+ // down to a single location for each member now.
|
|
|
+ if (!is_builtin && location != UINT32_MAX)
|
|
|
{
|
|
|
- uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation);
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ location++;
|
|
|
+ }
|
|
|
+ else if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation))
|
|
|
+ {
|
|
|
+ location = get_member_decoration(var_type.self, mbr_idx, DecorationLocation);
|
|
|
uint32_t comp = get_member_decoration(var_type.self, mbr_idx, DecorationComponent);
|
|
|
if (storage == StorageClassInput)
|
|
|
{
|
|
|
- mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, comp, 0, meta.strip_array);
|
|
|
+ mbr_type_id = ensure_correct_input_type(mbr_type_id, location, comp, 0, meta.strip_array);
|
|
|
var_type.member_types[mbr_idx] = mbr_type_id;
|
|
|
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
|
|
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective);
|
|
|
else
|
|
|
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
|
|
}
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
else if (has_decoration(var.self, DecorationLocation))
|
|
|
{
|
|
|
- // The block itself might have a location and in this case, all members of the block
|
|
|
- // receive incrementing locations.
|
|
|
- uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array);
|
|
|
+ location = get_accumulated_member_location(var, mbr_idx, meta.strip_array);
|
|
|
if (storage == StorageClassInput)
|
|
|
{
|
|
|
- mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, 0, 0, meta.strip_array);
|
|
|
+ mbr_type_id = ensure_correct_input_type(mbr_type_id, location, 0, 0, meta.strip_array);
|
|
|
var_type.member_types[mbr_idx] = mbr_type_id;
|
|
|
if (storage == StorageClassInput && pull_model_inputs.count(var.self))
|
|
|
ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective);
|
|
|
else
|
|
|
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
|
|
|
}
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin))
|
|
|
{
|
|
|
- uint32_t locn = 0;
|
|
|
- auto builtin_itr = inputs_by_builtin.find(builtin);
|
|
|
- if (builtin_itr != end(inputs_by_builtin))
|
|
|
- locn = builtin_itr->second.location;
|
|
|
- set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
|
|
|
- mark_location_as_used_by_shader(locn, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ location = inputs_by_builtin[builtin].location;
|
|
|
+ set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
|
|
|
+ mark_location_as_used_by_shader(location, get<SPIRType>(mbr_type_id), storage);
|
|
|
+ location++;
|
|
|
}
|
|
|
|
|
|
// Copy the component location, if present.
|
|
|
@@ -2854,7 +2900,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor
|
|
|
}
|
|
|
|
|
|
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
|
|
|
- set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx);
|
|
|
+ set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, var_mbr_idx);
|
|
|
}
|
|
|
|
|
|
// In Metal, the tessellation levels are stored as tightly packed half-precision floating point values.
|
|
|
@@ -3114,67 +3160,102 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st
|
|
|
else
|
|
|
{
|
|
|
bool masked_block = false;
|
|
|
+ uint32_t location = UINT32_MAX;
|
|
|
+ uint32_t var_mbr_idx = 0;
|
|
|
+ uint32_t elem_cnt = 1;
|
|
|
+ if (is_matrix(var_type))
|
|
|
+ {
|
|
|
+ if (is_array(var_type))
|
|
|
+ SPIRV_CROSS_THROW("MSL cannot emit arrays-of-matrices in input and output variables.");
|
|
|
|
|
|
- // Flatten the struct members into the interface struct
|
|
|
- for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(var_type.member_types.size()); mbr_idx++)
|
|
|
+ elem_cnt = var_type.columns;
|
|
|
+ }
|
|
|
+ else if (is_array(var_type))
|
|
|
{
|
|
|
- builtin = BuiltInMax;
|
|
|
- is_builtin = is_member_builtin(var_type, mbr_idx, &builtin);
|
|
|
- auto &mbr_type = get<SPIRType>(var_type.member_types[mbr_idx]);
|
|
|
+ if (var_type.array.size() != 1)
|
|
|
+ SPIRV_CROSS_THROW("MSL cannot emit arrays-of-arrays in input and output variables.");
|
|
|
+
|
|
|
+ elem_cnt = to_array_size_literal(var_type);
|
|
|
+ }
|
|
|
|
|
|
- if (storage == StorageClassOutput && is_stage_output_block_member_masked(var, mbr_idx, meta.strip_array))
|
|
|
+ for (uint32_t elem_idx = 0; elem_idx < elem_cnt; elem_idx++)
|
|
|
+ {
|
|
|
+ // Flatten the struct members into the interface struct
|
|
|
+ for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(var_type.member_types.size()); mbr_idx++)
|
|
|
{
|
|
|
- if (is_block)
|
|
|
- masked_block = true;
|
|
|
+ builtin = BuiltInMax;
|
|
|
+ is_builtin = is_member_builtin(var_type, mbr_idx, &builtin);
|
|
|
+ auto &mbr_type = get<SPIRType>(var_type.member_types[mbr_idx]);
|
|
|
|
|
|
- // Non-builtin block output variables are just ignored, since they will still access
|
|
|
- // the block variable as-is. They're just not flattened.
|
|
|
- if (is_builtin && !meta.strip_array)
|
|
|
+ if (storage == StorageClassOutput && is_stage_output_block_member_masked(var, mbr_idx, meta.strip_array))
|
|
|
{
|
|
|
- // Emit a fake variable instead.
|
|
|
- uint32_t ids = ir.increase_bound_by(2);
|
|
|
- uint32_t ptr_type_id = ids + 0;
|
|
|
- uint32_t var_id = ids + 1;
|
|
|
-
|
|
|
- auto ptr_type = mbr_type;
|
|
|
- ptr_type.pointer = true;
|
|
|
- ptr_type.pointer_depth++;
|
|
|
- ptr_type.parent_type = var_type.member_types[mbr_idx];
|
|
|
- ptr_type.storage = StorageClassOutput;
|
|
|
-
|
|
|
- uint32_t initializer = 0;
|
|
|
- if (var.initializer)
|
|
|
- if (auto *c = maybe_get<SPIRConstant>(var.initializer))
|
|
|
- initializer = c->subconstants[mbr_idx];
|
|
|
-
|
|
|
- set<SPIRType>(ptr_type_id, ptr_type);
|
|
|
- set<SPIRVariable>(var_id, ptr_type_id, StorageClassOutput, initializer);
|
|
|
- entry_func.add_local_variable(var_id);
|
|
|
- vars_needing_early_declaration.push_back(var_id);
|
|
|
- set_name(var_id, builtin_to_glsl(builtin, StorageClassOutput));
|
|
|
- set_decoration(var_id, DecorationBuiltIn, builtin);
|
|
|
- }
|
|
|
- }
|
|
|
- else if (!is_builtin || has_active_builtin(builtin, storage))
|
|
|
- {
|
|
|
- bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type);
|
|
|
- bool attribute_load_store =
|
|
|
- storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
|
|
- bool storage_is_stage_io = variable_storage_requires_stage_io(storage);
|
|
|
+ location = UINT32_MAX; // Skip this member and resolve location again on next var member
|
|
|
|
|
|
- // Clip/CullDistance always need to be declared as user attributes.
|
|
|
- if (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance)
|
|
|
- is_builtin = false;
|
|
|
+ if (is_block)
|
|
|
+ masked_block = true;
|
|
|
|
|
|
- if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
|
|
- {
|
|
|
- add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx,
|
|
|
- meta);
|
|
|
+ // Non-builtin block output variables are just ignored, since they will still access
|
|
|
+ // the block variable as-is. They're just not flattened.
|
|
|
+ if (is_builtin && !meta.strip_array)
|
|
|
+ {
|
|
|
+ // Emit a fake variable instead.
|
|
|
+ uint32_t ids = ir.increase_bound_by(2);
|
|
|
+ uint32_t ptr_type_id = ids + 0;
|
|
|
+ uint32_t var_id = ids + 1;
|
|
|
+
|
|
|
+ auto ptr_type = mbr_type;
|
|
|
+ ptr_type.pointer = true;
|
|
|
+ ptr_type.pointer_depth++;
|
|
|
+ ptr_type.parent_type = var_type.member_types[mbr_idx];
|
|
|
+ ptr_type.storage = StorageClassOutput;
|
|
|
+
|
|
|
+ uint32_t initializer = 0;
|
|
|
+ if (var.initializer)
|
|
|
+ if (auto *c = maybe_get<SPIRConstant>(var.initializer))
|
|
|
+ initializer = c->subconstants[mbr_idx];
|
|
|
+
|
|
|
+ set<SPIRType>(ptr_type_id, ptr_type);
|
|
|
+ set<SPIRVariable>(var_id, ptr_type_id, StorageClassOutput, initializer);
|
|
|
+ entry_func.add_local_variable(var_id);
|
|
|
+ vars_needing_early_declaration.push_back(var_id);
|
|
|
+ set_name(var_id, builtin_to_glsl(builtin, StorageClassOutput));
|
|
|
+ set_decoration(var_id, DecorationBuiltIn, builtin);
|
|
|
+ }
|
|
|
}
|
|
|
- else
|
|
|
+ else if (!is_builtin || has_active_builtin(builtin, storage))
|
|
|
{
|
|
|
- add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, meta);
|
|
|
+ bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type) || mbr_type.basetype == SPIRType::Struct;
|
|
|
+ bool attribute_load_store =
|
|
|
+ storage == StorageClassInput && get_execution_model() != ExecutionModelFragment;
|
|
|
+ bool storage_is_stage_io = variable_storage_requires_stage_io(storage);
|
|
|
+
|
|
|
+ // Clip/CullDistance always need to be declared as user attributes.
|
|
|
+ if (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance)
|
|
|
+ is_builtin = false;
|
|
|
+
|
|
|
+ string mbr_name_qual = to_name(var_type.self);
|
|
|
+ string var_chain_qual = to_name(var.self);
|
|
|
+ if (elem_cnt > 1) {
|
|
|
+ mbr_name_qual += join("_", elem_idx);
|
|
|
+ var_chain_qual += join("[", elem_idx, "]");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type)
|
|
|
+ {
|
|
|
+ add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type,
|
|
|
+ var, var_type, mbr_idx, meta,
|
|
|
+ mbr_name_qual, var_chain_qual,
|
|
|
+ location, var_mbr_idx);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type,
|
|
|
+ var, var_type, mbr_idx, meta,
|
|
|
+ mbr_name_qual, var_chain_qual,
|
|
|
+ location, var_mbr_idx);
|
|
|
+ }
|
|
|
}
|
|
|
+ var_mbr_idx++;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -5370,7 +5451,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupBroadcast(T value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_broadcast(value, lane);");
|
|
|
else
|
|
|
statement("return simd_broadcast(value, lane);");
|
|
|
@@ -5379,7 +5460,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupBroadcast(bool value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_broadcast((ushort)value, lane);");
|
|
|
else
|
|
|
statement("return !!simd_broadcast((ushort)value, lane);");
|
|
|
@@ -5388,7 +5469,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupBroadcast(vec<bool, N> value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_broadcast((vec<ushort, N>)value, lane);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_broadcast((vec<ushort, N>)value, lane);");
|
|
|
@@ -5400,7 +5481,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupBroadcastFirst(T value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_broadcast_first(value);");
|
|
|
else
|
|
|
statement("return simd_broadcast_first(value);");
|
|
|
@@ -5409,7 +5490,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupBroadcastFirst(bool value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_broadcast_first((ushort)value);");
|
|
|
else
|
|
|
statement("return !!simd_broadcast_first((ushort)value);");
|
|
|
@@ -5418,7 +5499,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupBroadcastFirst(vec<bool, N> value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_broadcast_first((vec<ushort, N>)value);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_broadcast_first((vec<ushort, N>)value);");
|
|
|
@@ -5429,7 +5510,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
case SPVFuncImplSubgroupBallot:
|
|
|
statement("inline uint4 spvSubgroupBallot(bool value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
{
|
|
|
statement("return uint4((quad_vote::vote_t)quad_ballot(value), 0, 0, 0);");
|
|
|
}
|
|
|
@@ -5557,7 +5638,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline bool spvSubgroupAllEqual(T value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_all(all(value == quad_broadcast_first(value)));");
|
|
|
else
|
|
|
statement("return simd_all(all(value == simd_broadcast_first(value)));");
|
|
|
@@ -5566,7 +5647,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupAllEqual(bool value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_all(value) || !quad_any(value);");
|
|
|
else
|
|
|
statement("return simd_all(value) || !simd_any(value);");
|
|
|
@@ -5575,7 +5656,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline bool spvSubgroupAllEqual(vec<bool, N> value)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_all(all(value == (vec<bool, N>)quad_broadcast_first((vec<ushort, N>)value)));");
|
|
|
else
|
|
|
statement("return simd_all(all(value == (vec<bool, N>)simd_broadcast_first((vec<ushort, N>)value)));");
|
|
|
@@ -5587,7 +5668,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupShuffle(T value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_shuffle(value, lane);");
|
|
|
else
|
|
|
statement("return simd_shuffle(value, lane);");
|
|
|
@@ -5596,7 +5677,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupShuffle(bool value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_shuffle((ushort)value, lane);");
|
|
|
else
|
|
|
statement("return !!simd_shuffle((ushort)value, lane);");
|
|
|
@@ -5605,7 +5686,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupShuffle(vec<bool, N> value, ushort lane)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_shuffle((vec<ushort, N>)value, lane);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_shuffle((vec<ushort, N>)value, lane);");
|
|
|
@@ -5617,7 +5698,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupShuffleXor(T value, ushort mask)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_shuffle_xor(value, mask);");
|
|
|
else
|
|
|
statement("return simd_shuffle_xor(value, mask);");
|
|
|
@@ -5626,7 +5707,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupShuffleXor(bool value, ushort mask)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_shuffle_xor((ushort)value, mask);");
|
|
|
else
|
|
|
statement("return !!simd_shuffle_xor((ushort)value, mask);");
|
|
|
@@ -5635,7 +5716,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupShuffleXor(vec<bool, N> value, ushort mask)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_shuffle_xor((vec<ushort, N>)value, mask);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_shuffle_xor((vec<ushort, N>)value, mask);");
|
|
|
@@ -5647,7 +5728,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupShuffleUp(T value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_shuffle_up(value, delta);");
|
|
|
else
|
|
|
statement("return simd_shuffle_up(value, delta);");
|
|
|
@@ -5656,7 +5737,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupShuffleUp(bool value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_shuffle_up((ushort)value, delta);");
|
|
|
else
|
|
|
statement("return !!simd_shuffle_up((ushort)value, delta);");
|
|
|
@@ -5665,7 +5746,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupShuffleUp(vec<bool, N> value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_shuffle_up((vec<ushort, N>)value, delta);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_shuffle_up((vec<ushort, N>)value, delta);");
|
|
|
@@ -5677,7 +5758,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<typename T>");
|
|
|
statement("inline T spvSubgroupShuffleDown(T value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return quad_shuffle_down(value, delta);");
|
|
|
else
|
|
|
statement("return simd_shuffle_down(value, delta);");
|
|
|
@@ -5686,7 +5767,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<>");
|
|
|
statement("inline bool spvSubgroupShuffleDown(bool value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return !!quad_shuffle_down((ushort)value, delta);");
|
|
|
else
|
|
|
statement("return !!simd_shuffle_down((ushort)value, delta);");
|
|
|
@@ -5695,7 +5776,7 @@ void CompilerMSL::emit_custom_functions()
|
|
|
statement("template<uint N>");
|
|
|
statement("inline vec<bool, N> spvSubgroupShuffleDown(vec<bool, N> value, ushort delta)");
|
|
|
begin_scope();
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
statement("return (vec<bool, N>)quad_shuffle_down((vec<ushort, N>)value, delta);");
|
|
|
else
|
|
|
statement("return (vec<bool, N>)simd_shuffle_down((vec<ushort, N>)value, delta);");
|
|
|
@@ -7368,7 +7449,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
|
|
|
expr_type->vecsize > result_ptr_type.vecsize)
|
|
|
e += vector_swizzle(result_ptr_type.vecsize, 0);
|
|
|
|
|
|
- auto &expr = set<SPIRExpression>(ops[1], move(e), ops[0], should_forward(ops[2]));
|
|
|
+ auto &expr = set<SPIRExpression>(ops[1], std::move(e), ops[0], should_forward(ops[2]));
|
|
|
expr.loaded_from = var->self;
|
|
|
expr.need_transpose = meta.need_transpose;
|
|
|
expr.access_chain = true;
|
|
|
@@ -7559,6 +7640,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
|
|
auto ops = stream(instruction);
|
|
|
auto opcode = static_cast<Op>(instruction.op);
|
|
|
|
|
|
+ opcode = get_remapped_spirv_op(opcode);
|
|
|
+
|
|
|
// If we need to do implicit bitcasts, make sure we do it with the correct type.
|
|
|
uint32_t integer_width = get_integer_width_for_instruction(instruction);
|
|
|
auto int_type = to_signed_basetype(integer_width);
|
|
|
@@ -7601,6 +7684,10 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
|
|
|
|
|
case OpLogicalNotEqual:
|
|
|
case OpFOrdNotEqual:
|
|
|
+ // TODO: Should probably negate the == result here.
|
|
|
+ // Typically OrdNotEqual comes from GLSL which itself does not really specify what
|
|
|
+ // happens with NaN.
|
|
|
+ // Consider fixing this if we run into real issues.
|
|
|
MSL_BOP(!=);
|
|
|
break;
|
|
|
|
|
|
@@ -7657,7 +7744,9 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
|
|
break;
|
|
|
|
|
|
case OpFUnordNotEqual:
|
|
|
- MSL_UNORD_BOP(!=);
|
|
|
+ // not equal in MSL generates une opcodes to begin with.
|
|
|
+ // Since unordered not equal is how it works in C, just inherit that behavior.
|
|
|
+ MSL_BOP(!=);
|
|
|
break;
|
|
|
|
|
|
case OpFUnordGreaterThan:
|
|
|
@@ -8920,6 +9009,8 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
|
|
|
auto int_type = to_signed_basetype(integer_width);
|
|
|
auto uint_type = to_unsigned_basetype(integer_width);
|
|
|
|
|
|
+ op = get_remapped_glsl_op(op);
|
|
|
+
|
|
|
switch (op)
|
|
|
{
|
|
|
case GLSLstd450Sinh:
|
|
|
@@ -9335,6 +9426,9 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
|
|
|
else
|
|
|
decl += entry_point_args_classic(!func.arguments.empty());
|
|
|
|
|
|
+ // append entry point args to avoid conflicts in local variable names.
|
|
|
+ local_variable_names.insert(resource_names.begin(), resource_names.end());
|
|
|
+
|
|
|
// If entry point function has variables that require early declaration,
|
|
|
// ensure they each have an empty initializer, creating one if needed.
|
|
|
// This is done at this late stage because the initialization expression
|
|
|
@@ -10567,7 +10661,7 @@ string CompilerMSL::convert_row_major_matrix(string exp_str, const SPIRType &exp
|
|
|
{
|
|
|
if (!is_matrix(exp_type))
|
|
|
{
|
|
|
- return CompilerGLSL::convert_row_major_matrix(move(exp_str), exp_type, physical_type_id, is_packed);
|
|
|
+ return CompilerGLSL::convert_row_major_matrix(std::move(exp_str), exp_type, physical_type_id, is_packed);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -12077,16 +12171,6 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
|
|
|
});
|
|
|
}
|
|
|
break;
|
|
|
- case BuiltInHelperInvocation:
|
|
|
- if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3))
|
|
|
- SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS.");
|
|
|
- else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1))
|
|
|
- SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS.");
|
|
|
-
|
|
|
- entry_func.fixup_hooks_in.push_back([=]() {
|
|
|
- statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = simd_is_helper_thread();");
|
|
|
- });
|
|
|
- break;
|
|
|
case BuiltInInvocationId:
|
|
|
// This is direct-mapped without multi-patch workgroups.
|
|
|
if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup)
|
|
|
@@ -12979,8 +13063,8 @@ string CompilerMSL::to_name(uint32_t id, bool allow_alias) const
|
|
|
return Compiler::to_name(id, allow_alias);
|
|
|
}
|
|
|
|
|
|
-// Returns a name that combines the name of the struct with the name of the member, except for Builtins
|
|
|
-string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t index)
|
|
|
+// Appends the name of the member to the variable qualifier string, except for Builtins.
|
|
|
+string CompilerMSL::append_member_name(const string &qualifier, const SPIRType &type, uint32_t index)
|
|
|
{
|
|
|
// Don't qualify Builtin names because they are unique and are treated as such when building expressions
|
|
|
BuiltIn builtin = BuiltInMax;
|
|
|
@@ -12991,7 +13075,7 @@ string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t inde
|
|
|
string mbr_name = to_member_name(type, index);
|
|
|
size_t startPos = mbr_name.find_first_not_of("_");
|
|
|
mbr_name = (startPos != string::npos) ? mbr_name.substr(startPos) : "";
|
|
|
- return join(to_name(type.self), "_", mbr_name);
|
|
|
+ return join(qualifier, "_", mbr_name);
|
|
|
}
|
|
|
|
|
|
// Ensures that the specified name is permanently usable by prepending a prefix
|
|
|
@@ -13969,7 +14053,7 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
|
|
|
switch (op)
|
|
|
{
|
|
|
case OpGroupNonUniformElect:
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
emit_op(result_type, id, "quad_is_first()", false);
|
|
|
else
|
|
|
emit_op(result_type, id, "simd_is_first()", false);
|
|
|
@@ -14042,14 +14126,14 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
|
|
|
break;
|
|
|
|
|
|
case OpGroupNonUniformAll:
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
emit_unary_func_op(result_type, id, ops[3], "quad_all");
|
|
|
else
|
|
|
emit_unary_func_op(result_type, id, ops[3], "simd_all");
|
|
|
break;
|
|
|
|
|
|
case OpGroupNonUniformAny:
|
|
|
- if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions)
|
|
|
+ if (msl_options.use_quadgroup_operation())
|
|
|
emit_unary_func_op(result_type, id, ops[3], "quad_any");
|
|
|
else
|
|
|
emit_unary_func_op(result_type, id, ops[3], "simd_any");
|
|
|
@@ -14381,6 +14465,14 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
+ case BuiltInHelperInvocation:
|
|
|
+ if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3))
|
|
|
+ SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS.");
|
|
|
+ else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1))
|
|
|
+ SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS.");
|
|
|
+ // In SPIR-V 1.6 with Volatile HelperInvocation, we cannot emit a fixup early.
|
|
|
+ return "simd_is_helper_thread()";
|
|
|
+
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
@@ -14547,7 +14639,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
|
|
|
SPIRV_CROSS_THROW("NumSubgroups is handled specially with emulation.");
|
|
|
if (!msl_options.supports_msl_version(2))
|
|
|
SPIRV_CROSS_THROW("Subgroup builtins require Metal 2.0.");
|
|
|
- return msl_options.is_ios() ? "quadgroups_per_threadgroup" : "simdgroups_per_threadgroup";
|
|
|
+ return msl_options.use_quadgroup_operation() ? "quadgroups_per_threadgroup" : "simdgroups_per_threadgroup";
|
|
|
|
|
|
case BuiltInSubgroupId:
|
|
|
if (msl_options.emulate_subgroups)
|
|
|
@@ -14555,7 +14647,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
|
|
|
SPIRV_CROSS_THROW("SubgroupId is handled specially with emulation.");
|
|
|
if (!msl_options.supports_msl_version(2))
|
|
|
SPIRV_CROSS_THROW("Subgroup builtins require Metal 2.0.");
|
|
|
- return msl_options.is_ios() ? "quadgroup_index_in_threadgroup" : "simdgroup_index_in_threadgroup";
|
|
|
+ return msl_options.use_quadgroup_operation() ? "quadgroup_index_in_threadgroup" : "simdgroup_index_in_threadgroup";
|
|
|
|
|
|
case BuiltInSubgroupLocalInvocationId:
|
|
|
if (msl_options.emulate_subgroups)
|
|
|
@@ -14574,7 +14666,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
|
|
|
// We are generating a Metal kernel function.
|
|
|
if (!msl_options.supports_msl_version(2))
|
|
|
SPIRV_CROSS_THROW("Subgroup builtins in kernel functions require Metal 2.0.");
|
|
|
- return msl_options.is_ios() ? "thread_index_in_quadgroup" : "thread_index_in_simdgroup";
|
|
|
+ return msl_options.use_quadgroup_operation() ? "thread_index_in_quadgroup" : "thread_index_in_simdgroup";
|
|
|
}
|
|
|
else
|
|
|
SPIRV_CROSS_THROW("Subgroup builtins are not available in this type of function.");
|