Merge pull request #252 from brenwill/master

CompilerMSL enhancements.
This commit is contained in:
Hans-Kristian Arntzen 2017-08-11 12:41:24 +02:00 committed by GitHub
commit dd4c5ce068
11 changed files with 110 additions and 46 deletions

View File

@ -23,12 +23,12 @@ struct UBO
struct main0_out
{
float4 oF [[user(locn5)]];
float4 oE [[user(locn4)]];
float4 oD [[user(locn3)]];
float4 oC [[user(locn2)]];
float4 oB [[user(locn1)]];
float4 oA [[user(locn0)]];
float4 oB [[user(locn1)]];
float4 oC [[user(locn2)]];
float4 oD [[user(locn3)]];
float4 oE [[user(locn4)]];
float4 oF [[user(locn5)]];
float4 gl_Position [[position]];
};

View File

@ -0,0 +1,24 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_in
{
float4 vColor [[user(locn0)]];
};
struct main0_out
{
float4 FragColor [[color(0)]];
float gl_FragDepth [[depth(any)]];
};
fragment main0_out main0(main0_in in [[stage_in]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
out.FragColor = gl_FragCoord + in.vColor;
out.gl_FragDepth = 0.5;
return out;
}

View File

@ -21,11 +21,11 @@ struct main0_in
struct main0_out
{
float3 vRotRad [[user(locn2)]];
float3 vRotDeg [[user(locn1)]];
float3 vNormal [[user(locn0)]];
int2 vMSB [[user(locn4)]];
float3 vRotDeg [[user(locn1)]];
float3 vRotRad [[user(locn2)]];
int2 vLSB [[user(locn3)]];
int2 vMSB [[user(locn4)]];
float4 gl_Position [[position]];
};

View File

@ -16,8 +16,8 @@ struct main0_in
struct main0_out
{
float4 VertexOut_color2 [[user(locn3)]];
float4 VertexOut_color [[user(locn2)]];
float4 VertexOut_color2 [[user(locn3)]];
float4 gl_Position [[position]];
};

View File

@ -20,9 +20,9 @@ struct main0_in
struct main0_out
{
float2 vSize [[user(locn2)]];
float3 vNormal [[user(locn0)]];
float3 vColor [[user(locn1)]];
float2 vSize [[user(locn2)]];
float4 gl_Position [[position]];
};

View File

@ -0,0 +1,11 @@
#version 310 es
precision mediump float;
layout(location = 0) out vec4 FragColor;
layout(location = 0) in vec4 vColor;
void main()
{
FragColor = gl_FragCoord + vColor;
gl_FragDepth = 0.5;
}

View File

@ -475,6 +475,11 @@ bool Compiler::is_matrix(const SPIRType &type) const
return type.vecsize > 1 && type.columns > 1;
}
bool Compiler::is_array(const SPIRType &type) const
{
return !type.array.empty();
}
ShaderResources Compiler::get_shader_resources() const
{
return get_shader_resources(nullptr);

View File

@ -455,6 +455,7 @@ protected:
bool is_scalar(const SPIRType &type) const;
bool is_vector(const SPIRType &type) const;
bool is_matrix(const SPIRType &type) const;
bool is_array(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);

View File

@ -340,7 +340,7 @@ string CompilerGLSL::compile()
std::string CompilerGLSL::get_partial_source()
{
return buffer->str();
return buffer ? buffer->str() : "No compiled source available yet.";
}
void CompilerGLSL::emit_header()

View File

@ -87,6 +87,8 @@ string CompilerMSL::compile()
update_active_builtins();
fixup_image_load_store_access();
set_enabled_interface_variables(get_active_interface_variables());
// Preprocess OpCodes to extract the need to output additional header content
preprocess_op_codes();
@ -168,7 +170,6 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
// Register the need to output any custom functions.
void CompilerMSL::preprocess_op_codes()
{
set_enabled_interface_variables(get_active_interface_variables());
spv_function_implementations.clear();
OpCodePreprocessor preproc(*this);
@ -389,6 +390,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
case StorageClassUniformConstant:
{
ib_var_ref = stage_uniform_var_name;
active_interface_variables.insert(ib_var_id); // Ensure will be emitted
break;
}
@ -413,10 +415,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
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);
}
if (should_move_to_input_buffer(mbr_type, is_builtin, storage))
move_member_to_input_buffer(type, mbr_idx);
else if (!is_builtin || has_active_builtin(builtin, storage))
{
// Add a reference to the member to the interface struct.
@ -467,8 +468,8 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
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);
if (should_move_to_input_buffer(type, is_builtin, storage))
move_to_input_buffer(*p_var);
else if (!is_builtin || has_active_builtin(builtin, storage))
{
@ -503,34 +504,58 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
}
}
// Sort the members of the interface structure by their attribute numbers.
// Oddly, Metal handles inputs better if they are sorted in reverse order,
// particularly if the offsets are all equal.
// Sort the members of the structure by their locations.
// Oddly, Metal handles inputs better if they are sorted in reverse order.
MemberSorter::SortAspect sort_aspect =
(storage == StorageClassInput) ? MemberSorter::LocationReverse : MemberSorter::Location;
MemberSorter member_sorter(ib_type, meta[ib_type_id], sort_aspect);
member_sorter.sort();
// Sort input or output variables alphabetical
auto &execution = get_entry_point();
if ((execution.model == ExecutionModelFragment && storage == StorageClassInput) ||
(execution.model == ExecutionModelVertex && storage == StorageClassOutput))
{
MemberSorter member_sorter_io(ib_type, meta[ib_type.self], MemberSorter::Alphabetical);
member_sorter_io.sort();
}
return ib_var_id;
}
// Excludes the specified input variable from the stage_in block structure.
// Instead, the variable is added to a block variable corresponding to a secondary MSL buffer.
// The main use case for this is when a stage_in variable contains a matrix, which is a rare occurrence.
void CompilerMSL::exclude_from_stage_in(SPIRVariable &var)
// Returns whether a variable of type and storage class should be moved from an interface
// block to a secondary input buffer block.
// This is the case for matrixes and arrays that appear in the stage_in interface block
// of a vertex function, and true is returned.
// Other types do not need to move, and false is returned.
// Matrices and arrays are not permitted in the output of a vertex function or the input
// or output of a fragment function, and in those cases, an exception is thrown.
bool CompilerMSL::should_move_to_input_buffer(SPIRType &type, bool is_builtin, StorageClass storage)
{
if ((is_matrix(type) || is_array(type)) && !is_builtin)
{
auto &execution = get_entry_point();
if (execution.model == ExecutionModelVertex)
{
if (storage == StorageClassInput)
return true;
if (storage == StorageClassOutput)
SPIRV_CROSS_THROW("The vertex function output structure may not include a matrix or array.");
}
else if (execution.model == ExecutionModelFragment)
{
if (storage == StorageClassInput)
SPIRV_CROSS_THROW("The fragment function stage_in structure may not include a matrix or array.");
if (storage == StorageClassOutput)
SPIRV_CROSS_THROW("The fragment function output structure may not include a matrix or array.");
}
}
return false;
}
// Excludes the specified variable from an interface block structure.
// Instead, for the variable is added to a block variable corresponding to a secondary MSL buffer.
// The use case for this is when a vertex stage_in variable contains a matrix or array.
void CompilerMSL::move_to_input_buffer(SPIRVariable &var)
{
uint32_t var_id = var.self;
if (!(get_decoration_mask(var_id) & (1ull << DecorationLocation)))
if (!has_decoration(var_id, DecorationLocation))
return;
uint32_t mbr_type_id = var.basetype;
@ -540,9 +565,9 @@ void CompilerMSL::exclude_from_stage_in(SPIRVariable &var)
}
// Excludes the specified type member from the stage_in block structure.
// Instead, the member is added to a block variable corresponding to a secondary MSL buffer.
// The main use case for this is when a stage_in variable contains a matrix, which is a rare occurrence.
void CompilerMSL::exclude_member_from_stage_in(const SPIRType &type, uint32_t index)
// Instead, for the variable is added to a block variable corresponding to a secondary MSL buffer.
// The use case for this is when a vertex stage_in variable contains a matrix or array.
void CompilerMSL::move_member_to_input_buffer(const SPIRType &type, uint32_t index)
{
uint32_t type_id = type.self;
@ -2610,11 +2635,12 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
case BuiltInInstanceIndex:
return "gl_InstanceIndex";
// Output builtins qualified with output struct when used in the entry function
// When used in the entry function, output builtins are qualified with output struct name.
case BuiltInPosition:
case BuiltInPointSize:
case BuiltInClipDistance:
case BuiltInLayer:
case BuiltInFragDepth:
if (current_function && (current_function->self == entry_point))
return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin, storage);
else
@ -2666,16 +2692,12 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
// Fragment function out
case BuiltInFragDepth:
{
if (execution.flags & (1ull << ExecutionModeDepthGreater))
return "depth(greater)";
else if (execution.flags & (1ull << ExecutionModeDepthLess))
return "depth(less)";
else if (execution.flags & (1ull << ExecutionModeDepthUnchanged))
return "depth(any)";
else
return "depth(any)";
}
// Compute function in
case BuiltInGlobalInvocationId:
@ -2993,7 +3015,7 @@ bool CompilerMSL::MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
return (mbr_meta1.offset < mbr_meta2.offset) ||
((mbr_meta1.offset == mbr_meta2.offset) && (mbr_meta1.location > mbr_meta2.location));
case Alphabetical:
return mbr_meta1.alias > mbr_meta2.alias;
return mbr_meta1.alias < mbr_meta2.alias;
default:
return false;
}

View File

@ -202,8 +202,9 @@ protected:
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index);
size_t get_declared_struct_member_alignment(const SPIRType &struct_type, uint32_t index) const;
std::string to_component_argument(uint32_t id);
void exclude_from_stage_in(SPIRVariable &var);
void exclude_member_from_stage_in(const SPIRType &type, uint32_t index);
bool should_move_to_input_buffer(SPIRType &type, bool is_builtin, spv::StorageClass storage);
void move_to_input_buffer(SPIRVariable &var);
void move_member_to_input_buffer(const SPIRType &type, uint32_t index);
std::string add_input_buffer_block_member(uint32_t mbr_type_id, std::string mbr_name, uint32_t mbr_locn);
uint32_t get_input_buffer_block_var_id(uint32_t msl_buffer);
void align_struct(SPIRType &ib_type);