Properly flatten MRT outputs in MSL.

This commit is contained in:
Hans-Kristian Arntzen 2018-03-13 14:03:35 +01:00
Родитель 6e6ca0b237
Коммит 8e90382675
6 изменённых файлов: 125 добавлений и 38 удалений

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

@ -13,7 +13,10 @@ struct main0_in
struct main0_out struct main0_out
{ {
float4 FragColor [[color(0)]][4]; float4 FragColor_0 [[color(0)]];
float4 FragColor_1 [[color(1)]];
float4 FragColor_2 [[color(2)]];
float4 FragColor_3 [[color(3)]];
}; };
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() // Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
@ -26,10 +29,15 @@ Tx mod(Tx x, Ty y)
fragment main0_out main0(main0_in in [[stage_in]]) fragment main0_out main0(main0_in in [[stage_in]])
{ {
main0_out out = {}; main0_out out = {};
out.FragColor[0] = mod(in.vA, in.vB); float4 FragColor[4];
out.FragColor[1] = in.vA + in.vB; FragColor[0] = mod(in.vA, in.vB);
out.FragColor[2] = in.vA - in.vB; FragColor[1] = in.vA + in.vB;
out.FragColor[3] = in.vA * in.vB; FragColor[2] = in.vA - in.vB;
FragColor[3] = in.vA * in.vB;
out.FragColor_0 = FragColor[0];
out.FragColor_1 = FragColor[1];
out.FragColor_2 = FragColor[2];
out.FragColor_3 = FragColor[3];
return out; return out;
} }

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

@ -13,7 +13,10 @@ struct main0_in
struct main0_out struct main0_out
{ {
float4 FragColor [[color(0)]][4]; float4 FragColor_0 [[color(0)]];
float4 FragColor_1 [[color(1)]];
float4 FragColor_2 [[color(2)]];
float4 FragColor_3 [[color(3)]];
}; };
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod() // Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
@ -23,13 +26,28 @@ Tx mod(Tx x, Ty y)
return x - y * floor(x / y); return x - y * floor(x / y);
} }
void write_deeper_in_function(thread float4 (&FragColor)[4], thread float4& vA, thread float4& vB)
{
FragColor[3] = vA * vB;
}
void write_in_function(thread float4 (&FragColor)[4], thread float4& vA, thread float4& vB)
{
FragColor[2] = vA - vB;
write_deeper_in_function(FragColor, vA, vB);
}
fragment main0_out main0(main0_in in [[stage_in]]) fragment main0_out main0(main0_in in [[stage_in]])
{ {
main0_out out = {}; main0_out out = {};
out.FragColor[0] = mod(in.vA, in.vB); float4 FragColor[4];
out.FragColor[1] = in.vA + in.vB; FragColor[0] = mod(in.vA, in.vB);
out.FragColor[2] = in.vA - in.vB; FragColor[1] = in.vA + in.vB;
out.FragColor[3] = in.vA * in.vB; write_in_function(FragColor, in.vA, in.vB);
out.FragColor_0 = FragColor[0];
out.FragColor_1 = FragColor[1];
out.FragColor_2 = FragColor[2];
out.FragColor_3 = FragColor[3];
return out; return out;
} }

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

@ -5,10 +5,20 @@ layout(location = 0) out vec4 FragColor[4];
layout(location = 0) in vec4 vA; layout(location = 0) in vec4 vA;
layout(location = 1) in vec4 vB; layout(location = 1) in vec4 vB;
void write_deeper_in_function()
{
FragColor[3] = vA * vB;
}
void write_in_function()
{
FragColor[2] = vA - vB;
write_deeper_in_function();
}
void main() void main()
{ {
FragColor[0] = mod(vA, vB); FragColor[0] = mod(vA, vB);
FragColor[1] = vA + vB; FragColor[1] = vA + vB;
FragColor[2] = vA - vB; write_in_function();
FragColor[3] = vA * vB;
} }

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

@ -739,6 +739,10 @@ struct SPIRFunction : IVariant
arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable }); arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable });
} }
// Statements to be emitted when the function returns.
// Mostly used for lowering internal data structures onto flattened structures.
std::vector<std::string> fixup_statements;
bool active = false; bool active = false;
bool flush_undeclared = true; bool flush_undeclared = true;
bool do_combined_parameters = true; bool do_combined_parameters = true;

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

@ -9063,6 +9063,8 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
} }
case SPIRBlock::Return: case SPIRBlock::Return:
for (auto &line : current_function->fixup_statements)
statement(line);
if (processing_entry_point) if (processing_entry_point)
emit_fixup(); emit_fixup();

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

@ -550,8 +550,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);
if (should_move_to_input_buffer(mbr_type_id, is_builtin, storage)) if (should_move_to_input_buffer(mbr_type_id, is_builtin, storage))
{
move_member_to_input_buffer(type, mbr_idx); move_member_to_input_buffer(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.
@ -609,34 +610,78 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
} }
else if (!is_builtin || has_active_builtin(builtin, storage)) else if (!is_builtin || has_active_builtin(builtin, storage))
{ {
// Add a reference to the variable type to the interface struct. // Arrays of MRT output is not allowed in MSL, so need to handle it specially.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size()); if (!is_builtin &&
type_id = ensure_correct_builtin_type(type_id, builtin); storage == StorageClassOutput &&
p_var->basetype = type_id; get_entry_point().model == ExecutionModelFragment &&
ib_type.member_types.push_back(type_id); !type.array.empty())
// Give the member a name
string mbr_name = ensure_valid_name(to_expression(p_var->self), "m");
set_member_name(ib_type_id, ib_mbr_idx, mbr_name);
// Update the original variable reference to include the structure reference
string qual_var_name = ib_var_ref + "." + mbr_name;
meta[p_var->self].decoration.qualified_alias = qual_var_name;
// Copy the variable location from the original variable to the member
if (get_decoration_bitset(p_var->self).get(DecorationLocation))
{ {
uint32_t locn = get_decoration(p_var->self, DecorationLocation); if (type.array.size() != 1)
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn); SPIRV_CROSS_THROW("Cannot emit arrays-of-arrays with MRT.");
mark_location_as_used_by_shader(locn, storage);
uint32_t num_mrts =
type.array_size_literal.back() ? type.array.back() : get<SPIRConstant>(type.array.back()).scalar();
auto *no_array_type = &type;
while (!no_array_type->array.empty())
no_array_type = &get<SPIRType>(no_array_type->parent_type);
auto &entry_func = get<SPIRFunction>(entry_point);
entry_func.add_local_variable(p_var->self);
for (uint32_t i = 0; i < num_mrts; i++)
{
// Add a reference to the variable type to the interface struct.
uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
ib_type.member_types.push_back(no_array_type->self);
// Give the member a name
string mbr_name = ensure_valid_name(join(to_expression(p_var->self), "_", i), "m");
set_member_name(ib_type_id, ib_mbr_idx, mbr_name);
// There is no qualified alias since we need to flatten the internal array on return.
if (get_decoration_bitset(p_var->self).get(DecorationLocation))
{
uint32_t locn = get_decoration(p_var->self, DecorationLocation) + i;
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage);
}
// Lower the internal array to flattened output when entry point returns.
entry_func.fixup_statements.push_back(join(ib_var_ref, ".", mbr_name, " = ", to_name(p_var->self), "[", i, "];"));
}
} }
else
// Mark the member as builtin if needed
if (is_builtin)
{ {
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationBuiltIn, builtin); // Add a reference to the variable type to the interface struct.
if (builtin == BuiltInPosition) uint32_t ib_mbr_idx = uint32_t(ib_type.member_types.size());
qual_pos_var_name = qual_var_name; type_id = ensure_correct_builtin_type(type_id, builtin);
p_var->basetype = type_id;
ib_type.member_types.push_back(type_id);
// Give the member a name
string mbr_name = ensure_valid_name(to_expression(p_var->self), "m");
set_member_name(ib_type_id, ib_mbr_idx, mbr_name);
// Update the original variable reference to include the structure reference
string qual_var_name = ib_var_ref + "." + mbr_name;
meta[p_var->self].decoration.qualified_alias = qual_var_name;
// Copy the variable location from the original variable to the member
if (get_decoration_bitset(p_var->self).get(DecorationLocation))
{
uint32_t locn = get_decoration(p_var->self, DecorationLocation);
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationLocation, locn);
mark_location_as_used_by_shader(locn, storage);
}
// Mark the member as builtin if needed
if (is_builtin)
{
set_member_decoration(ib_type_id, ib_mbr_idx, DecorationBuiltIn, builtin);
if (builtin == BuiltInPosition)
qual_pos_var_name = qual_var_name;
}
} }
} }
} }