Updated spirv-cross.

This commit is contained in:
Бранимир Караџић
2021-05-28 20:17:12 -07:00
parent 4ada836d3d
commit f0b68fd9d4
5 changed files with 245 additions and 86 deletions

View File

@@ -658,10 +658,12 @@ struct CLIArguments
bool msl_emulate_subgroups = false;
uint32_t msl_fixed_subgroup_size = 0;
bool msl_force_sample_rate_shading = false;
const char *msl_combined_sampler_suffix = nullptr;
bool glsl_emit_push_constant_as_ubo = false;
bool glsl_emit_ubo_as_plain_uniforms = false;
bool glsl_force_flattened_io_blocks = false;
SmallVector<pair<uint32_t, uint32_t>> glsl_ext_framebuffer_fetch;
bool glsl_ext_framebuffer_fetch_noncoherent = false;
bool vulkan_glsl_disable_ext_samplerless_texture_functions = false;
bool emit_line_directives = false;
bool enable_storage_image_qualifier_deduction = true;
@@ -754,6 +756,7 @@ static void print_help_glsl()
"\t[--glsl-emit-ubo-as-plain-uniforms]:\n\t\tInstead of emitting UBOs, emit them as plain uniform structs.\n"
"\t[--glsl-remap-ext-framebuffer-fetch input-attachment color-location]:\n\t\tRemaps an input attachment to use GL_EXT_shader_framebuffer_fetch.\n"
"\t\tgl_LastFragData[location] is read from. The attachment to read from must be declared as an output in the shader.\n"
"\t[--glsl-ext-framebuffer-fetch-noncoherent]:\n\t\tUses noncoherent qualifier for framebuffer fetch.\n"
"\t[--vulkan-glsl-disable-ext-samplerless-texture-functions]:\n\t\tDo not allow use of GL_EXT_samperless_texture_functions, even in Vulkan GLSL.\n"
"\t\tUse of texelFetch and similar might have to create dummy samplers to work around it.\n"
"\t[--combined-samplers-inherit-bindings]:\n\t\tInherit binding information from the textures when building combined image samplers from separate textures and samplers.\n"
@@ -882,7 +885,8 @@ static void print_help_msl()
"\t\tIntended for Vulkan Portability implementations where VK_EXT_subgroup_size_control is not supported or disabled.\n"
"\t\tIf 0, assume variable subgroup size as actually exposed by Metal.\n"
"\t[--msl-force-sample-rate-shading]:\n\t\tForce fragment shaders to run per sample.\n"
"\t\tThis adds a [[sample_id]] parameter if none is already present.\n");
"\t\tThis adds a [[sample_id]] parameter if none is already present.\n"
"\t[--msl-combined-sampler-suffix <suffix>]:\n\t\tUses a custom suffix for combined samplers.\n");
// clang-format on
}
@@ -1145,6 +1149,8 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
msl_comp->add_inline_uniform_block(v.first, v.second);
for (auto &v : args.msl_shader_inputs)
msl_comp->add_msl_shader_input(v);
if (args.msl_combined_sampler_suffix)
msl_comp->set_combined_sampler_suffix(args.msl_combined_sampler_suffix);
}
else if (args.hlsl)
compiler.reset(new CompilerHLSL(move(spirv_parser.get_parsed_ir())));
@@ -1279,7 +1285,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
compiler->set_common_options(opts);
for (auto &fetch : args.glsl_ext_framebuffer_fetch)
compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second);
compiler->remap_ext_framebuffer_fetch(fetch.first, fetch.second, !args.glsl_ext_framebuffer_fetch_noncoherent);
// Set HLSL specific options.
if (args.hlsl)
@@ -1469,6 +1475,9 @@ static int main_inner(int argc, char *argv[])
uint32_t color_attachment = parser.next_uint();
args.glsl_ext_framebuffer_fetch.push_back({ input_index, color_attachment });
});
cbs.add("--glsl-ext-framebuffer-fetch-noncoherent", [&args](CLIParser &) {
args.glsl_ext_framebuffer_fetch_noncoherent = true;
});
cbs.add("--vulkan-glsl-disable-ext-samplerless-texture-functions",
[&args](CLIParser &) { args.vulkan_glsl_disable_ext_samplerless_texture_functions = true; });
cbs.add("--disable-storage-image-qualifier-deduction",
@@ -1572,6 +1581,9 @@ static int main_inner(int argc, char *argv[])
cbs.add("--msl-fixed-subgroup-size",
[&args](CLIParser &parser) { args.msl_fixed_subgroup_size = parser.next_uint(); });
cbs.add("--msl-force-sample-rate-shading", [&args](CLIParser &) { args.msl_force_sample_rate_shading = true; });
cbs.add("--msl-combined-sampler-suffix", [&args](CLIParser &parser) {
args.msl_combined_sampler_suffix = parser.next_string();
});
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
auto old_name = parser.next_string();

View File

@@ -359,10 +359,26 @@ void CompilerGLSL::remap_pls_variables()
}
}
void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location)
void CompilerGLSL::remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent)
{
subpass_to_framebuffer_fetch_attachment.push_back({ input_attachment_index, color_location });
inout_color_attachments.insert(color_location);
inout_color_attachments.push_back({ color_location, coherent });
}
bool CompilerGLSL::location_is_framebuffer_fetch(uint32_t location) const
{
return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
[&](const std::pair<uint32_t, bool> &elem) {
return elem.first == location;
}) != end(inout_color_attachments);
}
bool CompilerGLSL::location_is_non_coherent_framebuffer_fetch(uint32_t location) const
{
return std::find_if(begin(inout_color_attachments), end(inout_color_attachments),
[&](const std::pair<uint32_t, bool> &elem) {
return elem.first == location && !elem.second;
}) != end(inout_color_attachments);
}
void CompilerGLSL::find_static_extensions()
@@ -484,7 +500,22 @@ void CompilerGLSL::find_static_extensions()
SPIRV_CROSS_THROW("Can only use GL_EXT_shader_framebuffer_fetch in fragment shaders.");
if (options.vulkan_semantics)
SPIRV_CROSS_THROW("Cannot use EXT_shader_framebuffer_fetch in Vulkan GLSL.");
require_extension_internal("GL_EXT_shader_framebuffer_fetch");
bool has_coherent = false;
bool has_incoherent = false;
for (auto &att : inout_color_attachments)
{
if (att.second)
has_coherent = true;
else
has_incoherent = true;
}
if (has_coherent)
require_extension_internal("GL_EXT_shader_framebuffer_fetch");
if (has_incoherent)
require_extension_internal("GL_EXT_shader_framebuffer_fetch_non_coherent");
}
if (options.separate_shader_objects && !options.es && options.version < 410)
@@ -1693,6 +1724,12 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
attr.push_back(join("location = ", get_decoration(var.self, DecorationLocation)));
}
if (get_execution_model() == ExecutionModelFragment && var.storage == StorageClassOutput &&
location_is_non_coherent_framebuffer_fetch(get_decoration(var.self, DecorationLocation)))
{
attr.push_back("noncoherent");
}
// Transform feedback
bool uses_enhanced_layouts = false;
if (is_block && var.storage == StorageClassOutput)
@@ -2234,7 +2271,9 @@ const char *CompilerGLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
return "varying "; // Fragment outputs are renamed so they never hit this case.
else if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
{
if (inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
uint32_t loc = get_decoration(var.self, DecorationLocation);
bool is_inout = location_is_framebuffer_fetch(loc);
if (is_inout)
return "inout ";
else
return "out ";
@@ -3405,7 +3444,7 @@ void CompilerGLSL::emit_resources()
// Unused output I/O variables might still be required to implement framebuffer fetch.
if (var.storage == StorageClassOutput && !is_legacy() &&
inout_color_attachments.count(get_decoration(var.self, DecorationLocation)) != 0)
location_is_framebuffer_fetch(get_decoration(var.self, DecorationLocation)) != 0)
{
is_hidden = false;
}
@@ -4909,7 +4948,13 @@ string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col
char print_buffer[32];
sprintf(print_buffer, "0x%xu", c.scalar(col, row));
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
const char *comment = "inf";
if (float_value == -numeric_limits<float>::infinity())
comment = "-inf";
else if (std::isnan(float_value))
comment = "nan";
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
}
else
{
@@ -4976,7 +5021,13 @@ std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32
char print_buffer[64];
sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
backend.long_long_literal_suffix ? "ull" : "ul");
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
const char *comment = "inf";
if (double_value == -numeric_limits<double>::infinity())
comment = "-inf";
else if (std::isnan(double_value))
comment = "nan";
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, " /* ", comment, " */)");
}
else
{

View File

@@ -178,7 +178,8 @@ public:
// Redirect a subpassInput reading from input_attachment_index to instead load its value from
// the color attachment at location = color_location. Requires ESSL.
void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location);
// If coherent, uses GL_EXT_shader_framebuffer_fetch, if not, uses noncoherent variant.
void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent);
explicit CompilerGLSL(std::vector<uint32_t> spirv_)
: Compiler(std::move(spirv_))
@@ -858,7 +859,9 @@ protected:
// GL_EXT_shader_framebuffer_fetch support.
std::vector<std::pair<uint32_t, uint32_t>> subpass_to_framebuffer_fetch_attachment;
std::unordered_set<uint32_t> inout_color_attachments;
std::vector<std::pair<uint32_t, bool>> inout_color_attachments;
bool location_is_framebuffer_fetch(uint32_t location) const;
bool location_is_non_coherent_framebuffer_fetch(uint32_t location) const;
bool subpass_input_is_framebuffer_fetch(uint32_t id) const;
void emit_inout_fragment_outputs_copy_to_subpass_inputs();
const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const;

View File

@@ -1991,6 +1991,92 @@ uint32_t CompilerMSL::build_msl_interpolant_type(uint32_t type_id, bool is_noper
return new_type_id;
}
bool CompilerMSL::add_component_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
SPIRVariable &var,
const SPIRType &type,
InterfaceBlockMeta &meta)
{
// Deal with Component decorations.
const InterfaceBlockMeta::LocationMeta *location_meta = nullptr;
uint32_t location = ~0u;
if (has_decoration(var.self, DecorationLocation))
{
location = get_decoration(var.self, DecorationLocation);
auto location_meta_itr = meta.location_meta.find(location);
if (location_meta_itr != end(meta.location_meta))
location_meta = &location_meta_itr->second;
}
// Check if we need to pad fragment output to match a certain number of components.
if (location_meta)
{
bool pad_fragment_output = has_decoration(var.self, DecorationLocation) &&
msl_options.pad_fragment_output_components &&
get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput;
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
uint32_t start_component = get_decoration(var.self, DecorationComponent);
uint32_t type_components = type.vecsize;
uint32_t num_components = location_meta->num_components;
if (pad_fragment_output)
{
uint32_t locn = get_decoration(var.self, DecorationLocation);
num_components = std::max(num_components, get_target_components_for_fragment_location(locn));
}
// We have already declared an IO block member as m_location_N.
// Just emit an early-declared variable and fixup as needed.
// Arrays need to be unrolled here since each location might need a different number of components.
entry_func.add_local_variable(var.self);
vars_needing_early_declaration.push_back(var.self);
if (var.storage == StorageClassInput)
{
entry_func.fixup_hooks_in.push_back([=, &type, &var]() {
if (!type.array.empty())
{
uint32_t array_size = to_array_size_literal(type);
for (uint32_t loc_off = 0; loc_off < array_size; loc_off++)
{
statement(to_name(var.self), "[", loc_off, "]", " = ", ib_var_ref,
".m_location_", location + loc_off,
vector_swizzle(type_components, start_component), ";");
}
}
else
{
statement(to_name(var.self), " = ", ib_var_ref, ".m_location_", location,
vector_swizzle(type_components, start_component), ";");
}
});
}
else
{
entry_func.fixup_hooks_out.push_back([=, &type, &var]() {
if (!type.array.empty())
{
uint32_t array_size = to_array_size_literal(type);
for (uint32_t loc_off = 0; loc_off < array_size; loc_off++)
{
statement(ib_var_ref, ".m_location_", location + loc_off,
vector_swizzle(type_components, start_component), " = ",
to_name(var.self), "[", loc_off, "];");
}
}
else
{
statement(ib_var_ref, ".m_location_", location,
vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";");
}
});
}
return true;
}
else
return false;
}
void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta)
{
@@ -2019,65 +2105,14 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
// Deal with Component decorations.
InterfaceBlockMeta::LocationMeta *location_meta = nullptr;
if (has_decoration(var.self, DecorationLocation))
{
auto location_meta_itr = meta.location_meta.find(get_decoration(var.self, DecorationLocation));
if (location_meta_itr != end(meta.location_meta))
location_meta = &location_meta_itr->second;
}
if (add_component_variable_to_interface_block(storage, ib_var_ref, var, type, meta))
return;
bool pad_fragment_output = has_decoration(var.self, DecorationLocation) &&
msl_options.pad_fragment_output_components &&
get_entry_point().model == ExecutionModelFragment && storage == StorageClassOutput;
// Check if we need to pad fragment output to match a certain number of components.
if (location_meta)
{
start_component = get_decoration(var.self, DecorationComponent);
uint32_t num_components = location_meta->num_components;
if (pad_fragment_output)
{
uint32_t locn = get_decoration(var.self, DecorationLocation);
num_components = std::max(num_components, get_target_components_for_fragment_location(locn));
}
if (location_meta->ib_index != ~0u)
{
// We have already declared the variable. Just emit an early-declared variable and fixup as needed.
entry_func.add_local_variable(var.self);
vars_needing_early_declaration.push_back(var.self);
if (var.storage == StorageClassInput)
{
uint32_t ib_index = location_meta->ib_index;
entry_func.fixup_hooks_in.push_back([=, &var]() {
statement(to_name(var.self), " = ", ib_var_ref, ".", to_member_name(ib_type, ib_index),
vector_swizzle(type_components, start_component), ";");
});
}
else
{
uint32_t ib_index = location_meta->ib_index;
entry_func.fixup_hooks_out.push_back([=, &var]() {
statement(ib_var_ref, ".", to_member_name(ib_type, ib_index),
vector_swizzle(type_components, start_component), " = ", to_name(var.self), ";");
});
}
return;
}
else
{
location_meta->ib_index = uint32_t(ib_type.member_types.size());
type_id = build_extended_vector_type(type_id, num_components);
if (var.storage == StorageClassInput)
padded_input = true;
else
padded_output = true;
}
}
else if (pad_fragment_output)
if (pad_fragment_output)
{
uint32_t locn = get_decoration(var.self, DecorationLocation);
target_components = get_target_components_for_fragment_location(locn);
@@ -2169,11 +2204,8 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
uint32_t locn = get_decoration(var.self, DecorationLocation);
if (storage == StorageClassInput)
{
type_id = ensure_correct_input_type(var.basetype, locn,
location_meta ? location_meta->num_components : 0,
meta.strip_array);
if (!location_meta)
var.basetype = type_id;
type_id = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array);
var.basetype = type_id;
type_id = get_pointee_type_id(type_id);
if (meta.strip_array && is_array(get<SPIRType>(type_id)))
@@ -2193,13 +2225,10 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
mark_location_as_used_by_shader(locn, type, storage);
}
if (!location_meta)
if (get_decoration_bitset(var.self).get(DecorationComponent))
{
if (get_decoration_bitset(var.self).get(DecorationComponent))
{
uint32_t component = get_decoration(var.self, DecorationComponent);
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component);
}
uint32_t component = get_decoration(var.self, DecorationComponent);
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, component);
}
if (get_decoration_bitset(var.self).get(DecorationIndex))
@@ -2229,10 +2258,7 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
}
// If we have location meta, there is no unique OrigID. We won't need it, since we flatten/unflatten
// the variable to stack anyways here.
if (!location_meta)
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self);
}
void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage, const string &ib_var_ref,
@@ -2243,6 +2269,9 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var);
uint32_t elem_cnt = 0;
if (add_component_variable_to_interface_block(storage, ib_var_ref, var, var_type, meta))
return;
if (is_matrix(var_type))
{
if (is_array(var_type))
@@ -2339,6 +2368,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
if (get_decoration_bitset(var.self).get(DecorationLocation))
{
uint32_t locn = get_decoration(var.self, DecorationLocation) + i;
uint32_t comp = get_decoration(var.self, DecorationComponent);
if (storage == StorageClassInput)
{
var.basetype = ensure_correct_input_type(var.basetype, locn, 0, meta.strip_array);
@@ -2349,6 +2379,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
ib_type.member_types[ib_mbr_idx] = mbr_type_id;
}
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn);
if (comp)
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationComponent, comp);
mark_location_as_used_by_shader(locn, *usable_type, storage);
}
else if (is_builtin && is_tessellation_shader() && inputs_by_builtin.count(builtin))
@@ -3319,7 +3351,6 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
// Need to deal specially with DecorationComponent.
// Multiple variables can alias the same Location, and try to make sure each location is declared only once.
// We will swizzle data in and out to make this work.
// We only need to consider plain variables here, not composites.
// This is only relevant for vertex inputs and fragment outputs.
// Technically tessellation as well, but it is too complicated to support.
uint32_t component = get_decoration(var_id, DecorationComponent);
@@ -3329,8 +3360,22 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
SPIRV_CROSS_THROW("Component decoration is not supported in tessellation shaders.");
else if (pack_components)
{
auto &location_meta = meta.location_meta[location];
location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize);
uint32_t array_size = 1;
if (!type.array.empty())
array_size = to_array_size_literal(type);
for (uint32_t location_offset = 0; location_offset < array_size; location_offset++)
{
auto &location_meta = meta.location_meta[location + location_offset];
location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize);
// For variables sharing location, decorations and base type must match.
location_meta.base_type_id = type.self;
location_meta.flat = has_decoration(var.self, DecorationFlat);
location_meta.noperspective = has_decoration(var.self, DecorationNoPerspective);
location_meta.centroid = has_decoration(var.self, DecorationCentroid);
location_meta.sample = has_decoration(var.self, DecorationSample);
}
}
}
}
@@ -3579,6 +3624,31 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
}
}
// When multiple variables need to access same location,
// unroll locations one by one and we will flatten output or input as necessary.
for (auto &loc : meta.location_meta)
{
uint32_t location = loc.first;
auto &location_meta = loc.second;
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
uint32_t type_id = build_extended_vector_type(location_meta.base_type_id, location_meta.num_components);
ib_type.member_types.push_back(type_id);
set_member_name(ib_type.self, ib_mbr_idx, join("m_location_", location));
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location);
mark_location_as_used_by_shader(location, get<SPIRType>(type_id), storage);
if (location_meta.flat)
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationFlat);
if (location_meta.noperspective)
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationNoPerspective);
if (location_meta.centroid)
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationCentroid);
if (location_meta.sample)
set_member_decoration(ib_type.self, ib_mbr_idx, DecorationSample);
}
// Sort the members of the structure by their locations.
MemberSorter member_sorter(ib_type, ir.meta[ib_type_id], MemberSorter::LocationThenBuiltInType);
member_sorter.sort();
@@ -7075,7 +7145,17 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
uint32_t const_mbr_id = next_id++;
uint32_t index = get_extended_decoration(ops[2], SPIRVCrossDecorationInterfaceMemberIndex);
if (flatten_composites || is_block)
// If we have a pointer chain expression, and we are no longer pointing to a composite
// object, we are in the clear. There is no longer a need to flatten anything.
bool further_access_chain_is_trivial = false;
if (ptr_is_chain && flatten_composites)
{
auto &ptr_type = expression_type(ptr);
if (!is_array(ptr_type) && !is_matrix(ptr_type) && ptr_type.basetype != SPIRType::Struct)
further_access_chain_is_trivial = true;
}
if (!further_access_chain_is_trivial && (flatten_composites || is_block))
{
uint32_t i = first_non_array_index;
auto *type = &get_variable_element_type(*var);
@@ -7191,7 +7271,11 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
// First one is the gl_in/gl_out struct itself, then an index into that array.
// If we have traversed further, we use a normal access chain formulation.
auto *ptr_expr = maybe_get<SPIRExpression>(ptr);
if (flatten_composites && ptr_expr && ptr_expr->implied_read_expressions.size() == 2)
bool split_access_chain_formulation = flatten_composites && ptr_expr &&
ptr_expr->implied_read_expressions.size() == 2 &&
!further_access_chain_is_trivial;
if (split_access_chain_formulation)
{
e = join(to_expression(ptr),
access_chain_internal(stage_var_id, indices.data(), uint32_t(indices.size()),
@@ -15112,6 +15196,8 @@ bool CompilerMSL::MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
return mbr_meta2.builtin;
else if (mbr_meta1.builtin)
return mbr_meta1.builtin_type < mbr_meta2.builtin_type;
else if (mbr_meta1.location == mbr_meta2.location)
return mbr_meta1.component < mbr_meta2.component;
else
return mbr_meta1.location < mbr_meta2.location;
}

View File

@@ -799,8 +799,12 @@ protected:
{
struct LocationMeta
{
uint32_t base_type_id = 0;
uint32_t num_components = 0;
uint32_t ib_index = ~0u;
bool flat = false;
bool noperspective = false;
bool centroid = false;
bool sample = false;
};
std::unordered_map<uint32_t, LocationMeta> location_meta;
bool strip_array = false;
@@ -815,6 +819,9 @@ protected:
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta);
void add_plain_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
SPIRType &ib_type, SPIRVariable &var, InterfaceBlockMeta &meta);
bool add_component_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
SPIRVariable &var, const SPIRType &type,
InterfaceBlockMeta &meta);
void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref,
SPIRType &ib_type, SPIRVariable &var, uint32_t index,
InterfaceBlockMeta &meta);