Merge pull request #1516 from billhollings/VK_EXT_descriptor_indexing

MSL: Support run-time sized image and sampler arrays
This commit is contained in:
Hans-Kristian Arntzen 2020-11-03 10:15:36 +01:00 committed by GitHub
commit 244839d350
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 7 deletions

View File

@ -10024,12 +10024,22 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
bool pointer = get<SPIRType>(result_type).pointer; bool pointer = get<SPIRType>(result_type).pointer;
auto *chain = maybe_get<SPIRAccessChain>(rhs); auto *chain = maybe_get<SPIRAccessChain>(rhs);
auto *imgsamp = maybe_get<SPIRCombinedImageSampler>(rhs);
if (chain) if (chain)
{ {
// Cannot lower to a SPIRExpression, just copy the object. // Cannot lower to a SPIRExpression, just copy the object.
auto &e = set<SPIRAccessChain>(id, *chain); auto &e = set<SPIRAccessChain>(id, *chain);
e.self = id; e.self = id;
} }
else if (imgsamp)
{
// Cannot lower to a SPIRExpression, just copy the object.
// GLSL does not currently use this type and will never get here, but MSL does.
// Handled here instead of CompilerMSL for better integration and general handling,
// and in case GLSL or other subclasses require it in the future.
auto &e = set<SPIRCombinedImageSampler>(id, *imgsamp);
e.self = id;
}
else if (expression_is_lvalue(rhs) && !pointer) else if (expression_is_lvalue(rhs) && !pointer)
{ {
// Need a copy. // Need a copy.

View File

@ -103,6 +103,16 @@ bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t de
return itr != end(resource_bindings) && itr->second.second; return itr != end(resource_bindings) && itr->second.second;
} }
// Returns the size of the array of resources used by the variable with the specified id.
// The returned value is retrieved from the resource binding added using add_msl_resource_binding().
uint32_t CompilerMSL::get_resource_array_size(uint32_t id) const
{
StageSetBinding tuple = { get_entry_point().model, get_decoration(id, DecorationDescriptorSet),
get_decoration(id, DecorationBinding) };
auto itr = resource_bindings.find(tuple);
return itr != end(resource_bindings) ? itr->second.first.count : 0;
}
uint32_t CompilerMSL::get_automatic_msl_resource_binding(uint32_t id) const uint32_t CompilerMSL::get_automatic_msl_resource_binding(uint32_t id) const
{ {
return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexPrimary); return get_extended_decoration(id, SPIRVCrossDecorationResourceIndexPrimary);
@ -8136,7 +8146,7 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
// Manufacture automatic sampler arg for SampledImage texture // Manufacture automatic sampler arg for SampledImage texture
if (arg_type.image.dim != DimBuffer) if (arg_type.image.dim != DimBuffer)
decl += join(", thread const ", sampler_type(arg_type), " ", to_sampler_expression(arg.id)); decl += join(", thread const ", sampler_type(arg_type, arg.id), " ", to_sampler_expression(arg.id));
} }
// Manufacture automatic swizzle arg. // Manufacture automatic swizzle arg.
@ -10449,7 +10459,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
case SPIRType::Sampler: case SPIRType::Sampler:
if (!ep_args.empty()) if (!ep_args.empty())
ep_args += ", "; ep_args += ", ";
ep_args += sampler_type(type) + " " + r.name; ep_args += sampler_type(type, var_id) + " " + r.name;
ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]"; ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]";
break; break;
case SPIRType::Image: case SPIRType::Image:
@ -11709,7 +11719,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
return image_type_glsl(type, id); return image_type_glsl(type, id);
case SPIRType::Sampler: case SPIRType::Sampler:
return sampler_type(type); return sampler_type(type, id);
case SPIRType::Void: case SPIRType::Void:
return "void"; return "void";
@ -11840,8 +11850,15 @@ std::string CompilerMSL::variable_decl(const SPIRType &type, const std::string &
return CompilerGLSL::variable_decl(type, name, id); return CompilerGLSL::variable_decl(type, name, id);
} }
std::string CompilerMSL::sampler_type(const SPIRType &type) std::string CompilerMSL::sampler_type(const SPIRType &type, uint32_t id)
{ {
auto *var = maybe_get<SPIRVariable>(id);
if (var && var->basevariable)
{
// Check against the base variable, and not a fake ID which might have been generated for this variable.
id = var->basevariable;
}
if (!type.array.empty()) if (!type.array.empty())
{ {
if (!msl_options.supports_msl_version(2)) if (!msl_options.supports_msl_version(2))
@ -11851,12 +11868,16 @@ std::string CompilerMSL::sampler_type(const SPIRType &type)
SPIRV_CROSS_THROW("Arrays of arrays of samplers are not supported in MSL."); SPIRV_CROSS_THROW("Arrays of arrays of samplers are not supported in MSL.");
// Arrays of samplers in MSL must be declared with a special array<T, N> syntax ala C++11 std::array. // Arrays of samplers in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
// If we have a runtime array, it could be a variable-count descriptor set binding.
uint32_t array_size = to_array_size_literal(type); uint32_t array_size = to_array_size_literal(type);
if (array_size == 0)
array_size = get_resource_array_size(id);
if (array_size == 0) if (array_size == 0)
SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL."); SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL.");
auto &parent = get<SPIRType>(get_pointee_type(type).parent_type); auto &parent = get<SPIRType>(get_pointee_type(type).parent_type);
return join("array<", sampler_type(parent), ", ", array_size, ">"); return join("array<", sampler_type(parent, id), ", ", array_size, ">");
} }
else else
return "sampler"; return "sampler";
@ -11893,7 +11914,11 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
SPIRV_CROSS_THROW("Arrays of arrays of textures are not supported in MSL."); SPIRV_CROSS_THROW("Arrays of arrays of textures are not supported in MSL.");
// Arrays of images in MSL must be declared with a special array<T, N> syntax ala C++11 std::array. // Arrays of images in MSL must be declared with a special array<T, N> syntax ala C++11 std::array.
// If we have a runtime array, it could be a variable-count descriptor set binding.
uint32_t array_size = to_array_size_literal(type); uint32_t array_size = to_array_size_literal(type);
if (array_size == 0)
array_size = get_resource_array_size(id);
if (array_size == 0) if (array_size == 0)
SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL."); SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL.");

View File

@ -60,7 +60,11 @@ struct MSLShaderInput
// Matches the binding index of a MSL resource for a binding within a descriptor set. // Matches the binding index of a MSL resource for a binding within a descriptor set.
// Taken together, the stage, desc_set and binding combine to form a reference to a resource // Taken together, the stage, desc_set and binding combine to form a reference to a resource
// descriptor used in a particular shading stage. // descriptor used in a particular shading stage. The count field indicates the number of
// resources consumed by this binding, if the binding represents an array of resources.
// If the resource array is a run-time-sized array, which are legal in GLSL or SPIR-V, this value
// will be used to declare the array size in MSL, which does not support run-time-sized arrays.
// For resources that are not held in a run-time-sized array, the count field does not need to be populated.
// If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set, // If using MSL 2.0 argument buffers, the descriptor set is not marked as a discrete descriptor set,
// and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we // and (for iOS only) the resource is not a storage image (sampled != 2), the binding reference we
// remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure. // remap to will become an [[id(N)]] attribute within the "descriptor set" argument buffer structure.
@ -71,6 +75,7 @@ struct MSLResourceBinding
spv::ExecutionModel stage = spv::ExecutionModelMax; spv::ExecutionModel stage = spv::ExecutionModelMax;
uint32_t desc_set = 0; uint32_t desc_set = 0;
uint32_t binding = 0; uint32_t binding = 0;
uint32_t count = 0;
uint32_t msl_buffer = 0; uint32_t msl_buffer = 0;
uint32_t msl_texture = 0; uint32_t msl_texture = 0;
uint32_t msl_sampler = 0; uint32_t msl_sampler = 0;
@ -672,7 +677,7 @@ protected:
std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override; std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0) override;
std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override; std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string sampler_type(const SPIRType &type); std::string sampler_type(const SPIRType &type, uint32_t id);
std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override; std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) override;
std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override; std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
std::string to_name(uint32_t id, bool allow_alias = true) const override; std::string to_name(uint32_t id, bool allow_alias = true) const override;
@ -756,6 +761,7 @@ protected:
void emit_specialization_constants_and_structs(); void emit_specialization_constants_and_structs();
void emit_interface_block(uint32_t ib_var_id); void emit_interface_block(uint32_t ib_var_id);
bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs); bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs);
uint32_t get_resource_array_size(uint32_t id) const;
void fix_up_shader_inputs_outputs(); void fix_up_shader_inputs_outputs();