Merge pull request #190 from brenwill/master

Emit type declarations tuned for specified SPIR-V objects + MSL builtin enhancements.
This commit is contained in:
Hans-Kristian Arntzen 2017-06-02 15:34:06 +02:00 committed by GitHub
commit 3ab1700073
25 changed files with 134 additions and 98 deletions

View File

@ -18,7 +18,6 @@ struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]])

View File

@ -16,7 +16,6 @@ struct main0_in
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _20 [[buffer(0)]])

View File

@ -20,7 +20,6 @@ struct main0_out
{
float2 vRot [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant PushMe& registers [[buffer(0)]])

View File

@ -26,7 +26,6 @@ struct main0_out
{
float4 vColor [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _18 [[buffer(0)]])

View File

@ -30,7 +30,6 @@ struct main0_out
float4 oB [[user(locn4)]];
float4 oA [[user(locn5)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(constant UBO& _22 [[buffer(0)]])

View File

@ -18,7 +18,6 @@ struct main0_in
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant Buffer& _13 [[buffer(0)]])

View File

@ -18,7 +18,6 @@ struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]])

View File

@ -26,7 +26,6 @@ struct main0_out
{
float4 vColor [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _21 [[buffer(0)]])

View File

@ -26,7 +26,6 @@ struct main0_out
{
float4 vColor [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _21 [[buffer(0)]])

View File

@ -27,7 +27,6 @@ struct main0_out
int2 vMSB [[user(locn3)]];
int2 vLSB [[user(locn4)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
// Implementation of the GLSL radians() function

View File

@ -18,8 +18,6 @@ struct main0_out
{
float4 VertexOut_color [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
float gl_ClipDistance[1] /* [[clip_distance]] built-in not yet supported under Metal. */;
};
vertex main0_out main0(main0_in in [[stage_in]], constant Transform& block [[buffer(0)]])

View File

@ -20,7 +20,6 @@ struct main0_out
float4 color [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize [[point_size]];
float gl_ClipDistance[1] /* [[clip_distance]] built-in not yet supported under Metal. */;
};
vertex main0_out main0(main0_in in [[stage_in]], constant params& _19 [[buffer(0)]])

View File

@ -6,7 +6,6 @@ using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(texture2d<float> uSamp [[texture(0)]], texture2d<float> uSampo [[texture(1)]])

View File

@ -24,7 +24,6 @@ struct main0_out
float3 vNormal [[user(locn1)]];
float3 vColor [[user(locn2)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _18 [[buffer(0)]])

View File

@ -18,7 +18,6 @@ struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]])

View File

@ -6,7 +6,6 @@ using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
float gl_PointSize;
};
vertex main0_out main0(uint gl_VertexIndex [[vertex_id]], uint gl_InstanceIndex [[instance_id]])

View File

@ -296,10 +296,9 @@ struct SPIRType : IVariant
bool depth;
bool arrayed;
bool ms;
bool is_read = false; // TODO: temp hack to be replaced with var-based type output
bool is_written = false; // TODO: temp hack to be replaced with var-based type output
uint32_t sampled;
spv::ImageFormat format;
spv::AccessQualifier access;
} image;
// Structs can be declared multiple times if they are used as part of interface blocks.

View File

@ -1468,6 +1468,11 @@ void Compiler::parse(const Instruction &instruction)
type.image.ms = ops[5] != 0;
type.image.sampled = ops[6];
type.image.format = static_cast<ImageFormat>(ops[7]);
type.image.access = (length >= 9) ? static_cast<AccessQualifier>(ops[8]) : AccessQualifierMax;
if (type.image.sampled == 0)
SPIRV_CROSS_THROW("OpTypeImage Sampled parameter must not be zero.");
break;
}
@ -3409,6 +3414,25 @@ void Compiler::update_active_builtins()
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
}
// Returns whether this shader uses a builtin of the storage class
bool Compiler::has_active_builtin(BuiltIn builtin, StorageClass storage)
{
uint64_t flags;
switch (storage)
{
case StorageClassInput:
flags = active_input_builtins;
break;
case StorageClassOutput:
flags = active_output_builtins;
break;
default:
return false;
}
return flags & (1ull << builtin);
}
void Compiler::analyze_sampler_comparison_states()
{
CombinedImageSamplerUsageHandler handler(*this);

View File

@ -640,6 +640,7 @@ protected:
uint64_t active_output_builtins = 0;
// Traverses all reachable opcodes and sets active_builtins to a bitmask of all builtin variables which are accessed in the shader.
void update_active_builtins();
bool has_active_builtin(spv::BuiltIn builtin, spv::StorageClass storage);
void analyze_parameter_preservation(
SPIRFunction &entry, const CFG &cfg,

View File

@ -2893,9 +2893,6 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
auto &type = expression_type(img);
auto &imgtype = get<SPIRType>(type.self);
// Mark that this shader reads from this image
imgtype.image.is_read = true;
uint32_t coord_components = 0;
switch (imgtype.image.dim)
{
@ -6107,7 +6104,7 @@ string CompilerGLSL::type_to_array_glsl(const SPIRType &type)
}
}
string CompilerGLSL::image_type_glsl(const SPIRType &type)
string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */)
{
auto &imagetype = get<SPIRType>(type.image.type);
string res;
@ -6202,7 +6199,10 @@ string CompilerGLSL::type_to_glsl_constructor(const SPIRType &type)
return e;
}
string CompilerGLSL::type_to_glsl(const SPIRType &type)
// The optional id parameter indicates the object whose type we are trying
// to find the description for. It is optional. Most type descriptions do not
// depend on a specific object's use of that type.
string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
{
// Ignore the pointer type since GLSL doesn't have pointers.
@ -6217,7 +6217,7 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
case SPIRType::Image:
case SPIRType::SampledImage:
return image_type_glsl(type);
return image_type_glsl(type, id);
case SPIRType::Sampler:
// This is a hacky workaround. The sampler type in SPIR-V doesn't actually signal this distinction,

View File

@ -171,11 +171,11 @@ protected:
virtual void emit_header();
virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
virtual void emit_texture_op(const Instruction &i);
virtual std::string type_to_glsl(const SPIRType &type);
virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0);
virtual std::string builtin_to_glsl(spv::BuiltIn builtin);
virtual void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const std::string &qualifier = "");
virtual std::string image_type_glsl(const SPIRType &type);
virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0);
virtual std::string constant_expression(const SPIRConstant &c);
std::string constant_op_expression(const SPIRConstantOp &cop);
virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector);

View File

@ -154,7 +154,10 @@ string CompilerHLSL::image_type_hlsl(const SPIRType &type)
return image_type_hlsl_modern(type);
}
string CompilerHLSL::type_to_glsl(const SPIRType &type)
// The optional id parameter indicates the object whose type we are trying
// to find the description for. It is optional. Most type descriptions do not
// depend on a specific object's use of that type.
string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t /* id */)
{
// Ignore the pointer type since GLSL doesn't have pointers.

View File

@ -59,7 +59,7 @@ public:
std::string compile() override;
private:
std::string type_to_glsl(const SPIRType &type) override;
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string image_type_hlsl(const SPIRType &type);
std::string image_type_hlsl_modern(const SPIRType &type);
std::string image_type_hlsl_legacy(const SPIRType &type);

View File

@ -85,6 +85,7 @@ string CompilerMSL::compile()
struct_member_padding.clear();
update_active_builtins();
fixup_image_load_store_access();
// Preprocess OpCodes to extract the need to output additional header content
preprocess_op_codes();
@ -406,12 +407,14 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
uint32_t mbr_idx = 0;
for (auto &mbr_type_id : type.member_types)
{
BuiltIn builtin;
bool is_builtin = is_member_builtin(type, mbr_idx, &builtin);
auto &mbr_type = get<SPIRType>(mbr_type_id);
if (is_matrix(mbr_type))
{
exclude_member_from_stage_in(type, mbr_idx);
}
else
else if (!is_builtin || has_active_builtin(builtin, storage))
{
// Add a reference to the member to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
@ -434,8 +437,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
}
// Mark the member as builtin if needed
BuiltIn builtin;
if (is_member_builtin(type, mbr_idx, &builtin))
if (is_builtin)
{
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationBuiltIn, builtin);
if (builtin == BuiltInPosition)
@ -451,11 +453,13 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
type.basetype == SPIRType::Float || type.basetype == SPIRType::Double ||
type.basetype == SPIRType::Boolean)
{
bool is_builtin = is_builtin_variable(*p_var);
BuiltIn builtin = BuiltIn(get_decoration(p_var->self, DecorationBuiltIn));
if (is_matrix(type))
{
exclude_from_stage_in(*p_var);
}
else
else if (!is_builtin || has_active_builtin(builtin, storage))
{
// Add a reference to the variable type to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
@ -478,9 +482,8 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
}
// Mark the member as builtin if needed
if (is_builtin_variable(*p_var))
if (is_builtin)
{
uint32_t builtin = get_decoration(p_var->self, DecorationBuiltIn);
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationBuiltIn, builtin);
if (builtin == BuiltInPosition)
qual_pos_var_name = qual_var_name;
@ -1176,10 +1179,18 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
// Images
// Reads == fetches in Metal
// Reads == Fetches in Metal
case OpImageRead:
{
// Mark that this shader reads from this image
uint32_t img_id = ops[2];
auto *p_var = maybe_get_backing_variable(img_id);
if (p_var)
unset_decoration(p_var->self, DecorationNonReadable);
emit_texture_op(instruction);
break;
}
case OpImageWrite:
{
@ -1195,26 +1206,13 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
// Ensure this image has been marked as being written to and force a
// recommpile so that the image type output will include write access
if (!img_type.image.is_written)
auto *p_var = maybe_get_backing_variable(img_id);
if (p_var && has_decoration(p_var->self, DecorationNonWritable))
{
img_type.image.is_written = true;
unset_decoration(p_var->self, DecorationNonWritable);
force_recompile = true;
}
// We added Nonwritable speculatively to the OpImage variable due to glslangValidator
// not adding the proper qualifiers.
// If it turns out we need to write to the image after all, remove the qualifier and recompile.
auto *var = maybe_get_backing_variable(img_id);
if (var)
{
auto &flags = meta.at(var->self).decoration.decoration_flags;
if (flags & (1ull << DecorationNonWritable))
{
flags &= ~(1ull << DecorationNonWritable);
force_recompile = true;
}
}
bool forward = false;
uint32_t bias = 0;
uint32_t lod = 0;
@ -1242,7 +1240,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
to_function_args(img_id, img_type, true, false, false, coord_id, 0, 0, 0, 0, lod, 0, 0, 0, 0, 0, &forward),
");"));
if (var && variable_storage_is_aliased(*var))
if (p_var && variable_storage_is_aliased(*p_var))
flush_all_aliased_variables();
break;
@ -1916,7 +1914,7 @@ void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_
string pack_pfx = member_is_packed_type(type, index) ? "packed_" : "";
statement(pack_pfx, type_to_glsl(membertype), " ", qualifier, to_member_name(type, index),
type_to_array_glsl(membertype), member_attribute_qualifier(type, index), ";");
member_attribute_qualifier(type, index), type_to_array_glsl(membertype), ";");
}
// Return a MSL qualifier for the specified function attribute member
@ -1924,6 +1922,9 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
{
auto &execution = get_entry_point();
uint32_t mbr_type_id = type.member_types[index];
auto &mbr_type = get<SPIRType>(mbr_type_id);
BuiltIn builtin;
bool is_builtin = is_member_builtin(type, index, &builtin);
@ -1956,21 +1957,17 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
{
switch (builtin)
{
case BuiltInClipDistance:
return " /* [[clip_distance]] built-in not yet supported under Metal. */";
case BuiltInPointSize: // Must output only if really rendering points
// SPIR-V might declare PointSize as a builtin even though it's not really used.
// In some cases PointSize builtin may be written without Point topology.
// This is not an issue on GL/Vulkan, but it is on Metal, so we also have some way to forcefully disable
// this builtin.
return (active_output_builtins & (1ull << BuiltInPointSize)) && options.enable_point_size_builtin ?
(string(" [[") + builtin_qualifier(builtin) + "]]") :
"";
case BuiltInPointSize:
// Only mark the PointSize builtin if really rendering points.
// Some shaders may include a PointSize builtin even when used to render
// non-point topologies, and Metal will reject this builtin when compiling
// the shader into a render pipeline that uses a non-point topology.
return options.enable_point_size_builtin ? (string(" [[") + builtin_qualifier(builtin) + "]]") : "";
case BuiltInPosition:
case BuiltInLayer:
return string(" [[") + builtin_qualifier(builtin) + "]]";
case BuiltInClipDistance:
return string(" [[") + builtin_qualifier(builtin) + "]]" + (mbr_type.array.empty() ? "" : " ");
default:
return "";
@ -2201,6 +2198,8 @@ string CompilerMSL::entry_point_args(bool append_comma)
auto &var = id.get<SPIRVariable>();
auto &type = get<SPIRType>(var.basetype);
uint32_t var_id = var.self;
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
var.storage == StorageClassPushConstant) &&
!is_hidden_variable(var))
@ -2214,31 +2213,31 @@ string CompilerMSL::entry_point_args(bool append_comma)
break;
if (!ep_args.empty())
ep_args += ", ";
ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_name(var.self);
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.self);
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) + " " + to_name(var.self);
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) + " " + to_name(var.self);
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)) + ")]]";
if (type.image.dim != DimBuffer)
{
ep_args += ", sampler " + to_sampler_expression(var.self);
ep_args += ", sampler " + to_sampler_expression(var_id);
ep_args +=
" [[sampler(" + convert_to_string(get_metal_resource_index(var, SPIRType::Sampler)) + ")]]";
}
@ -2251,8 +2250,8 @@ string CompilerMSL::entry_point_args(bool append_comma)
{
if (!ep_args.empty())
ep_args += ", ";
BuiltIn bi_type = meta[var.self].decoration.builtin_type;
ep_args += builtin_type_decl(bi_type) + " " + to_expression(var.self);
BuiltIn bi_type = meta[var_id].decoration.builtin_type;
ep_args += builtin_type_decl(bi_type) + " " + to_expression(var_id);
ep_args += " [[" + builtin_qualifier(bi_type) + "]]";
}
}
@ -2377,8 +2376,10 @@ string CompilerMSL::ensure_valid_name(string name, string pfx)
}
}
// Returns an MSL string describing the SPIR-V type
string CompilerMSL::type_to_glsl(const SPIRType &type)
// The optional id parameter indicates the object whose type we are trying
// to find the description for. It is optional. Most type descriptions do not
// depend on a specific object's use of that type.
string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
{
// Ignore the pointer type since GLSL doesn't have pointers.
@ -2392,7 +2393,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type)
case SPIRType::Image:
case SPIRType::SampledImage:
return image_type_glsl(type);
return image_type_glsl(type, id);
case SPIRType::Sampler:
return "sampler";
@ -2445,7 +2446,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type)
}
// Returns an MSL string describing the SPIR-V image type
string CompilerMSL::image_type_glsl(const SPIRType &type)
string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
{
string img_type_name;
@ -2456,10 +2457,10 @@ string CompilerMSL::image_type_glsl(const SPIRType &type)
{
switch (img_type.dim)
{
case spv::Dim2D:
case Dim2D:
img_type_name += (img_type.ms ? "depth2d_ms" : (img_type.arrayed ? "depth2d_array" : "depth2d"));
break;
case spv::DimCube:
case DimCube:
img_type_name += (img_type.arrayed ? "depthcube_array" : "depthcube");
break;
default:
@ -2471,17 +2472,17 @@ string CompilerMSL::image_type_glsl(const SPIRType &type)
{
switch (img_type.dim)
{
case spv::Dim1D:
case Dim1D:
img_type_name += (img_type.arrayed ? "texture1d_array" : "texture1d");
break;
case spv::DimBuffer:
case spv::Dim2D:
case DimBuffer:
case Dim2D:
img_type_name += (img_type.ms ? "texture2d_ms" : (img_type.arrayed ? "texture2d_array" : "texture2d"));
break;
case spv::Dim3D:
case Dim3D:
img_type_name += "texture3d";
break;
case spv::DimCube:
case DimCube:
img_type_name += (img_type.arrayed ? "texturecube_array" : "texturecube");
break;
default:
@ -2491,18 +2492,43 @@ string CompilerMSL::image_type_glsl(const SPIRType &type)
}
// Append the pixel type
auto &img_pix_type = get<SPIRType>(img_type.type);
img_type_name += "<";
img_type_name += type_to_glsl(img_pix_type);
img_type_name += type_to_glsl(get<SPIRType>(img_type.type));
if (img_type.is_written)
// For unsampled images, append the sample/read/write access qualifier.
// For kernel images, the access qualifier my be supplied directly by SPIR-V.
// Otherwise it may be set based on whether the image is read from or written to within the shader.
if (type.basetype == SPIRType::Image && type.image.sampled == 2)
{
img_type_name += ", access::";
switch (img_type.access)
{
case AccessQualifierReadOnly:
img_type_name += ", access::read";
break;
if (img_type.is_read)
img_type_name += "read_";
case AccessQualifierWriteOnly:
img_type_name += ", access::write";
break;
img_type_name += "write";
case AccessQualifierReadWrite:
img_type_name += ", access::read_write";
break;
default:
{
auto *p_var = maybe_get_backing_variable(id);
if (p_var && !has_decoration(p_var->self, DecorationNonWritable))
{
img_type_name += ", access::";
if (!has_decoration(p_var->self, DecorationNonReadable))
img_type_name += "read_";
img_type_name += "write";
}
break;
}
}
}
img_type_name += ">";

View File

@ -149,8 +149,8 @@ protected:
void emit_fixup() override;
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const std::string &qualifier = "") override;
std::string type_to_glsl(const SPIRType &type) override;
std::string image_type_glsl(const SPIRType &type) override;
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string image_type_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string builtin_to_glsl(spv::BuiltIn builtin) 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;
@ -165,6 +165,7 @@ protected:
uint32_t comp, uint32_t sample, bool *p_forward) override;
std::string unpack_expression_type(std::string expr_str, const SPIRType &type) override;
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
bool skip_argument(uint32_t id) const override;
void preprocess_op_codes();
void emit_custom_functions();
@ -217,7 +218,6 @@ protected:
bool op1_is_pointer = false, uint32_t op2 = 0);
const char *get_memory_order(uint32_t spv_mem_sem);
void add_pragma_line(const std::string &line);
bool skip_argument(uint32_t id) const override;
Options options;
std::unordered_map<std::string, std::string> func_name_overrides;