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
{
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]];
};

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

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

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

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

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

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

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

@ -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;
}
bool Compiler::is_array(const SPIRType &type) const
{
return !type.array.empty();
}
ShaderResources Compiler::get_shader_resources() const
{
return get_shader_resources(nullptr);

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

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

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

@ -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()

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

@ -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;
@ -2607,19 +2632,22 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin)
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);
else
return CompilerGLSL::builtin_to_glsl(builtin);
break;
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
@ -2663,16 +2691,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:
@ -2987,7 +3011,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;
}

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

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