|
@@ -208,6 +208,7 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord);
|
|
|
builtin_frag_coord_id = var_id;
|
|
builtin_frag_coord_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!has_sample_id && need_sample_pos)
|
|
if (!has_sample_id && need_sample_pos)
|
|
@@ -234,6 +235,7 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSampleId);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSampleId);
|
|
|
builtin_sample_id_id = var_id;
|
|
builtin_sample_id_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance))
|
|
if (need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance))
|
|
@@ -263,7 +265,9 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInVertexIndex);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInVertexIndex);
|
|
|
builtin_vertex_idx_id = var_id;
|
|
builtin_vertex_idx_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInVertexIndex, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
if (!has_base_vertex)
|
|
if (!has_base_vertex)
|
|
|
{
|
|
{
|
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
@@ -272,7 +276,9 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseVertex);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseVertex);
|
|
|
builtin_base_vertex_id = var_id;
|
|
builtin_base_vertex_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInBaseVertex, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
if (!has_instance_idx)
|
|
if (!has_instance_idx)
|
|
|
{
|
|
{
|
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
@@ -281,7 +287,9 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInInstanceIndex);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInInstanceIndex);
|
|
|
builtin_instance_idx_id = var_id;
|
|
builtin_instance_idx_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
if (!has_base_instance)
|
|
if (!has_base_instance)
|
|
|
{
|
|
{
|
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
@@ -290,6 +298,7 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseInstance);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseInstance);
|
|
|
builtin_base_instance_id = var_id;
|
|
builtin_base_instance_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var_id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -320,7 +329,9 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInInvocationId);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInInvocationId);
|
|
|
builtin_invocation_id_id = var_id;
|
|
builtin_invocation_id_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
if (!has_primitive_id)
|
|
if (!has_primitive_id)
|
|
|
{
|
|
{
|
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
uint32_t var_id = ir.increase_bound_by(1);
|
|
@@ -329,6 +340,7 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInPrimitiveId);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInPrimitiveId);
|
|
|
builtin_primitive_id_id = var_id;
|
|
builtin_primitive_id_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var_id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -356,6 +368,7 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSubgroupLocalInvocationId);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSubgroupLocalInvocationId);
|
|
|
builtin_subgroup_invocation_id_id = var_id;
|
|
builtin_subgroup_invocation_id_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInSubgroupLocalInvocationId, var_id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!has_subgroup_size && need_subgroup_ge_mask)
|
|
if (!has_subgroup_size && need_subgroup_ge_mask)
|
|
@@ -382,43 +395,82 @@ void CompilerMSL::build_implicit_builtins()
|
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSubgroupSize);
|
|
set_decoration(var_id, DecorationBuiltIn, BuiltInSubgroupSize);
|
|
|
builtin_subgroup_size_id = var_id;
|
|
builtin_subgroup_size_id = var_id;
|
|
|
|
|
+ mark_implicit_builtin(StorageClassInput, BuiltInSubgroupSize, var_id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (needs_swizzle_buffer_def)
|
|
if (needs_swizzle_buffer_def)
|
|
|
{
|
|
{
|
|
|
- uint32_t offset = ir.increase_bound_by(4);
|
|
|
|
|
- uint32_t type_id = offset;
|
|
|
|
|
- uint32_t type_ptr_id = offset + 1;
|
|
|
|
|
- uint32_t type_ptr_ptr_id = offset + 2;
|
|
|
|
|
- uint32_t var_id = offset + 3;
|
|
|
|
|
-
|
|
|
|
|
- // Create a buffer to hold extra data, including the swizzle constants.
|
|
|
|
|
- SPIRType uint_type;
|
|
|
|
|
- uint_type.basetype = SPIRType::UInt;
|
|
|
|
|
- uint_type.width = 32;
|
|
|
|
|
- set<SPIRType>(type_id, uint_type);
|
|
|
|
|
-
|
|
|
|
|
- SPIRType uint_type_pointer = uint_type;
|
|
|
|
|
- uint_type_pointer.pointer = true;
|
|
|
|
|
- uint_type_pointer.pointer_depth = 1;
|
|
|
|
|
- uint_type_pointer.parent_type = type_id;
|
|
|
|
|
- uint_type_pointer.storage = StorageClassUniform;
|
|
|
|
|
- set<SPIRType>(type_ptr_id, uint_type_pointer);
|
|
|
|
|
- set_decoration(type_ptr_id, DecorationArrayStride, 4);
|
|
|
|
|
-
|
|
|
|
|
- SPIRType uint_type_pointer2 = uint_type_pointer;
|
|
|
|
|
- uint_type_pointer2.pointer_depth++;
|
|
|
|
|
- uint_type_pointer2.parent_type = type_ptr_id;
|
|
|
|
|
- set<SPIRType>(type_ptr_ptr_id, uint_type_pointer2);
|
|
|
|
|
-
|
|
|
|
|
- set<SPIRVariable>(var_id, type_ptr_ptr_id, StorageClassUniformConstant);
|
|
|
|
|
|
|
+ uint32_t var_id = build_constant_uint_array_pointer();
|
|
|
set_name(var_id, "spvSwizzleConstants");
|
|
set_name(var_id, "spvSwizzleConstants");
|
|
|
// This should never match anything.
|
|
// This should never match anything.
|
|
|
- set_decoration(var_id, DecorationDescriptorSet, 0xFFFFFFFE);
|
|
|
|
|
|
|
+ set_decoration(var_id, DecorationDescriptorSet, kSwizzleBufferBinding);
|
|
|
set_decoration(var_id, DecorationBinding, msl_options.swizzle_buffer_index);
|
|
set_decoration(var_id, DecorationBinding, msl_options.swizzle_buffer_index);
|
|
|
swizzle_buffer_id = var_id;
|
|
swizzle_buffer_id = var_id;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if (!buffers_requiring_array_length.empty())
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t var_id = build_constant_uint_array_pointer();
|
|
|
|
|
+ set_name(var_id, "spvBufferSizeConstants");
|
|
|
|
|
+ // This should never match anything.
|
|
|
|
|
+ set_decoration(var_id, DecorationDescriptorSet, kBufferSizeBufferBinding);
|
|
|
|
|
+ set_decoration(var_id, DecorationBinding, msl_options.buffer_size_buffer_index);
|
|
|
|
|
+ buffer_size_buffer_id = var_id;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, uint32_t id)
|
|
|
|
|
+{
|
|
|
|
|
+ Bitset *active_builtins = nullptr;
|
|
|
|
|
+ switch (storage)
|
|
|
|
|
+ {
|
|
|
|
|
+ case StorageClassInput:
|
|
|
|
|
+ active_builtins = &active_input_builtins;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case StorageClassOutput:
|
|
|
|
|
+ active_builtins = &active_output_builtins;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ assert(active_builtins != nullptr);
|
|
|
|
|
+ active_builtins->set(builtin);
|
|
|
|
|
+ get_entry_point().interface_variables.push_back(id);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+uint32_t CompilerMSL::build_constant_uint_array_pointer()
|
|
|
|
|
+{
|
|
|
|
|
+ uint32_t offset = ir.increase_bound_by(4);
|
|
|
|
|
+ uint32_t type_id = offset;
|
|
|
|
|
+ uint32_t type_ptr_id = offset + 1;
|
|
|
|
|
+ uint32_t type_ptr_ptr_id = offset + 2;
|
|
|
|
|
+ uint32_t var_id = offset + 3;
|
|
|
|
|
+
|
|
|
|
|
+ // Create a buffer to hold extra data, including the swizzle constants.
|
|
|
|
|
+ SPIRType uint_type;
|
|
|
|
|
+ uint_type.basetype = SPIRType::UInt;
|
|
|
|
|
+ uint_type.width = 32;
|
|
|
|
|
+ set<SPIRType>(type_id, uint_type);
|
|
|
|
|
+
|
|
|
|
|
+ SPIRType uint_type_pointer = uint_type;
|
|
|
|
|
+ uint_type_pointer.pointer = true;
|
|
|
|
|
+ uint_type_pointer.pointer_depth = 1;
|
|
|
|
|
+ uint_type_pointer.parent_type = type_id;
|
|
|
|
|
+ uint_type_pointer.storage = StorageClassUniform;
|
|
|
|
|
+ set<SPIRType>(type_ptr_id, uint_type_pointer);
|
|
|
|
|
+ set_decoration(type_ptr_id, DecorationArrayStride, 4);
|
|
|
|
|
+
|
|
|
|
|
+ SPIRType uint_type_pointer2 = uint_type_pointer;
|
|
|
|
|
+ uint_type_pointer2.pointer_depth++;
|
|
|
|
|
+ uint_type_pointer2.parent_type = type_ptr_id;
|
|
|
|
|
+ set<SPIRType>(type_ptr_ptr_id, uint_type_pointer2);
|
|
|
|
|
+
|
|
|
|
|
+ set<SPIRVariable>(var_id, type_ptr_ptr_id, StorageClassUniformConstant);
|
|
|
|
|
+ return var_id;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static string create_sampler_address(const char *prefix, MSLSamplerAddress addr)
|
|
static string create_sampler_address(const char *prefix, MSLSamplerAddress addr)
|
|
@@ -650,6 +702,7 @@ string CompilerMSL::compile()
|
|
|
capture_output_to_buffer = msl_options.capture_output_to_buffer;
|
|
capture_output_to_buffer = msl_options.capture_output_to_buffer;
|
|
|
is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
|
|
is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
|
|
|
|
|
|
|
|
|
|
+ fixup_type_alias();
|
|
|
replace_illegal_names();
|
|
replace_illegal_names();
|
|
|
|
|
|
|
|
struct_member_padding.clear();
|
|
struct_member_padding.clear();
|
|
@@ -666,6 +719,8 @@ string CompilerMSL::compile()
|
|
|
set_enabled_interface_variables(get_active_interface_variables());
|
|
set_enabled_interface_variables(get_active_interface_variables());
|
|
|
if (swizzle_buffer_id)
|
|
if (swizzle_buffer_id)
|
|
|
active_interface_variables.insert(swizzle_buffer_id);
|
|
active_interface_variables.insert(swizzle_buffer_id);
|
|
|
|
|
+ if (buffer_size_buffer_id)
|
|
|
|
|
+ active_interface_variables.insert(buffer_size_buffer_id);
|
|
|
|
|
|
|
|
// Create structs to hold input, output and uniform variables.
|
|
// Create structs to hold input, output and uniform variables.
|
|
|
// Do output first to ensure out. is declared at top of entry function.
|
|
// Do output first to ensure out. is declared at top of entry function.
|
|
@@ -691,6 +746,7 @@ string CompilerMSL::compile()
|
|
|
|
|
|
|
|
// Mark any non-stage-in structs to be tightly packed.
|
|
// Mark any non-stage-in structs to be tightly packed.
|
|
|
mark_packable_structs();
|
|
mark_packable_structs();
|
|
|
|
|
+ reorder_type_alias();
|
|
|
|
|
|
|
|
// Add fixup hooks required by shader inputs and outputs. This needs to happen before
|
|
// Add fixup hooks required by shader inputs and outputs. This needs to happen before
|
|
|
// the loop, so the hooks aren't added multiple times.
|
|
// the loop, so the hooks aren't added multiple times.
|
|
@@ -844,6 +900,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
|
|
|
case OpInBoundsAccessChain:
|
|
case OpInBoundsAccessChain:
|
|
|
case OpAccessChain:
|
|
case OpAccessChain:
|
|
|
case OpPtrAccessChain:
|
|
case OpPtrAccessChain:
|
|
|
|
|
+ case OpArrayLength:
|
|
|
{
|
|
{
|
|
|
uint32_t base_id = ops[2];
|
|
uint32_t base_id = ops[2];
|
|
|
if (global_var_ids.find(base_id) != global_var_ids.end())
|
|
if (global_var_ids.find(base_id) != global_var_ids.end())
|
|
@@ -1884,21 +1941,38 @@ void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t
|
|
|
// Returns the ID of the newly added variable, or zero if no variable was added.
|
|
// Returns the ID of the newly added variable, or zero if no variable was added.
|
|
|
uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
|
uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
|
|
|
{
|
|
{
|
|
|
- // Accumulate the variables that should appear in the interface struct
|
|
|
|
|
|
|
+ // Accumulate the variables that should appear in the interface struct.
|
|
|
SmallVector<SPIRVariable *> vars;
|
|
SmallVector<SPIRVariable *> vars;
|
|
|
- bool incl_builtins = (storage == StorageClassOutput || is_tessellation_shader());
|
|
|
|
|
|
|
+ bool incl_builtins = storage == StorageClassOutput || is_tessellation_shader();
|
|
|
|
|
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
|
|
|
|
+ if (var.storage != storage)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
auto &type = this->get<SPIRType>(var.basetype);
|
|
auto &type = this->get<SPIRType>(var.basetype);
|
|
|
- BuiltIn bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn));
|
|
|
|
|
- if (var.storage == storage && interface_variable_exists_in_entry_point(var.self) &&
|
|
|
|
|
- !is_hidden_variable(var, incl_builtins) && type.pointer &&
|
|
|
|
|
- (has_decoration(var_id, DecorationPatch) || is_patch_block(type)) == patch &&
|
|
|
|
|
- (!is_builtin_variable(var) || bi_type == BuiltInPosition || bi_type == BuiltInPointSize ||
|
|
|
|
|
- bi_type == BuiltInClipDistance || bi_type == BuiltInCullDistance || bi_type == BuiltInLayer ||
|
|
|
|
|
- bi_type == BuiltInViewportIndex || bi_type == BuiltInFragDepth || bi_type == BuiltInSampleMask ||
|
|
|
|
|
- (get_execution_model() == ExecutionModelTessellationEvaluation &&
|
|
|
|
|
- (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner))))
|
|
|
|
|
|
|
+
|
|
|
|
|
+ bool is_builtin = is_builtin_variable(var);
|
|
|
|
|
+ auto bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn));
|
|
|
|
|
+
|
|
|
|
|
+ // These builtins are part of the stage in/out structs.
|
|
|
|
|
+ bool is_interface_block_builtin =
|
|
|
|
|
+ (bi_type == BuiltInPosition || bi_type == BuiltInPointSize || bi_type == BuiltInClipDistance ||
|
|
|
|
|
+ bi_type == BuiltInCullDistance || bi_type == BuiltInLayer || bi_type == BuiltInViewportIndex ||
|
|
|
|
|
+ bi_type == BuiltInFragDepth || bi_type == BuiltInSampleMask) ||
|
|
|
|
|
+ (get_execution_model() == ExecutionModelTessellationEvaluation &&
|
|
|
|
|
+ (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner));
|
|
|
|
|
+
|
|
|
|
|
+ bool is_active = interface_variable_exists_in_entry_point(var.self);
|
|
|
|
|
+ if (is_builtin && is_active)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Only emit the builtin if it's active in this entry point. Interface variable list might lie.
|
|
|
|
|
+ is_active = has_active_builtin(bi_type, storage);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ bool filter_patch_decoration = (has_decoration(var_id, DecorationPatch) || is_patch_block(type)) == patch;
|
|
|
|
|
+
|
|
|
|
|
+ if (is_active && !is_hidden_variable(var, incl_builtins) && type.pointer && filter_patch_decoration &&
|
|
|
|
|
+ (!is_builtin || is_interface_block_builtin))
|
|
|
{
|
|
{
|
|
|
vars.push_back(&var);
|
|
vars.push_back(&var);
|
|
|
}
|
|
}
|
|
@@ -4027,6 +4101,17 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ case OpArrayLength:
|
|
|
|
|
+ {
|
|
|
|
|
+ auto &type = expression_type(ops[2]);
|
|
|
|
|
+ uint32_t offset = type_struct_member_offset(type, ops[3]);
|
|
|
|
|
+ uint32_t stride = type_struct_member_array_stride(type, ops[3]);
|
|
|
|
|
+
|
|
|
|
|
+ auto expr = join("(", to_buffer_size_expression(ops[2]), " - ", offset, ") / ", stride);
|
|
|
|
|
+ emit_op(ops[0], ops[1], expr, true);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
default:
|
|
default:
|
|
|
CompilerGLSL::emit_instruction(instruction);
|
|
CompilerGLSL::emit_instruction(instruction);
|
|
|
break;
|
|
break;
|
|
@@ -4558,7 +4643,13 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
|
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type))
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type))
|
|
|
{
|
|
{
|
|
|
bool arg_is_array = !arg_type.array.empty();
|
|
bool arg_is_array = !arg_type.array.empty();
|
|
|
- decl += join(", constant uint32_t", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id));
|
|
|
|
|
|
|
+ decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (buffers_requiring_array_length.count(name_id))
|
|
|
|
|
+ {
|
|
|
|
|
+ bool arg_is_array = !arg_type.array.empty();
|
|
|
|
|
+ decl += join(", constant uint", arg_is_array ? "* " : "& ", to_buffer_size_expression(name_id));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (&arg != &func.arguments.back())
|
|
if (&arg != &func.arguments.back())
|
|
@@ -5038,17 +5129,20 @@ string CompilerMSL::to_func_call_arg(uint32_t id)
|
|
|
arg_str += ", " + to_sampler_expression(var_id ? var_id : id);
|
|
arg_str += ", " + to_sampler_expression(var_id ? var_id : id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ uint32_t var_id = 0;
|
|
|
|
|
+ auto *var = maybe_get<SPIRVariable>(id);
|
|
|
|
|
+ if (var)
|
|
|
|
|
+ var_id = var->basevariable;
|
|
|
|
|
+
|
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
|
|
|
{
|
|
{
|
|
|
// Need to check the base variable in case we need to apply a qualified alias.
|
|
// Need to check the base variable in case we need to apply a qualified alias.
|
|
|
- uint32_t var_id = 0;
|
|
|
|
|
- auto *sampler_var = maybe_get<SPIRVariable>(id);
|
|
|
|
|
- if (sampler_var)
|
|
|
|
|
- var_id = sampler_var->basevariable;
|
|
|
|
|
-
|
|
|
|
|
arg_str += ", " + to_swizzle_expression(var_id ? var_id : id);
|
|
arg_str += ", " + to_swizzle_expression(var_id ? var_id : id);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (buffers_requiring_array_length.count(var_id))
|
|
|
|
|
+ arg_str += ", " + to_buffer_size_expression(var_id ? var_id : id);
|
|
|
|
|
+
|
|
|
return arg_str;
|
|
return arg_str;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -5097,6 +5191,32 @@ string CompilerMSL::to_swizzle_expression(uint32_t id)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+string CompilerMSL::to_buffer_size_expression(uint32_t id)
|
|
|
|
|
+{
|
|
|
|
|
+ auto expr = to_expression(id);
|
|
|
|
|
+ auto index = expr.find_first_of('[');
|
|
|
|
|
+
|
|
|
|
|
+ // This is quite crude, but we need to translate the reference name (*spvDescriptorSetN.name) to
|
|
|
|
|
+ // the pointer expression spvDescriptorSetN.name to make a reasonable expression here.
|
|
|
|
|
+ // This only happens if we have argument buffers and we are using OpArrayLength on a lone SSBO in that set.
|
|
|
|
|
+ if (expr.size() >= 3 && expr[0] == '(' && expr[1] == '*')
|
|
|
|
|
+ expr = address_of_expression(expr);
|
|
|
|
|
+
|
|
|
|
|
+ // If a buffer is part of an argument buffer translate this to a legal identifier.
|
|
|
|
|
+ for (auto &c : expr)
|
|
|
|
|
+ if (c == '.')
|
|
|
|
|
+ c = '_';
|
|
|
|
|
+
|
|
|
|
|
+ if (index == string::npos)
|
|
|
|
|
+ return expr + buffer_size_name_suffix;
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ auto buffer_expr = expr.substr(0, index);
|
|
|
|
|
+ auto array_expr = expr.substr(index);
|
|
|
|
|
+ return buffer_expr + buffer_size_name_suffix + array_expr;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Checks whether the type is a Block all of whose members have DecorationPatch.
|
|
// Checks whether the type is a Block all of whose members have DecorationPatch.
|
|
|
bool CompilerMSL::is_patch_block(const SPIRType &type)
|
|
bool CompilerMSL::is_patch_block(const SPIRType &type)
|
|
|
{
|
|
{
|
|
@@ -5786,7 +5906,7 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
|
|
|
{
|
|
{
|
|
|
// Builtin variables
|
|
// Builtin variables
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
|
|
|
- BuiltIn bi_type = ir.meta[var_id].decoration.builtin_type;
|
|
|
|
|
|
|
+ auto bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn));
|
|
|
|
|
|
|
|
// Don't emit SamplePosition as a separate parameter. In the entry
|
|
// Don't emit SamplePosition as a separate parameter. In the entry
|
|
|
// point, we get that by calling get_sample_position() on the sample ID.
|
|
// point, we get that by calling get_sample_position() on the sample ID.
|
|
@@ -5794,6 +5914,13 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
|
|
|
get_variable_data_type(var).basetype != SPIRType::Struct &&
|
|
get_variable_data_type(var).basetype != SPIRType::Struct &&
|
|
|
get_variable_data_type(var).basetype != SPIRType::ControlPointArray)
|
|
get_variable_data_type(var).basetype != SPIRType::ControlPointArray)
|
|
|
{
|
|
{
|
|
|
|
|
+ // If the builtin is not part of the active input builtin set, don't emit it.
|
|
|
|
|
+ // Relevant for multiple entry-point modules which might declare unused builtins.
|
|
|
|
|
+ if (!active_input_builtins.get(bi_type) || !interface_variable_exists_in_entry_point(var_id))
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // These builtins are emitted specially. If we pass this branch, the builtin directly matches
|
|
|
|
|
+ // a MSL builtin.
|
|
|
if (bi_type != BuiltInSamplePosition && bi_type != BuiltInHelperInvocation &&
|
|
if (bi_type != BuiltInSamplePosition && bi_type != BuiltInHelperInvocation &&
|
|
|
bi_type != BuiltInPatchVertices && bi_type != BuiltInTessLevelInner &&
|
|
bi_type != BuiltInPatchVertices && bi_type != BuiltInTessLevelInner &&
|
|
|
bi_type != BuiltInTessLevelOuter && bi_type != BuiltInPosition && bi_type != BuiltInPointSize &&
|
|
bi_type != BuiltInTessLevelOuter && bi_type != BuiltInPosition && bi_type != BuiltInPointSize &&
|
|
@@ -6047,15 +6174,13 @@ string CompilerMSL::entry_point_args_classic(bool append_comma)
|
|
|
|
|
|
|
|
void CompilerMSL::fix_up_shader_inputs_outputs()
|
|
void CompilerMSL::fix_up_shader_inputs_outputs()
|
|
|
{
|
|
{
|
|
|
- // Look for sampled images. Add hooks to set up the swizzle constants.
|
|
|
|
|
|
|
+ // Look for sampled images and buffer. Add hooks to set up the swizzle constants or array lengths.
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
|
|
auto &type = get_variable_data_type(var);
|
|
auto &type = get_variable_data_type(var);
|
|
|
-
|
|
|
|
|
uint32_t var_id = var.self;
|
|
uint32_t var_id = var.self;
|
|
|
|
|
+ bool ssbo = has_decoration(type.self, DecorationBufferBlock);
|
|
|
|
|
|
|
|
- if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
|
|
|
|
|
- var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) &&
|
|
|
|
|
- !is_hidden_variable(var))
|
|
|
|
|
|
|
+ if (var.storage == StorageClassUniformConstant && !is_hidden_variable(var))
|
|
|
{
|
|
{
|
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
|
|
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
|
|
|
{
|
|
{
|
|
@@ -6066,7 +6191,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
|
|
|
uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet);
|
|
uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet);
|
|
|
if (descriptor_set_is_argument_buffer(desc_set))
|
|
if (descriptor_set_is_argument_buffer(desc_set))
|
|
|
{
|
|
{
|
|
|
- statement("constant uint32_t", is_array_type ? "* " : "& ", to_swizzle_expression(var_id),
|
|
|
|
|
|
|
+ statement("constant uint", is_array_type ? "* " : "& ", to_swizzle_expression(var_id),
|
|
|
is_array_type ? " = &" : " = ", to_name(argument_buffer_ids[desc_set]),
|
|
is_array_type ? " = &" : " = ", to_name(argument_buffer_ids[desc_set]),
|
|
|
".spvSwizzleConstants", "[",
|
|
".spvSwizzleConstants", "[",
|
|
|
convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
|
convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
|
@@ -6074,13 +6199,40 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
// If we have an array of images, we need to be able to index into it, so take a pointer instead.
|
|
// If we have an array of images, we need to be able to index into it, so take a pointer instead.
|
|
|
- statement("constant uint32_t", is_array_type ? "* " : "& ", to_swizzle_expression(var_id),
|
|
|
|
|
|
|
+ statement("constant uint", is_array_type ? "* " : "& ", to_swizzle_expression(var_id),
|
|
|
is_array_type ? " = &" : " = ", to_name(swizzle_buffer_id), "[",
|
|
is_array_type ? " = &" : " = ", to_name(swizzle_buffer_id), "[",
|
|
|
convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
|
convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ else if ((var.storage == StorageClassStorageBuffer || (var.storage == StorageClassUniform && ssbo)) &&
|
|
|
|
|
+ !is_hidden_variable(var))
|
|
|
|
|
+ {
|
|
|
|
|
+ if (buffers_requiring_array_length.count(var.self))
|
|
|
|
|
+ {
|
|
|
|
|
+ auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
|
|
|
|
|
+ entry_func.fixup_hooks_in.push_back([this, &type, &var, var_id]() {
|
|
|
|
|
+ bool is_array_type = !type.array.empty();
|
|
|
|
|
+
|
|
|
|
|
+ uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet);
|
|
|
|
|
+ if (descriptor_set_is_argument_buffer(desc_set))
|
|
|
|
|
+ {
|
|
|
|
|
+ statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id),
|
|
|
|
|
+ is_array_type ? " = &" : " = ", to_name(argument_buffer_ids[desc_set]),
|
|
|
|
|
+ ".spvBufferSizeConstants", "[",
|
|
|
|
|
+ convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ // If we have an array of images, we need to be able to index into it, so take a pointer instead.
|
|
|
|
|
+ statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id),
|
|
|
|
|
+ is_array_type ? " = &" : " = ", to_name(buffer_size_buffer_id), "[",
|
|
|
|
|
+ convert_to_string(get_metal_resource_index(var, type.basetype)), "];");
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
// Builtin variables
|
|
// Builtin variables
|
|
@@ -6363,17 +6515,21 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
|
|
|
|
|
|
|
if (msl_options.argument_buffers)
|
|
if (msl_options.argument_buffers)
|
|
|
{
|
|
{
|
|
|
- // An awkward case where we need to emit *more* address space declarations (yay!).
|
|
|
|
|
- // An example is where we pass down an array of buffer pointers to leaf functions.
|
|
|
|
|
- // It's a constant array containing pointers to constants.
|
|
|
|
|
- // The pointer array is always constant however. E.g.
|
|
|
|
|
- // device SSBO * constant (&array)[N].
|
|
|
|
|
- // const device SSBO * constant (&array)[N].
|
|
|
|
|
- // constant SSBO * constant (&array)[N].
|
|
|
|
|
- // However, this only matters for argument buffers, since for MSL 1.0 style codegen,
|
|
|
|
|
- // we emit the buffer array on stack instead, and that seems to work just fine apparently.
|
|
|
|
|
- if (storage == StorageClassUniform || storage == StorageClassStorageBuffer)
|
|
|
|
|
|
|
+ uint32_t desc_set = get_decoration(name_id, DecorationDescriptorSet);
|
|
|
|
|
+ if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) &&
|
|
|
|
|
+ descriptor_set_is_argument_buffer(desc_set))
|
|
|
|
|
+ {
|
|
|
|
|
+ // An awkward case where we need to emit *more* address space declarations (yay!).
|
|
|
|
|
+ // An example is where we pass down an array of buffer pointers to leaf functions.
|
|
|
|
|
+ // It's a constant array containing pointers to constants.
|
|
|
|
|
+ // The pointer array is always constant however. E.g.
|
|
|
|
|
+ // device SSBO * constant (&array)[N].
|
|
|
|
|
+ // const device SSBO * constant (&array)[N].
|
|
|
|
|
+ // constant SSBO * constant (&array)[N].
|
|
|
|
|
+ // However, this only matters for argument buffers, since for MSL 1.0 style codegen,
|
|
|
|
|
+ // we emit the buffer array on stack instead, and that seems to work just fine apparently.
|
|
|
decl += " constant";
|
|
decl += " constant";
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
decl += " (&";
|
|
decl += " (&";
|
|
@@ -7847,6 +8003,28 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui
|
|
|
needs_subgroup_invocation_id = true;
|
|
needs_subgroup_invocation_id = true;
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
|
|
+ case OpArrayLength:
|
|
|
|
|
+ {
|
|
|
|
|
+ auto *var = compiler.maybe_get_backing_variable(args[2]);
|
|
|
|
|
+ if (var)
|
|
|
|
|
+ compiler.buffers_requiring_array_length.insert(var->self);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ case OpInBoundsAccessChain:
|
|
|
|
|
+ case OpAccessChain:
|
|
|
|
|
+ case OpPtrAccessChain:
|
|
|
|
|
+ {
|
|
|
|
|
+ // OpArrayLength might want to know if taking ArrayLength of an array of SSBOs.
|
|
|
|
|
+ uint32_t result_type = args[0];
|
|
|
|
|
+ uint32_t id = args[1];
|
|
|
|
|
+ uint32_t ptr = args[2];
|
|
|
|
|
+ compiler.set<SPIRExpression>(id, "", result_type, true);
|
|
|
|
|
+ compiler.register_read(id, ptr, true);
|
|
|
|
|
+ compiler.ir.ids[id].set_allow_type_rewrite();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
default:
|
|
default:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -8242,6 +8420,8 @@ void CompilerMSL::analyze_argument_buffers()
|
|
|
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
|
|
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
|
|
|
|
|
|
|
|
bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {};
|
|
bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {};
|
|
|
|
|
+ bool set_needs_buffer_sizes[kMaxArgumentBuffers] = {};
|
|
|
|
|
+ bool needs_buffer_sizes = false;
|
|
|
|
|
|
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &var) {
|
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &var) {
|
|
|
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
|
|
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
|
|
@@ -8290,24 +8470,29 @@ void CompilerMSL::analyze_argument_buffers()
|
|
|
// Check if this descriptor set needs a swizzle buffer.
|
|
// Check if this descriptor set needs a swizzle buffer.
|
|
|
if (needs_swizzle_buffer_def && is_sampled_image_type(type))
|
|
if (needs_swizzle_buffer_def && is_sampled_image_type(type))
|
|
|
set_needs_swizzle_buffer[desc_set] = true;
|
|
set_needs_swizzle_buffer[desc_set] = true;
|
|
|
|
|
+ else if (buffers_requiring_array_length.count(var_id) != 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ set_needs_buffer_sizes[desc_set] = true;
|
|
|
|
|
+ needs_buffer_sizes = true;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- if (needs_swizzle_buffer_def)
|
|
|
|
|
|
|
+ if (needs_swizzle_buffer_def || needs_buffer_sizes)
|
|
|
{
|
|
{
|
|
|
- uint32_t swizzle_buffer_type_id = 0;
|
|
|
|
|
|
|
+ uint32_t uint_ptr_type_id = 0;
|
|
|
|
|
|
|
|
// We might have to add a swizzle buffer resource to the set.
|
|
// We might have to add a swizzle buffer resource to the set.
|
|
|
for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++)
|
|
for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++)
|
|
|
{
|
|
{
|
|
|
- if (!set_needs_swizzle_buffer[desc_set])
|
|
|
|
|
|
|
+ if (!set_needs_swizzle_buffer[desc_set] && !set_needs_buffer_sizes[desc_set])
|
|
|
continue;
|
|
continue;
|
|
|
|
|
|
|
|
- if (swizzle_buffer_type_id == 0)
|
|
|
|
|
|
|
+ if (uint_ptr_type_id == 0)
|
|
|
{
|
|
{
|
|
|
uint32_t offset = ir.increase_bound_by(2);
|
|
uint32_t offset = ir.increase_bound_by(2);
|
|
|
uint32_t type_id = offset;
|
|
uint32_t type_id = offset;
|
|
|
- swizzle_buffer_type_id = offset + 1;
|
|
|
|
|
|
|
+ uint_ptr_type_id = offset + 1;
|
|
|
|
|
|
|
|
// Create a buffer to hold extra data, including the swizzle constants.
|
|
// Create a buffer to hold extra data, including the swizzle constants.
|
|
|
SPIRType uint_type;
|
|
SPIRType uint_type;
|
|
@@ -8320,17 +8505,31 @@ void CompilerMSL::analyze_argument_buffers()
|
|
|
uint_type_pointer.pointer_depth = 1;
|
|
uint_type_pointer.pointer_depth = 1;
|
|
|
uint_type_pointer.parent_type = type_id;
|
|
uint_type_pointer.parent_type = type_id;
|
|
|
uint_type_pointer.storage = StorageClassUniform;
|
|
uint_type_pointer.storage = StorageClassUniform;
|
|
|
- set<SPIRType>(swizzle_buffer_type_id, uint_type_pointer);
|
|
|
|
|
- set_decoration(swizzle_buffer_type_id, DecorationArrayStride, 4);
|
|
|
|
|
|
|
+ set<SPIRType>(uint_ptr_type_id, uint_type_pointer);
|
|
|
|
|
+ set_decoration(uint_ptr_type_id, DecorationArrayStride, 4);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- uint32_t var_id = ir.increase_bound_by(1);
|
|
|
|
|
- auto &var = set<SPIRVariable>(var_id, swizzle_buffer_type_id, StorageClassUniformConstant);
|
|
|
|
|
- set_name(var_id, "spvSwizzleConstants");
|
|
|
|
|
- set_decoration(var_id, DecorationDescriptorSet, desc_set);
|
|
|
|
|
- set_decoration(var_id, DecorationBinding, kSwizzleBufferBinding);
|
|
|
|
|
- resources_in_set[desc_set].push_back(
|
|
|
|
|
- { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt) });
|
|
|
|
|
|
|
+ if (set_needs_swizzle_buffer[desc_set])
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t var_id = ir.increase_bound_by(1);
|
|
|
|
|
+ auto &var = set<SPIRVariable>(var_id, uint_ptr_type_id, StorageClassUniformConstant);
|
|
|
|
|
+ set_name(var_id, "spvSwizzleConstants");
|
|
|
|
|
+ set_decoration(var_id, DecorationDescriptorSet, desc_set);
|
|
|
|
|
+ set_decoration(var_id, DecorationBinding, kSwizzleBufferBinding);
|
|
|
|
|
+ resources_in_set[desc_set].push_back(
|
|
|
|
|
+ { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt) });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (set_needs_buffer_sizes[desc_set])
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t var_id = ir.increase_bound_by(1);
|
|
|
|
|
+ auto &var = set<SPIRVariable>(var_id, uint_ptr_type_id, StorageClassUniformConstant);
|
|
|
|
|
+ set_name(var_id, "spvBufferSizeConstants");
|
|
|
|
|
+ set_decoration(var_id, DecorationDescriptorSet, desc_set);
|
|
|
|
|
+ set_decoration(var_id, DecorationBinding, kBufferSizeBufferBinding);
|
|
|
|
|
+ resources_in_set[desc_set].push_back(
|
|
|
|
|
+ { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt) });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|