MSL: Order resources by type and binding index in the output
We've hit a bizarre bug on NVidia / macOS 10.13 where if two subsequent draw calls use two different shaders that both have VS use buffers 0 & 1, but one declares them in the increasing binding order and another one declares them in the decreasing binding order, then the second draw call (with the decreasing order) doesn't get correct data in some cases. This has been reported to Apple and they will probably fix it at some point; to work around that it's sufficient to sort resources by their binding index. For consistency we also sort by type to get a stable order, and output builtins after that to prevent random bugs like this from happening.
This commit is contained in:
parent
ab3907e4b5
commit
050361422c
112
spirv_msl.cpp
112
spirv_msl.cpp
@ -2692,7 +2692,19 @@ string CompilerMSL::entry_point_args(bool append_comma)
|
||||
convert_to_string(nsi_var.first) + ")]]";
|
||||
}
|
||||
|
||||
// Uniforms
|
||||
// Output resources, sorted by resource index & type
|
||||
// We need to sort to work around a bug on macOS 10.13 with NVidia drivers where switching between shaders
|
||||
// with different order of buffers can result in issues with buffer assignments inside the driver.
|
||||
struct Resource
|
||||
{
|
||||
Variant* id;
|
||||
string name;
|
||||
SPIRType::BaseType basetype;
|
||||
uint32_t index;
|
||||
};
|
||||
|
||||
vector<Resource> resources;
|
||||
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() == TypeVariable)
|
||||
@ -2706,48 +2718,70 @@ string CompilerMSL::entry_point_args(bool append_comma)
|
||||
var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) &&
|
||||
!is_hidden_variable(var))
|
||||
{
|
||||
switch (type.basetype)
|
||||
if (type.basetype == SPIRType::SampledImage)
|
||||
{
|
||||
case SPIRType::Struct:
|
||||
{
|
||||
auto &m = meta.at(type.self);
|
||||
if (m.members.size() == 0)
|
||||
break;
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_name(var_id);
|
||||
ep_args += " [[buffer(" + convert_to_string(get_metal_resource_index(var, type.basetype)) + ")]]";
|
||||
break;
|
||||
}
|
||||
case SPIRType::Sampler:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += type_to_glsl(type) + " " + to_name(var_id);
|
||||
ep_args += " [[sampler(" + convert_to_string(get_metal_resource_index(var, type.basetype)) + ")]]";
|
||||
break;
|
||||
case SPIRType::Image:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += type_to_glsl(type, var_id) + " " + to_name(var_id);
|
||||
ep_args += " [[texture(" + convert_to_string(get_metal_resource_index(var, type.basetype)) + ")]]";
|
||||
break;
|
||||
case SPIRType::SampledImage:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += type_to_glsl(type, var_id) + " " + to_name(var_id);
|
||||
ep_args +=
|
||||
" [[texture(" + convert_to_string(get_metal_resource_index(var, SPIRType::Image)) + ")]]";
|
||||
resources.push_back({ &id, to_name(var_id), SPIRType::Image, get_metal_resource_index(var, SPIRType::Image) });
|
||||
|
||||
if (type.image.dim != DimBuffer)
|
||||
{
|
||||
ep_args += ", sampler " + to_sampler_expression(var_id);
|
||||
ep_args +=
|
||||
" [[sampler(" + convert_to_string(get_metal_resource_index(var, SPIRType::Sampler)) + ")]]";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
resources.push_back({ &id, to_sampler_expression(var_id), SPIRType::Sampler, get_metal_resource_index(var, SPIRType::Sampler) });
|
||||
}
|
||||
else
|
||||
{
|
||||
resources.push_back({ &id, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(resources.begin(), resources.end(), [](const Resource& lhs, const Resource& rhs) { return tie(lhs.basetype, lhs.index) < tie(rhs.basetype, rhs.index); });
|
||||
|
||||
for (auto &r : resources)
|
||||
{
|
||||
auto &var = r.id->get<SPIRVariable>();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
uint32_t var_id = var.self;
|
||||
|
||||
switch (r.basetype)
|
||||
{
|
||||
case SPIRType::Struct:
|
||||
{
|
||||
auto &m = meta.at(type.self);
|
||||
if (m.members.size() == 0)
|
||||
break;
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + r.name;
|
||||
ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]";
|
||||
break;
|
||||
}
|
||||
case SPIRType::Sampler:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += "sampler " + r.name;
|
||||
ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]";
|
||||
break;
|
||||
case SPIRType::Image:
|
||||
if (!ep_args.empty())
|
||||
ep_args += ", ";
|
||||
ep_args += type_to_glsl(type, var_id) + " " + r.name;
|
||||
ep_args += " [[texture(" + convert_to_string(r.index) + ")]]";
|
||||
break;
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Unexpected resource type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Builtin variables
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() == TypeVariable)
|
||||
{
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
|
||||
uint32_t var_id = var.self;
|
||||
|
||||
if (var.storage == StorageClassInput && is_builtin_variable(var))
|
||||
{
|
||||
if (!ep_args.empty())
|
||||
|
Loading…
Reference in New Issue
Block a user