Clarify CompileMSL config parameters and move to compile() function.

CompileMSL supports marking vertex attributes and resource bindings
as to whether they are used by the shader, and feeding back to caller.
This commit is contained in:
Bill Hollings 2016-04-07 21:25:51 -04:00
parent 103aabf5e8
commit 8f30f07eb5
2 changed files with 138 additions and 92 deletions

View File

@ -22,35 +22,85 @@ using namespace spv;
using namespace spirv_cross;
using namespace std;
CompilerMSL::CompilerMSL(std::vector<uint32_t> spirv,
MSLOptions* p_msl_options,
vector<MSLVertexAttr>* p_vtx_attrs,
std::vector<MSLResourceBinding>* p_res_bindings) : CompilerGLSL(move(spirv)) {
CompilerMSL::CompilerMSL(vector<uint32_t> spirv) : CompilerGLSL(move(spirv)) {
options.vertex.fixup_clipspace = false;
if (p_msl_options)
msl_options = *p_msl_options;
if (p_vtx_attrs)
for (auto& va : *p_vtx_attrs)
vtx_attrs_by_location[va.location] = va;
if (p_res_bindings)
resource_bindings = *p_res_bindings;
post_parse();
}
// Perform additional configuration after parsing
void CompilerMSL::post_parse()
string CompilerMSL::compile(MSLOptions& msl_opts,
vector<MSLVertexAttr>* p_vtx_attrs,
std::vector<MSLResourceBinding>* p_res_bindings)
{
next_metal_resource_index.msl_buffer = 0;
next_metal_resource_index.msl_texture = 0;
next_metal_resource_index.msl_sampler = 0;
pad_type_ids_by_pad_len.clear();
msl_options = msl_opts;
vtx_attrs_by_location.clear();
if (p_vtx_attrs)
for (auto& va : *p_vtx_attrs) {
va.used_by_shader = false;
vtx_attrs_by_location[va.location] = &va;
}
resource_bindings.clear();
if (p_res_bindings) {
resource_bindings.reserve(p_vtx_attrs->size());
for (auto& rb : *p_res_bindings) {
rb.used_by_shader = false;
resource_bindings.push_back(&rb);
}
}
extract_builtins();
add_interface_structs();
// Do not deal with ES-isms like precision, older extensions and such.
options.es = false;
options.version = 1;
backend.float_literal_suffix = false;
backend.uint32_t_literal_suffix = true;
backend.basic_int_type = "int";
backend.basic_uint_type = "uint";
backend.swizzle_is_function = false;
backend.shared_is_implied = false;
uint32_t pass_count = 0;
do
{
if (pass_count >= 2)
throw CompilerError("Over 2 compilation loops detected. Must be a bug!");
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
emit_header();
emit_resources();
emit_function_declarations();
emit_function(get<SPIRFunction>(execution.entry_point), 0);
pass_count++;
} while (force_recompile);
return buffer->str();
}
string CompilerMSL::compile()
{
MSLOptions default_msl_opts;
compile(default_msl_opts, nullptr, nullptr);
}
// Adds any builtins used by this shader to the builtin_vars collection
void CompilerMSL::extract_builtins()
{
builtin_vars.clear();
for (auto& id : ids)
{
if (id.get_type() == TypeVariable)
@ -67,6 +117,9 @@ void CompilerMSL::extract_builtins()
// Adds any interface structure variables needed by this shader
void CompilerMSL::add_interface_structs()
{
stage_in_var_ids.clear();
qual_pos_var_name = "";
uint32_t var_id;
if (execution.model == ExecutionModelVertex)
{
@ -89,8 +142,9 @@ void CompilerMSL::add_interface_structs()
stage_out_var_id = add_interface_struct(StorageClassOutput);
}
// Iterate through the variables and populate each input vertex attribute variable to
// the binding info provided in the MSL context. Matching occurs by location.
// Iterate through the variables and populates each input vertex attribute variable
// from the binding info provided during compiler construction, matching by location.
// The MSL Each matched binding
void CompilerMSL::bind_vertex_attributes(std::set<uint32_t>& bindings)
{
if (execution.model == ExecutionModelVertex)
@ -108,13 +162,17 @@ void CompilerMSL::bind_vertex_attributes(std::set<uint32_t>& bindings)
type.pointer)
{
auto& dec = meta[var.self].decoration;
MSLVertexAttr& va = vtx_attrs_by_location[dec.location];
dec.binding = va.buffer;
dec.offset = va.offset;
dec.array_stride = va.stride;
dec.per_instance = va.per_instance;
MSLVertexAttr* p_va = vtx_attrs_by_location[dec.location];
if (p_va) {
dec.binding = p_va->msl_buffer;
dec.offset = p_va->msl_offset;
dec.array_stride = p_va->msl_stride;
dec.per_instance = p_va->per_instance;
bindings.insert(va.buffer);
// Mark the vertex attributes that were used.
p_va->used_by_shader = true;
bindings.insert(p_va->msl_buffer);
}
}
}
}
@ -301,40 +359,6 @@ uint32_t CompilerMSL::add_interface_struct(StorageClass storage, uint32_t vtx_bi
return ib_var_id;
}
string CompilerMSL::compile()
{
// Do not deal with ES-isms like precision, older extensions and such.
options.es = false;
options.version = 1;
backend.float_literal_suffix = false;
backend.uint32_t_literal_suffix = true;
backend.basic_int_type = "int";
backend.basic_uint_type = "uint";
backend.swizzle_is_function = false;
backend.shared_is_implied = false;
uint32_t pass_count = 0;
do
{
if (pass_count >= 2)
throw CompilerError("Over 2 compilation loops detected. Must be a bug!");
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
emit_header();
emit_resources();
emit_function_declarations();
emit_function(get<SPIRFunction>(execution.entry_point), 0);
pass_count++;
} while (force_recompile);
return buffer->str();
}
// Emits the file header info
void CompilerMSL::emit_header()
{
@ -1082,26 +1106,30 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable& var, SPIRType::Base
uint32_t var_binding = (var.storage == StorageClassPushConstant) ? kPushConstBinding : var_dec.binding;
// If a matching binding has been specified, find and use it
for (auto& res_bind : resource_bindings)
for (auto p_res_bind : resource_bindings)
{
if (res_bind.stage == execution.model &&
res_bind.desc_set == var_desc_set &&
res_bind.binding == var_binding) {
if (p_res_bind->stage == execution.model &&
p_res_bind->desc_set == var_desc_set &&
p_res_bind->binding == var_binding)
{
switch (basetype) {
case SPIRType::Struct: return res_bind.buffer;
case SPIRType::Image: return res_bind.texture;
case SPIRType::Sampler: return res_bind.sampler;
p_res_bind->used_by_shader = true;
switch (basetype)
{
case SPIRType::Struct: return p_res_bind->msl_buffer;
case SPIRType::Image: return p_res_bind->msl_texture;
case SPIRType::Sampler: return p_res_bind->msl_sampler;
default: return 0;
}
}
}
// If a binding has not been specified, revert to incrementing resource indices
switch (basetype) {
case SPIRType::Struct: return next_metal_resource_index.buffer++;
case SPIRType::Image: return next_metal_resource_index.texture++;
case SPIRType::Sampler: return next_metal_resource_index.sampler++;
switch (basetype)
{
case SPIRType::Struct: return next_metal_resource_index.msl_buffer++;
case SPIRType::Image: return next_metal_resource_index.msl_texture++;
case SPIRType::Sampler: return next_metal_resource_index.msl_sampler++;
default: return 0;
}
}

View File

@ -45,29 +45,35 @@ namespace spirv_cross {
bool is_rendering_points = false;
};
// Defines characteristics of vertex attributes at a particular location
// Defines MSL characteristics of a vertex attribute at a particular location.
// The used_by_shader flag is set to true during compilation of SPIR-V to MSL
// if the shader makes use of this vertex attribute.
struct MSLVertexAttr
{
uint32_t location = 0;
uint32_t buffer = 0;
uint32_t offset = 0;
uint32_t stride = 0;
uint32_t msl_buffer = 0;
uint32_t msl_offset = 0;
uint32_t msl_stride = 0;
bool per_instance = false;
bool used_by_shader = false;
};
// Specifies the binding index of a Metal 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
// descriptor used in a particular shading stage. Generally, only one of the buffer, texture,
// or sampler elements will be populated.
// or sampler elements will be populated. The used_by_shader flag is set to true during
// compilation of SPIR-V to MSL if the shader makes use of this vertex attribute.
struct MSLResourceBinding
{
spv::ExecutionModel stage;
uint32_t desc_set = 0;
uint32_t binding = 0;
uint32_t buffer = 0;
uint32_t texture = 0;
uint32_t sampler = 0;
uint32_t msl_buffer = 0;
uint32_t msl_texture = 0;
uint32_t msl_sampler = 0;
bool used_by_shader = false;
};
// Special constant used in a MSLResourceBinding desc_set
@ -84,12 +90,25 @@ namespace spirv_cross {
{
public:
CompilerMSL(std::vector<uint32_t> spirv,
MSLOptions* p_msl_options = nullptr,
std::vector<MSLVertexAttr>* p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding>* p_res_bindings = nullptr);
// Constructs an instance to compile the SPIR-V code into Metal Shading Language.
CompilerMSL(std::vector<uint32_t> spirv);
std::string compile() override;
// Compiles the SPIR-V code into Metal Shading Language using the specified configuration parameters.
// - msl_opts indicates some general options for directing the compilation.
// - p_vtx_attrs is an optional list of vertex attribute bindings used to match
// vertex content locations to MSL attributes. If vertex attributes are provided,
// the compiler will set the used_by_shader flag to true in any vertex attribute
// actually used by the MSL code.
// - p_res_bindings is a list of resource bindings to indicate the MSL buffer,
// texture or sampler index to use for a particular SPIR-V description set
// and binding. If resource bindings are provided, the compiler will set the
// used_by_shader flag to true in any resource binding actually used by the MSL code.
std::string compile(MSLOptions& msl_opts,
std::vector<MSLVertexAttr>* p_vtx_attrs = nullptr,
std::vector<MSLResourceBinding>* p_res_bindings = nullptr);
// Compiles the SPIR-V code into Metal Shading Language using default configuration parameters.
std::string compile() override;
protected:
void emit_header() override;
@ -130,18 +149,17 @@ namespace spirv_cross {
size_t get_declared_type_size(const SPIRType& type, uint64_t dec_mask) const;
MSLOptions msl_options;
std::unordered_map<uint32_t, MSLVertexAttr> vtx_attrs_by_location;
std::vector<MSLResourceBinding> resource_bindings;
std::unordered_map<uint32_t, MSLVertexAttr*> vtx_attrs_by_location;
std::vector<MSLResourceBinding*> resource_bindings;
std::unordered_map<spv::BuiltIn, uint32_t> builtin_vars;
MSLResourceBinding next_metal_resource_index;
std::unordered_map<uint32_t, uint32_t> pad_type_ids_by_pad_len;
std::string stage_in_var_name = "in";
std::vector<uint32_t> stage_in_var_ids;
std::string stage_out_var_name = "out";
uint32_t stage_out_var_id = 0;
std::string sampler_name_suffix = "Smplr";
std::string qual_pos_var_name;
std::string stage_in_var_name = "in";
std::string stage_out_var_name = "out";
std::string sampler_name_suffix = "Smplr";
};
// Sorts the members of a SPIRType and associated Meta info based on the location