Skip to content

Commit c9b8347

Browse files
committed
Set explicit resource bindings for Metal.
Previous versions of SPIRV-Cross used the binding that was set if no explicit mapping was added. This has since been removed and explicit mappings are always needed.
1 parent e3dc424 commit c9b8347

File tree

3 files changed

+85
-15
lines changed

3 files changed

+85
-15
lines changed

Compile/src/MetalOutput.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
namespace msl
2222
{
2323

24-
std::string MetalOutput::disassemble(Output& output, const Compiler::SpirV& spirv,
25-
std::uint32_t version, bool ios, bool outputToBuffer, const std::string& fileName,
24+
std::string MetalOutput::disassemble(Output& output, const Compiler::SpirV& spirv, Stage stage,
25+
std::uint32_t version, bool ios, bool outputToBuffer, bool hasPushConstant,
26+
std::uint32_t bufferCount, std::uint32_t textureCount, const std::string& fileName,
2627
std::size_t line, std::size_t column)
2728
{
2829
spirv_cross::CompilerMSL::Options options;
@@ -31,8 +32,54 @@ std::string MetalOutput::disassemble(Output& output, const Compiler::SpirV& spir
3132
options.msl_version = spirv_cross::CompilerMSL::Options::make_msl_version(version/10,
3233
version%10);
3334
options.capture_output_to_buffer = outputToBuffer;
35+
3436
spirv_cross::CompilerMSL compiler(spirv);
3537
compiler.set_msl_options(options);
38+
39+
spv::ExecutionModel executionModel = spv::ExecutionModelMax;
40+
switch (stage)
41+
{
42+
case Stage::Vertex:
43+
executionModel = spv::ExecutionModelVertex;
44+
break;
45+
case Stage::TessellationControl:
46+
executionModel = spv::ExecutionModelTessellationControl;
47+
break;
48+
case Stage::TessellationEvaluation:
49+
executionModel = spv::ExecutionModelTessellationEvaluation;
50+
break;
51+
case Stage::Geometry:
52+
executionModel = spv::ExecutionModelGeometry;
53+
break;
54+
case Stage::Fragment:
55+
executionModel = spv::ExecutionModelFragment;
56+
break;
57+
case Stage::Compute:
58+
executionModel = spv::ExecutionModelGLCompute;
59+
break;
60+
}
61+
62+
for (std::uint32_t i = hasPushConstant ? 1 : 0; i < bufferCount; ++i)
63+
{
64+
spirv_cross::MSLResourceBinding binding;
65+
binding.stage = executionModel;
66+
binding.desc_set = 0;
67+
binding.binding = i;
68+
binding.msl_buffer = i;
69+
compiler.add_msl_resource_binding(binding);
70+
}
71+
72+
for (std::uint32_t i = 0; i < textureCount; ++i)
73+
{
74+
spirv_cross::MSLResourceBinding binding;
75+
binding.stage = executionModel;
76+
binding.desc_set = 1;
77+
binding.binding = i;
78+
binding.msl_texture = i;
79+
binding.msl_sampler = i;
80+
compiler.add_msl_resource_binding(binding);
81+
}
82+
3683
try
3784
{
3885
return compiler.compile();

Compile/src/MetalOutput.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ namespace msl
2525
class MetalOutput
2626
{
2727
public:
28-
static std::string disassemble(Output& output, const Compiler::SpirV& spirv,
29-
std::uint32_t version, bool ios, bool outputToBuffer, const std::string& fileName,
28+
static std::string disassemble(Output& output, const Compiler::SpirV& spirv, Stage stage,
29+
std::uint32_t version, bool ios, bool outputToBuffer, bool hasPushConstant,
30+
std::uint32_t bufferCount, std::uint32_t textureCount, const std::string& fileName,
3031
std::size_t line, std::size_t column);
3132
};
3233

Compile/src/TargetMetal.cpp

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,18 @@
3939
namespace msl
4040
{
4141

42-
static void setBinding(std::vector<uint32_t>& spirv, std::uint32_t id, std::uint32_t index)
42+
static void setBinding(std::vector<uint32_t>& spirv, std::uint32_t id, std::uint32_t set,
43+
std::uint32_t binding)
4344
{
4445
const unsigned int firstInstruction = 5;
4546
const std::uint32_t opCodeMask = 0xFFFF;
4647
const std::uint32_t wordCountShift = 16;
4748
const std::uint32_t opFunction = 54;
4849
const std::uint32_t opDecorate = 71;
4950
const std::uint32_t decorationBinding = 33;
51+
const std::uint32_t decorationDescriptorSet = 34;
5052

53+
bool descriptorSet = false, bindingSet = false;
5154
for (uint32_t i = firstInstruction; i < spirv.size();)
5255
{
5356
uint32_t op = spirv[i] & opCodeMask;
@@ -57,22 +60,34 @@ static void setBinding(std::vector<uint32_t>& spirv, std::uint32_t id, std::uint
5760
if (op == opFunction)
5861
break;
5962

60-
if (op == opDecorate && spirv[i + 1] == id && spirv[i + 2] == decorationBinding)
63+
if (op == opDecorate && spirv[i + 1] == id)
6164
{
62-
spirv[i + 3] = index;
63-
break;
65+
if (spirv[i + 2] == decorationDescriptorSet)
66+
{
67+
spirv[i + 3] = set;
68+
descriptorSet = true;
69+
}
70+
else if (spirv[i + 2] == decorationBinding)
71+
{
72+
spirv[i + 3] = binding;
73+
bindingSet = true;
74+
}
75+
76+
if (bindingSet && descriptorSet)
77+
break;
6478
}
6579

6680
i += wordCount;
6781
}
6882
}
6983

7084
static std::vector<std::uint32_t> setBindingIndices(const std::vector<std::uint32_t>& spirv,
71-
const std::vector<compile::Uniform>& uniforms, std::vector<std::uint32_t>& uniformIds)
85+
const std::vector<compile::Uniform>& uniforms, std::vector<std::uint32_t>& uniformIds,
86+
bool& hasPushConstant, std::uint32_t& bufferCount, std::uint32_t& textureCount)
7287
{
7388
std::vector<std::uint32_t> adjustedSpirv = spirv;
7489

75-
bool hasPushConstant = false;
90+
hasPushConstant = false;
7691
for (std::size_t i = 0; i < uniforms.size(); ++i)
7792
{
7893
if (uniformIds[i] != unknown && uniforms[i].uniformType == UniformType::PushConstant)
@@ -96,18 +111,20 @@ static std::vector<std::uint32_t> setBindingIndices(const std::vector<std::uint3
96111
break;
97112
case UniformType::Block:
98113
case UniformType::BlockBuffer:
99-
setBinding(adjustedSpirv, uniformIds[i], bufferIndex);
114+
setBinding(adjustedSpirv, uniformIds[i], 0, bufferIndex);
100115
uniformIds[i] = bufferIndex++;
101116
break;
102117
case UniformType::Image:
103118
case UniformType::SampledImage:
104119
case UniformType::SubpassInput:
105-
setBinding(adjustedSpirv, uniformIds[i], textureIndex);
120+
setBinding(adjustedSpirv, uniformIds[i], 1, textureIndex);
106121
uniformIds[i] = textureIndex++;
107122
break;
108123
}
109124
}
110125

126+
bufferCount = bufferIndex;
127+
textureCount = textureIndex;
111128
return adjustedSpirv;
112129
}
113130

@@ -182,12 +199,17 @@ bool TargetMetal::crossCompile(std::vector<std::uint8_t>& data, Output& output,
182199
const std::vector<std::uint32_t>& spirv, const std::string& entryPoint,
183200
const std::vector<compile::Uniform>& uniforms, std::vector<std::uint32_t>& uniformIds)
184201
{
185-
std::vector<std::uint32_t> adjustedSpirv = setBindingIndices(spirv, uniforms, uniformIds);
186202
bool outputToBuffer = stage == compile::Stage::Vertex &&
187203
(pipelineStages[static_cast<int>(compile::Stage::TessellationControl)] ||
188204
pipelineStages[static_cast<int>(compile::Stage::TessellationEvaluation)]);
189-
std::string metal = MetalOutput::disassemble(output, adjustedSpirv, m_version, m_ios,
190-
outputToBuffer, fileName, line, column);
205+
206+
bool hasPushConstant;
207+
std::uint32_t bufferCount, textureCount;
208+
std::vector<std::uint32_t> adjustedSpirv = setBindingIndices(spirv, uniforms, uniformIds,
209+
hasPushConstant, bufferCount, textureCount);
210+
211+
std::string metal = MetalOutput::disassemble(output, adjustedSpirv, stage, m_version, m_ios,
212+
outputToBuffer, hasPushConstant, bufferCount, textureCount, fileName, line, column);
191213
if (metal.empty())
192214
return false;
193215

0 commit comments

Comments
 (0)