Initial support for Metal Shading Language.
This commit is contained in:
parent
147e53aeb2
commit
103aabf5e8
@ -5,13 +5,14 @@ SPIRV-Cross is a tool designed for parsing and converting SPIR-V to other shader
|
||||
## Features
|
||||
|
||||
- Convert SPIR-V to readable, usable and efficient GLSL
|
||||
- Convert SPIR-V to readable, usable and efficient Metal Shading Language (MSL) [EXPERIMENTAL]
|
||||
- Convert SPIR-V to debuggable C++ [EXPERIMENTAL]
|
||||
- Reflection API to simplify the creation of Vulkan pipeline layouts
|
||||
- Reflection API to modify and tweak OpDecorations
|
||||
- Supports "all" of vertex, fragment, tessellation, geometry and compute shaders.
|
||||
|
||||
SPIRV-Cross tries hard to emit readable and clean output from the SPIR-V.
|
||||
The goal is to emit GLSL that looks like it was written by a human and not awkward IR/assembly-like code.
|
||||
The goal is to emit GLSL or MSL that looks like it was written by a human and not awkward IR/assembly-like code.
|
||||
|
||||
NOTE: Individual features are expected to be mostly complete, but it is possible that certain obscure GLSL features are not yet supported.
|
||||
However, most missing features are expected to be "trivial" improvements at this stage.
|
||||
|
@ -72,12 +72,17 @@ namespace spirv_cross
|
||||
return std::to_string(std::forward<T>(t));
|
||||
}
|
||||
|
||||
// Allow implementations to set a convenient standard precision
|
||||
#ifndef SPVX_FLT_FMT
|
||||
# define SPVX_FLT_FMT "%.32g"
|
||||
#endif
|
||||
|
||||
inline std::string convert_to_string(float t)
|
||||
{
|
||||
// std::to_string for floating point values is broken.
|
||||
// Fallback to something more sane.
|
||||
char buf[64];
|
||||
sprintf(buf, "%.32g", t);
|
||||
sprintf(buf, SPVX_FLT_FMT, t);
|
||||
// Ensure that the literal is float.
|
||||
if (!strchr(buf, '.') && !strchr(buf, 'e'))
|
||||
strcat(buf, ".0");
|
||||
@ -89,7 +94,7 @@ namespace spirv_cross
|
||||
// std::to_string for floating point values is broken.
|
||||
// Fallback to something more sane.
|
||||
char buf[64];
|
||||
sprintf(buf, "%.32g", t);
|
||||
sprintf(buf, SPVX_FLT_FMT, t);
|
||||
// Ensure that the literal is float.
|
||||
if (!strchr(buf, '.') && !strchr(buf, 'e'))
|
||||
strcat(buf, ".0");
|
||||
@ -144,6 +149,7 @@ namespace spirv_cross
|
||||
Unknown,
|
||||
Void,
|
||||
Bool,
|
||||
Char,
|
||||
Int,
|
||||
UInt,
|
||||
AtomicCounter,
|
||||
@ -169,6 +175,8 @@ namespace spirv_cross
|
||||
|
||||
std::vector<uint32_t> member_types;
|
||||
|
||||
bool is_packed = false; // Tightly packed in memory (no alignment padding)
|
||||
|
||||
struct Image
|
||||
{
|
||||
uint32_t type;
|
||||
@ -631,6 +639,7 @@ namespace spirv_cross
|
||||
uint32_t offset = 0;
|
||||
uint32_t array_stride = 0;
|
||||
bool builtin = false;
|
||||
bool per_instance = false;
|
||||
};
|
||||
|
||||
Decoration decoration;
|
||||
|
@ -337,6 +337,21 @@ bool Compiler::is_member_builtin(const SPIRType &type, uint32_t index, BuiltIn *
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Compiler::is_scalar(const SPIRType &type) const
|
||||
{
|
||||
return type.vecsize == 1 && type.columns == 1;
|
||||
}
|
||||
|
||||
bool Compiler::is_vector(const SPIRType &type) const
|
||||
{
|
||||
return type.vecsize > 1 && type.columns == 1;
|
||||
}
|
||||
|
||||
bool Compiler::is_matrix(const SPIRType &type) const
|
||||
{
|
||||
return type.vecsize > 1 && type.columns > 1;
|
||||
}
|
||||
|
||||
ShaderResources Compiler::get_shader_resources() const
|
||||
{
|
||||
ShaderResources res;
|
||||
@ -1814,3 +1829,15 @@ std::vector<BufferRange> Compiler::get_active_buffer_ranges(unsigned id) const
|
||||
return ranges;
|
||||
}
|
||||
|
||||
// Increase the number of IDs by the specified incremental amount.
|
||||
// Returns the value of the first ID available for use in the expanded bound.
|
||||
uint32_t Compiler::increase_bound_by(uint32_t incr_amount)
|
||||
{
|
||||
uint32_t curr_bound = ids.size();
|
||||
uint32_t new_bound = curr_bound + incr_amount;
|
||||
ids.resize(new_bound);
|
||||
meta.resize(new_bound);
|
||||
return curr_bound;
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,6 +157,9 @@ namespace spirv_cross
|
||||
// Returns the effective size of a buffer block.
|
||||
size_t get_declared_struct_size(const SPIRType &struct_type) const;
|
||||
|
||||
// Returns the effective size of a buffer block struct member.
|
||||
virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
|
||||
|
||||
// Legacy GLSL compatibility method.
|
||||
// Takes a variable with a block interface and flattens it into a T array[N]; array instead.
|
||||
// For this to work, all types in the block must not themselves be composites
|
||||
@ -255,6 +258,9 @@ namespace spirv_cross
|
||||
bool is_builtin_variable(const SPIRVariable &var) const;
|
||||
bool is_immutable(uint32_t id) const;
|
||||
bool is_member_builtin(const SPIRType &type, uint32_t index, spv::BuiltIn *builtin) const;
|
||||
bool is_scalar(const SPIRType &type) const;
|
||||
bool is_vector(const SPIRType &type) const;
|
||||
bool is_matrix(const SPIRType &type) const;
|
||||
const SPIRType& expression_type(uint32_t id) const;
|
||||
bool expression_is_lvalue(uint32_t id) const;
|
||||
bool variable_storage_is_aliased(const SPIRVariable &var);
|
||||
@ -307,6 +313,8 @@ namespace spirv_cross
|
||||
|
||||
bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const;
|
||||
|
||||
uint32_t increase_bound_by(uint32_t incr_amount);
|
||||
|
||||
private:
|
||||
void parse();
|
||||
void parse(const Instruction &i);
|
||||
@ -337,8 +345,6 @@ namespace spirv_cross
|
||||
|
||||
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
|
||||
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
|
||||
|
||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1866,7 +1866,7 @@ string CompilerGLSL::bitcast_glsl(uint32_t result_type, uint32_t argument)
|
||||
return join(op, "(", to_expression(argument), ")");
|
||||
}
|
||||
|
||||
const char* CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
|
||||
string CompilerGLSL::builtin_to_glsl(BuiltIn builtin)
|
||||
{
|
||||
switch (builtin)
|
||||
{
|
||||
|
@ -110,6 +110,14 @@ namespace spirv_cross
|
||||
// Virtualize methods which need to be overridden by subclass targets like C++ and such.
|
||||
virtual void emit_function_prototype(SPIRFunction &func, uint64_t return_flags);
|
||||
virtual void emit_header();
|
||||
virtual void emit_texture_op(const Instruction &i);
|
||||
virtual std::string type_to_glsl(const SPIRType &type);
|
||||
virtual std::string builtin_to_glsl(spv::BuiltIn builtin);
|
||||
virtual std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member);
|
||||
virtual std::string image_type_glsl(const SPIRType &type);
|
||||
virtual std::string constant_expression(const SPIRConstant &c);
|
||||
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
||||
virtual void emit_fixup();
|
||||
|
||||
std::unique_ptr<std::ostringstream> buffer;
|
||||
|
||||
@ -165,7 +173,6 @@ namespace spirv_cross
|
||||
|
||||
Options options;
|
||||
|
||||
std::string type_to_glsl(const SPIRType &type);
|
||||
std::string type_to_array_glsl(const SPIRType &type);
|
||||
std::string variable_decl(const SPIRVariable &variable);
|
||||
|
||||
@ -189,7 +196,7 @@ namespace spirv_cross
|
||||
void emit_struct(const SPIRType &type);
|
||||
void emit_instruction(const Instruction &instr);
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
void emit_resources();
|
||||
void emit_buffer_block(const SPIRVariable &type);
|
||||
@ -209,7 +216,6 @@ namespace spirv_cross
|
||||
void flush_undeclared_variables();
|
||||
|
||||
bool should_forward(uint32_t id);
|
||||
void emit_texture_op(const Instruction &i);
|
||||
void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp);
|
||||
void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, uint32_t count);
|
||||
void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, uint32_t op3, const char *op);
|
||||
@ -229,13 +235,9 @@ namespace spirv_cross
|
||||
std::string to_member_name(const SPIRType &type, uint32_t index);
|
||||
std::string type_to_glsl_constructor(const SPIRType &type);
|
||||
std::string argument_decl(const SPIRFunction::Parameter &arg);
|
||||
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member);
|
||||
std::string image_type_glsl(const SPIRType &type);
|
||||
std::string to_qualifiers_glsl(uint32_t id);
|
||||
const char* to_precision_qualifiers_glsl(uint32_t id);
|
||||
const char* flags_to_precision_qualifiers_glsl(const SPIRType &type, uint64_t flags);
|
||||
std::string constant_expression(const SPIRConstant &c);
|
||||
std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);
|
||||
const char* format_to_glsl(spv::ImageFormat format);
|
||||
std::string layout_for_member(const SPIRType &type, uint32_t index);
|
||||
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
|
||||
@ -248,7 +250,6 @@ namespace spirv_cross
|
||||
|
||||
std::string bitcast_glsl(uint32_t result_type, uint32_t arg);
|
||||
std::string bitcast_glsl_op(uint32_t result_type, uint32_t arg);
|
||||
const char* builtin_to_glsl(spv::BuiltIn builtin);
|
||||
std::string build_composite_combiner(const uint32_t *elems, uint32_t length);
|
||||
bool remove_duplicate_swizzle(std::string &op);
|
||||
bool remove_unity_swizzle(uint32_t base, std::string &op);
|
||||
@ -263,7 +264,6 @@ namespace spirv_cross
|
||||
std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype);
|
||||
|
||||
uint32_t indent = 0;
|
||||
void emit_fixup();
|
||||
|
||||
std::unordered_set<uint32_t> emitted_functions;
|
||||
|
||||
|
1487
spirv_msl.cpp
Normal file
1487
spirv_msl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
161
spirv_msl.hpp
Normal file
161
spirv_msl.hpp
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright 2015-2016 The Brenwill Workshop Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef SPIRV_MSL_HPP
|
||||
#define SPIRV_MSL_HPP
|
||||
|
||||
#include "spirv_glsl.hpp"
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
|
||||
// Hash implementation to allow spv::BuiltIn to be used as a key in an unordered_map
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<spv::BuiltIn>
|
||||
{
|
||||
std::size_t operator()(const spv::BuiltIn& k) const
|
||||
{
|
||||
return k;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace spirv_cross {
|
||||
|
||||
// Options for compiling to Metal Shading Language
|
||||
struct MSLOptions
|
||||
{
|
||||
uint32_t vtx_attr_stage_in_binding= 0;
|
||||
bool flip_vert_y = true;
|
||||
bool flip_frag_y =true;
|
||||
bool is_rendering_points = false;
|
||||
};
|
||||
|
||||
// Defines characteristics of vertex attributes at a particular location
|
||||
struct MSLVertexAttr
|
||||
{
|
||||
uint32_t location = 0;
|
||||
uint32_t buffer = 0;
|
||||
uint32_t offset = 0;
|
||||
uint32_t stride = 0;
|
||||
bool per_instance = false;
|
||||
};
|
||||
|
||||
// Specifies the binding index of a Metal 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.
|
||||
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;
|
||||
};
|
||||
|
||||
// Special constant used in a MSLResourceBinding desc_set
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t kPushConstDescSet = UINT32_MAX;
|
||||
|
||||
// Special constant used in a MSLResourceBinding binding
|
||||
// element to indicate the bindings for the push constants.
|
||||
static const uint32_t kPushConstBinding = 0;
|
||||
|
||||
|
||||
// Decompiles SPIR-V to Metal Shading Language
|
||||
class CompilerMSL : public CompilerGLSL
|
||||
{
|
||||
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);
|
||||
|
||||
std::string compile() override;
|
||||
|
||||
protected:
|
||||
void emit_header() override;
|
||||
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
|
||||
void emit_texture_op(const Instruction &i) override;
|
||||
void emit_fixup() override;
|
||||
std::string type_to_glsl(const SPIRType &type) override;
|
||||
std::string image_type_glsl(const SPIRType &type) override;
|
||||
std::string builtin_to_glsl(spv::BuiltIn builtin) override;
|
||||
std::string member_decl(const SPIRType &type, const SPIRType &member_type, uint32_t member) override;
|
||||
std::string constant_expression(const SPIRConstant &c) override;
|
||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
||||
|
||||
void post_parse();
|
||||
void extract_builtins();
|
||||
void add_interface_structs();
|
||||
void bind_vertex_attributes(std::set<uint32_t>& bindings);
|
||||
uint32_t add_interface_struct(spv::StorageClass storage, uint32_t vtx_binding = 0);
|
||||
void emit_resources();
|
||||
void emit_interface_block(uint32_t ib_var_id);
|
||||
void emit_function_prototype(SPIRFunction &func, bool is_decl);
|
||||
void emit_function_declarations();
|
||||
|
||||
std::string func_type_decl(SPIRType& type);
|
||||
std::string clean_func_name(std::string func_name);
|
||||
std::string entry_point_args(bool append_comma);
|
||||
std::string get_entry_point_name();
|
||||
std::string builtin_qualifier(spv::BuiltIn builtin);
|
||||
std::string builtin_type_decl(spv::BuiltIn builtin);
|
||||
std::string member_attribute_qualifier(const SPIRType &type, uint32_t index);
|
||||
std::string argument_decl(const SPIRFunction::Parameter &arg);
|
||||
std::string get_vtx_idx_var_name(bool per_instance);
|
||||
uint32_t get_metal_resource_index(SPIRVariable& var, SPIRType::BaseType basetype);
|
||||
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
|
||||
uint32_t pad_to_offset(SPIRType& struct_type, uint32_t offset, uint32_t struct_size);
|
||||
SPIRType& get_pad_type(uint32_t pad_len);
|
||||
size_t get_declared_type_size(const SPIRType& type) const;
|
||||
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<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;
|
||||
};
|
||||
|
||||
// Sorts the members of a SPIRType and associated Meta info based on the location
|
||||
// and builtin decorations of the members. Members are rearranged by location,
|
||||
// with all builtin members appearing a the end.
|
||||
struct MemberSorterByLocation
|
||||
{
|
||||
void sort();
|
||||
bool operator() (uint32_t mbr_idx1,uint32_t mbr_idx2);
|
||||
MemberSorterByLocation(SPIRType& type, Meta& meta) : type(type), meta(meta) {}
|
||||
SPIRType& type;
|
||||
Meta& meta;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user