Support BuiltInFragDepth.
Emit interface block for StorageClassUniformConstant.
Throw exception when output or fragment input structs contain matrix or array.
Dynamically created interface structs sorted by location number instead of alphabetically.
Add Compiler::is_array() function.
This commit is contained in:
Bill Hollings 2017-06-30 19:10:46 -04:00
Родитель f5fd965fa0
Коммит f591bc0d4a
11 изменённых файлов: 115 добавлений и 49 удалений

Просмотреть файл

@ -23,12 +23,12 @@ struct UBO
struct main0_out 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 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]]; float4 gl_Position [[position]];
}; };

Просмотреть файл

@ -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;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -475,6 +475,11 @@ bool Compiler::is_matrix(const SPIRType &type) const
return type.vecsize > 1 && type.columns > 1; 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 ShaderResources Compiler::get_shader_resources() const
{ {
return get_shader_resources(nullptr); return get_shader_resources(nullptr);

Просмотреть файл

@ -455,6 +455,7 @@ protected:
bool is_scalar(const SPIRType &type) const; bool is_scalar(const SPIRType &type) const;
bool is_vector(const SPIRType &type) const; bool is_vector(const SPIRType &type) const;
bool is_matrix(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; const SPIRType &expression_type(uint32_t id) const;
bool expression_is_lvalue(uint32_t id) const; bool expression_is_lvalue(uint32_t id) const;
bool variable_storage_is_aliased(const SPIRVariable &var); bool variable_storage_is_aliased(const SPIRVariable &var);

Просмотреть файл

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

Просмотреть файл

@ -87,6 +87,8 @@ string CompilerMSL::compile()
update_active_builtins(); update_active_builtins();
fixup_image_load_store_access(); 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 OpCodes to extract the need to output additional header content
preprocess_op_codes(); preprocess_op_codes();
@ -168,7 +170,6 @@ string CompilerMSL::compile(MSLConfiguration &msl_cfg, vector<MSLVertexAttr> *p_
// Register the need to output any custom functions. // Register the need to output any custom functions.
void CompilerMSL::preprocess_op_codes() void CompilerMSL::preprocess_op_codes()
{ {
set_enabled_interface_variables(get_active_interface_variables());
spv_function_implementations.clear(); spv_function_implementations.clear();
OpCodePreprocessor preproc(*this); OpCodePreprocessor preproc(*this);
@ -389,6 +390,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
case StorageClassUniformConstant: case StorageClassUniformConstant:
{ {
ib_var_ref = stage_uniform_var_name; ib_var_ref = stage_uniform_var_name;
active_interface_variables.insert(ib_var_id); // Ensure will be emitted
break; break;
} }
@ -413,10 +415,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
bool is_builtin = is_member_builtin(type, mbr_idx, &builtin); bool is_builtin = is_member_builtin(type, mbr_idx, &builtin);
auto &mbr_type = get<SPIRType>(mbr_type_id); auto &mbr_type = get<SPIRType>(mbr_type_id);
if (is_matrix(mbr_type)) if (should_move_to_input_buffer(mbr_type, is_builtin, storage))
{ move_member_to_input_buffer(type, mbr_idx);
exclude_member_from_stage_in(type, mbr_idx);
}
else if (!is_builtin || has_active_builtin(builtin, storage)) else if (!is_builtin || has_active_builtin(builtin, storage))
{ {
// Add a reference to the member to the interface struct. // 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); bool is_builtin = is_builtin_variable(*p_var);
BuiltIn builtin = BuiltIn(get_decoration(p_var->self, DecorationBuiltIn)); BuiltIn builtin = BuiltIn(get_decoration(p_var->self, DecorationBuiltIn));
if (is_matrix(type)) if (should_move_to_input_buffer(type, is_builtin, storage))
exclude_from_stage_in(*p_var); move_to_input_buffer(*p_var);
else if (!is_builtin || has_active_builtin(builtin, storage)) 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. // Sort the members of the structure by their locations.
// Oddly, Metal handles inputs better if they are sorted in reverse order, // Oddly, Metal handles inputs better if they are sorted in reverse order.
// particularly if the offsets are all equal.
MemberSorter::SortAspect sort_aspect = MemberSorter::SortAspect sort_aspect =
(storage == StorageClassInput) ? MemberSorter::LocationReverse : MemberSorter::Location; (storage == StorageClassInput) ? MemberSorter::LocationReverse : MemberSorter::Location;
MemberSorter member_sorter(ib_type, meta[ib_type_id], sort_aspect); MemberSorter member_sorter(ib_type, meta[ib_type_id], sort_aspect);
member_sorter.sort(); 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; return ib_var_id;
} }
// Excludes the specified input variable from the stage_in block structure. // Returns whether a variable of type and storage class should be moved from an interface
// Instead, the variable is added to a block variable corresponding to a secondary MSL buffer. // block to a secondary input buffer block.
// The main use case for this is when a stage_in variable contains a matrix, which is a rare occurrence. // This is the case for matrixes and arrays that appear in the stage_in interface block
void CompilerMSL::exclude_from_stage_in(SPIRVariable &var) // 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; uint32_t var_id = var.self;
if (!(get_decoration_mask(var_id) & (1ull << DecorationLocation))) if (!has_decoration(var_id, DecorationLocation))
return; return;
uint32_t mbr_type_id = var.basetype; 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. // 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. // Instead, for 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. // The use case for this is when a vertex stage_in variable contains a matrix or array.
void CompilerMSL::exclude_member_from_stage_in(const SPIRType &type, uint32_t index) void CompilerMSL::move_member_to_input_buffer(const SPIRType &type, uint32_t index)
{ {
uint32_t type_id = type.self; uint32_t type_id = type.self;
@ -2607,19 +2632,22 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin)
case BuiltInInstanceIndex: case BuiltInInstanceIndex:
return "gl_InstanceIndex"; 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 BuiltInPosition:
case BuiltInPointSize: case BuiltInPointSize:
case BuiltInClipDistance: case BuiltInClipDistance:
case BuiltInLayer: case BuiltInLayer:
case BuiltInFragDepth:
if (current_function && (current_function->self == entry_point)) if (current_function && (current_function->self == entry_point))
return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin); return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin);
else
return CompilerGLSL::builtin_to_glsl(builtin); break;
default: default:
return CompilerGLSL::builtin_to_glsl(builtin); break;
} }
return CompilerGLSL::builtin_to_glsl(builtin);
} }
// Returns an MSL string attribute qualifer for a SPIR-V builtin // Returns an MSL string attribute qualifer for a SPIR-V builtin
@ -2663,16 +2691,12 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
// Fragment function out // Fragment function out
case BuiltInFragDepth: case BuiltInFragDepth:
{
if (execution.flags & (1ull << ExecutionModeDepthGreater)) if (execution.flags & (1ull << ExecutionModeDepthGreater))
return "depth(greater)"; return "depth(greater)";
else if (execution.flags & (1ull << ExecutionModeDepthLess)) else if (execution.flags & (1ull << ExecutionModeDepthLess))
return "depth(less)"; return "depth(less)";
else if (execution.flags & (1ull << ExecutionModeDepthUnchanged))
return "depth(any)";
else else
return "depth(any)"; return "depth(any)";
}
// Compute function in // Compute function in
case BuiltInGlobalInvocationId: case BuiltInGlobalInvocationId:
@ -2987,7 +3011,7 @@ bool CompilerMSL::MemberSorter::operator()(uint32_t mbr_idx1, uint32_t mbr_idx2)
return (mbr_meta1.offset < mbr_meta2.offset) || return (mbr_meta1.offset < mbr_meta2.offset) ||
((mbr_meta1.offset == mbr_meta2.offset) && (mbr_meta1.location > mbr_meta2.location)); ((mbr_meta1.offset == mbr_meta2.offset) && (mbr_meta1.location > mbr_meta2.location));
case Alphabetical: case Alphabetical:
return mbr_meta1.alias > mbr_meta2.alias; return mbr_meta1.alias < mbr_meta2.alias;
default: default:
return false; return false;
} }

Просмотреть файл

@ -202,8 +202,9 @@ protected:
uint32_t get_ordered_member_location(uint32_t type_id, uint32_t index); 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; size_t get_declared_struct_member_alignment(const SPIRType &struct_type, uint32_t index) const;
std::string to_component_argument(uint32_t id); std::string to_component_argument(uint32_t id);
void exclude_from_stage_in(SPIRVariable &var); bool should_move_to_input_buffer(SPIRType &type, bool is_builtin, spv::StorageClass storage);
void exclude_member_from_stage_in(const SPIRType &type, uint32_t index); 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); 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); uint32_t get_input_buffer_block_var_id(uint32_t msl_buffer);
void align_struct(SPIRType &ib_type); void align_struct(SPIRType &ib_type);