Can deal with std140 matrices now.
Refactor is coming together.
This commit is contained in:
parent
dd7ebaf9f7
commit
f6251e4699
@ -6561,7 +6561,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
is_invariant = true;
|
is_invariant = true;
|
||||||
|
|
||||||
is_packed = member_is_packed_physical_type(*type, index);
|
is_packed = member_is_packed_physical_type(*type, index);
|
||||||
if (member_is_packed_physical_type(*type, index))
|
if (member_is_remapped_physical_type(*type, index))
|
||||||
physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
|
physical_type = get_extended_member_decoration(type->self, index, SPIRVCrossDecorationPhysicalTypeID);
|
||||||
else
|
else
|
||||||
physical_type = 0;
|
physical_type = 0;
|
||||||
@ -6572,6 +6572,8 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice
|
|||||||
// Matrix -> Vector
|
// Matrix -> Vector
|
||||||
else if (type->columns > 1)
|
else if (type->columns > 1)
|
||||||
{
|
{
|
||||||
|
// FIXME: This cannot work for storing into a row-major matrix, this expression will become an r-value.
|
||||||
|
// We should defer the row-major conversion until Load or Store.
|
||||||
if (row_major_matrix_needs_conversion)
|
if (row_major_matrix_needs_conversion)
|
||||||
{
|
{
|
||||||
expr = convert_row_major_matrix(expr, *type, physical_type, is_packed);
|
expr = convert_row_major_matrix(expr, *type, physical_type, is_packed);
|
||||||
|
196
spirv_msl.cpp
196
spirv_msl.cpp
@ -2518,6 +2518,14 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
|||||||
if (validate_member_packing_rules_msl(ib_type, index))
|
if (validate_member_packing_rules_msl(ib_type, index))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// We failed validation.
|
||||||
|
// This case will be nightmare-ish to deal with. This could possibly happen if struct alignment does not quite
|
||||||
|
// match up with what we want. Scalar block layout comes to mind here where we might have to work around the rule
|
||||||
|
// that struct alignment == max alignment of all members and struct size depends on this alignment.
|
||||||
|
auto &mbr_type = get<SPIRType>(ib_type.member_types[index]);
|
||||||
|
if (mbr_type.basetype == SPIRType::Struct)
|
||||||
|
SPIRV_CROSS_THROW("Cannot perform any repacking for structs when it is used as a member of another struct.");
|
||||||
|
|
||||||
// Perform remapping here.
|
// Perform remapping here.
|
||||||
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||||
|
|
||||||
@ -2527,31 +2535,66 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
|||||||
|
|
||||||
// We're in deep trouble, and we need to create a new PhysicalType which matches up with what we expect.
|
// We're in deep trouble, and we need to create a new PhysicalType which matches up with what we expect.
|
||||||
// A lot of work goes here ...
|
// A lot of work goes here ...
|
||||||
|
// We will need remapping on Load and Store to translate the types between Logical and Physical.
|
||||||
|
|
||||||
auto physical_type = get<SPIRType>(ib_type.member_types[index]);
|
// First, we check if we have small vector std140 array.
|
||||||
physical_type.vecsize = 4;
|
// We detect this if we have an array of vectors, and array stride is greater than number of elements.
|
||||||
|
if (!mbr_type.array.empty() && !is_matrix(mbr_type))
|
||||||
|
{
|
||||||
|
uint32_t array_stride = type_struct_member_array_stride(ib_type, index);
|
||||||
|
|
||||||
|
// Hack off array-of-arrays until we find the array stride per element we must have to make it work.
|
||||||
|
uint32_t dimensions = mbr_type.array.size() - 1;
|
||||||
|
for (uint32_t dim = 0; dim < dimensions; dim++)
|
||||||
|
array_stride /= max(to_array_size_literal(mbr_type, dim), 1u);
|
||||||
|
|
||||||
|
uint32_t elems_per_stride = array_stride / (mbr_type.width / 8);
|
||||||
|
|
||||||
|
if (elems_per_stride > 4)
|
||||||
|
SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL.");
|
||||||
|
|
||||||
|
auto physical_type = mbr_type;
|
||||||
|
physical_type.vecsize = elems_per_stride;
|
||||||
|
physical_type.parent_type = 0;
|
||||||
uint32_t type_id = ir.increase_bound_by(1);
|
uint32_t type_id = ir.increase_bound_by(1);
|
||||||
set<SPIRType>(type_id, physical_type);
|
set<SPIRType>(type_id, physical_type);
|
||||||
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id);
|
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id);
|
||||||
|
set_decoration(type_id, DecorationArrayStride, array_stride);
|
||||||
|
|
||||||
|
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||||
|
if (elems_per_stride != 3)
|
||||||
|
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||||
|
}
|
||||||
|
else if (is_matrix(mbr_type))
|
||||||
|
{
|
||||||
|
// MatrixStride might be std140-esque.
|
||||||
|
uint32_t matrix_stride = type_struct_member_matrix_stride(ib_type, index);
|
||||||
|
|
||||||
|
uint32_t elems_per_stride = matrix_stride / (mbr_type.width / 8);
|
||||||
|
|
||||||
|
if (elems_per_stride > 4)
|
||||||
|
SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL.");
|
||||||
|
|
||||||
|
bool row_major = has_member_decoration(ib_type.self, index, DecorationRowMajor);
|
||||||
|
|
||||||
|
auto physical_type = mbr_type;
|
||||||
|
physical_type.parent_type = 0;
|
||||||
|
if (row_major)
|
||||||
|
physical_type.columns = elems_per_stride;
|
||||||
|
else
|
||||||
|
physical_type.vecsize = elems_per_stride;
|
||||||
|
uint32_t type_id = ir.increase_bound_by(1);
|
||||||
|
set<SPIRType>(type_id, physical_type);
|
||||||
|
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id);
|
||||||
|
|
||||||
|
// Remove packed_ for vectors of size 1, 2 and 4.
|
||||||
|
if (elems_per_stride != 3)
|
||||||
|
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CompilerMSL::get_member_packed_type(SPIRType &type, uint32_t index)
|
// This better validate now, or we must fail gracefully.
|
||||||
{
|
if (!validate_member_packing_rules_msl(ib_type, index))
|
||||||
auto &mbr_type = get<SPIRType>(type.member_types[index]);
|
SPIRV_CROSS_THROW("Found a buffer packing case which we cannot represent in MSL.");
|
||||||
if (is_matrix(mbr_type) && has_member_decoration(type.self, index, DecorationRowMajor))
|
|
||||||
{
|
|
||||||
// Packed row-major matrices are stored transposed. But, we don't know if
|
|
||||||
// we're dealing with a row-major matrix at the time we need to load it.
|
|
||||||
// So, we'll set a packed type with the columns and rows transposed, so we'll
|
|
||||||
// know to use the correct constructor.
|
|
||||||
uint32_t new_type_id = ir.increase_bound_by(1);
|
|
||||||
auto &transpose_type = set<SPIRType>(new_type_id);
|
|
||||||
transpose_type = mbr_type;
|
|
||||||
transpose_type.vecsize = mbr_type.columns;
|
|
||||||
transpose_type.columns = mbr_type.vecsize;
|
|
||||||
return new_type_id;
|
|
||||||
}
|
|
||||||
return type.member_types[index];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
|
void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression)
|
||||||
@ -2563,20 +2606,28 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Special handling when storing to a float[] or float2[] in std140 layout.
|
// Special handling when storing to a remapped physical type.
|
||||||
|
// This is mostly to deal with std140 padded matrices or vectors.
|
||||||
|
|
||||||
uint32_t type_id = get_extended_decoration(lhs_expression, SPIRVCrossDecorationPhysicalTypeID);
|
uint32_t physical_type_id = get_extended_decoration(lhs_expression, SPIRVCrossDecorationPhysicalTypeID);
|
||||||
auto &type = get<SPIRType>(type_id);
|
auto &physical_type = get<SPIRType>(physical_type_id);
|
||||||
|
auto &type = expression_type(rhs_expression);
|
||||||
string lhs = to_dereferenced_expression(lhs_expression);
|
string lhs = to_dereferenced_expression(lhs_expression);
|
||||||
string rhs = to_pointer_expression(rhs_expression);
|
string rhs = to_pointer_expression(rhs_expression);
|
||||||
uint32_t stride = get_decoration(type_id, DecorationArrayStride);
|
|
||||||
|
|
||||||
if (is_matrix(type))
|
static const char *swizzle_lut[] = {
|
||||||
|
".x",
|
||||||
|
".xy",
|
||||||
|
".xyz",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (is_matrix(physical_type))
|
||||||
{
|
{
|
||||||
// Packed matrices are stored as arrays of packed vectors, so we need
|
// Packed matrices are stored as arrays of packed vectors, so we need
|
||||||
// to assign the vectors one at a time.
|
// to assign the vectors one at a time.
|
||||||
// For row-major matrices, we need to transpose the *right-hand* side,
|
// For row-major matrices, we need to transpose the *right-hand* side,
|
||||||
// not the left-hand side. Otherwise, the changes will be lost.
|
// not the left-hand side. Otherwise, the changes will be lost.
|
||||||
|
|
||||||
auto *lhs_e = maybe_get<SPIRExpression>(lhs_expression);
|
auto *lhs_e = maybe_get<SPIRExpression>(lhs_expression);
|
||||||
auto *rhs_e = maybe_get<SPIRExpression>(rhs_expression);
|
auto *rhs_e = maybe_get<SPIRExpression>(rhs_expression);
|
||||||
bool transpose = lhs_e && lhs_e->need_transpose;
|
bool transpose = lhs_e && lhs_e->need_transpose;
|
||||||
@ -2588,8 +2639,14 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp
|
|||||||
lhs = to_dereferenced_expression(lhs_expression);
|
lhs = to_dereferenced_expression(lhs_expression);
|
||||||
rhs = to_pointer_expression(rhs_expression);
|
rhs = to_pointer_expression(rhs_expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *store_swiz = "";
|
||||||
|
if (physical_type.vecsize != type.vecsize)
|
||||||
|
store_swiz = swizzle_lut[type.vecsize - 1];
|
||||||
|
|
||||||
for (uint32_t i = 0; i < type.columns; i++)
|
for (uint32_t i = 0; i < type.columns; i++)
|
||||||
statement(enclose_expression(lhs), "[", i, "] = ", enclose_expression(rhs), "[", i, "];");
|
statement(enclose_expression(lhs), "[", i, "]", store_swiz, " = ", enclose_expression(rhs), "[", i, "];");
|
||||||
|
|
||||||
if (transpose)
|
if (transpose)
|
||||||
{
|
{
|
||||||
lhs_e->need_transpose = true;
|
lhs_e->need_transpose = true;
|
||||||
@ -2597,14 +2654,14 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp
|
|||||||
rhs_e->need_transpose = !rhs_e->need_transpose;
|
rhs_e->need_transpose = !rhs_e->need_transpose;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_array(type) && stride == 4 * type.width / 8)
|
else if (is_array(physical_type) && physical_type.vecsize > type.vecsize)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
||||||
|
|
||||||
// Unpack the expression so we can store to it with a float or float2.
|
// Unpack the expression so we can store to it with a float or float2.
|
||||||
// It's still an l-value, so it's fine. Most other unpacking of expressions turn them into r-values instead.
|
// It's still an l-value, so it's fine. Most other unpacking of expressions turn them into r-values instead.
|
||||||
if (is_scalar(type))
|
lhs = enclose_expression(lhs) + swizzle_lut[type.vecsize - 1];
|
||||||
lhs = enclose_expression(lhs) + ".x";
|
|
||||||
else if (is_vector(type) && type.vecsize == 2)
|
|
||||||
lhs = enclose_expression(lhs) + ".xy";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_matrix(type))
|
if (!is_matrix(type))
|
||||||
@ -2612,45 +2669,55 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp
|
|||||||
if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
|
if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs))
|
||||||
statement(lhs, " = ", rhs, ";");
|
statement(lhs, " = ", rhs, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
register_write(lhs_expression);
|
register_write(lhs_expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the format of the current expression from packed to unpacked,
|
// Converts the format of the current expression from packed to unpacked,
|
||||||
// by wrapping the expression in a constructor of the appropriate type.
|
// by wrapping the expression in a constructor of the appropriate type.
|
||||||
string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type, uint32_t packed_type_id, bool packed)
|
// Also, handle special physical ID remapping scenarios, similar to emit_store_statement().
|
||||||
|
string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type, uint32_t physical_type_id, bool packed)
|
||||||
{
|
{
|
||||||
(void)packed;
|
(void)packed;
|
||||||
|
|
||||||
const SPIRType *packed_type = nullptr;
|
const SPIRType *physical_type = nullptr;
|
||||||
uint32_t stride = 0;
|
if (physical_type_id)
|
||||||
if (packed_type_id)
|
physical_type = &get<SPIRType>(physical_type_id);
|
||||||
{
|
|
||||||
packed_type = &get<SPIRType>(packed_type_id);
|
|
||||||
stride = get_decoration(packed_type_id, DecorationArrayStride);
|
|
||||||
}
|
|
||||||
|
|
||||||
// float[] and float2[] cases are really just padding, so directly swizzle from the backing float4 instead.
|
static const char *swizzle_lut[] = {
|
||||||
if (packed_type && is_array(*packed_type) && is_scalar(*packed_type) && stride == 4 * packed_type->width / 8)
|
".x",
|
||||||
return enclose_expression(expr_str) + ".x";
|
".xy",
|
||||||
else if (packed_type && is_array(*packed_type) && is_vector(*packed_type) && packed_type->vecsize == 2 &&
|
".xyz",
|
||||||
stride == 4 * packed_type->width / 8)
|
};
|
||||||
return enclose_expression(expr_str) + ".xy";
|
|
||||||
|
// std140 array cases for vectors.
|
||||||
|
if (physical_type && is_array(*physical_type) && physical_type->vecsize > type.vecsize)
|
||||||
|
{
|
||||||
|
assert(type.vecsize >= 1 && type.vecsize <= 3);
|
||||||
|
return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1];
|
||||||
|
}
|
||||||
else if (is_matrix(type))
|
else if (is_matrix(type))
|
||||||
{
|
{
|
||||||
// Packed matrices are stored as arrays of packed vectors. Unfortunately,
|
// Packed matrices are stored as arrays of packed vectors. Unfortunately,
|
||||||
// we can't just pass the array straight to the matrix constructor. We have to
|
// we can't just pass the array straight to the matrix constructor. We have to
|
||||||
// pass each vector individually, so that they can be unpacked to normal vectors.
|
// pass each vector individually, so that they can be unpacked to normal vectors.
|
||||||
if (!packed_type)
|
if (!physical_type)
|
||||||
packed_type = &type;
|
physical_type = &type;
|
||||||
const char *base_type = packed_type->width == 16 ? "half" : "float";
|
const char *base_type = type.width == 16 ? "half" : "float";
|
||||||
string unpack_expr = join(type_to_glsl(*packed_type), "(");
|
string unpack_expr = join(type_to_glsl(type), "(");
|
||||||
for (uint32_t i = 0; i < packed_type->columns; i++)
|
|
||||||
|
const char *load_swiz = "";
|
||||||
|
if (physical_type->vecsize != type.vecsize)
|
||||||
|
load_swiz = swizzle_lut[type.vecsize - 1];
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < type.columns; i++)
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
unpack_expr += ", ";
|
unpack_expr += ", ";
|
||||||
unpack_expr += join(base_type, packed_type->vecsize, "(", expr_str, "[", i, "])");
|
unpack_expr += join(base_type, physical_type->vecsize, "(", expr_str, "[", i, "]", ")", load_swiz);
|
||||||
}
|
}
|
||||||
|
|
||||||
unpack_expr += ")";
|
unpack_expr += ")";
|
||||||
return unpack_expr;
|
return unpack_expr;
|
||||||
}
|
}
|
||||||
@ -8653,18 +8720,33 @@ const SPIRType &CompilerMSL::get_physical_member_type(const SPIRType &type, uint
|
|||||||
return get<SPIRType>(type.member_types[index]);
|
return get<SPIRType>(type.member_types[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, bool is_packed, bool row_major) const
|
uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type,
|
||||||
|
bool is_packed, bool row_major) const
|
||||||
{
|
{
|
||||||
// Array stride in MSL is always size * array_size. sizeof(float3) == 16,
|
// Array stride in MSL is always size * array_size. sizeof(float3) == 16,
|
||||||
// unlike GLSL and HLSL where array stride would be 16 and size 12.
|
// unlike GLSL and HLSL where array stride would be 16 and size 12.
|
||||||
auto &parent_type = get<SPIRType>(type.parent_type);
|
|
||||||
if (!parent_type.array.empty())
|
// We could use parent type here and recurse, but that makes creating physical type remappings
|
||||||
|
// far more complicated. We'd rather just create the final type, and ignore having to create the entire type
|
||||||
|
// hierarchy in order to compute this value, so make a temporary type on the stack.
|
||||||
|
|
||||||
|
auto basic_type = type;
|
||||||
|
basic_type.array.clear();
|
||||||
|
basic_type.array_size_literal.clear();
|
||||||
|
uint32_t value_size = get_declared_type_size_msl(basic_type, is_packed, row_major);
|
||||||
|
|
||||||
|
uint32_t dimensions = type.array.size();
|
||||||
|
assert(dimensions > 0);
|
||||||
|
dimensions--;
|
||||||
|
|
||||||
|
// Multiply together every dimension, except the last one.
|
||||||
|
for (uint32_t dim = 0; dim < dimensions; dim++)
|
||||||
{
|
{
|
||||||
uint32_t array_size = to_array_size_literal(type);
|
uint32_t array_size = to_array_size_literal(type, dim);
|
||||||
return get_declared_type_array_stride_msl(parent_type, is_packed, row_major) * max(array_size, 1u);
|
value_size *= max(array_size, 1u);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
return get_declared_type_size_msl(parent_type, is_packed, row_major);
|
return value_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t CompilerMSL::get_declared_struct_member_array_stride_msl(const SPIRType &type, uint32_t index) const
|
uint32_t CompilerMSL::get_declared_struct_member_array_stride_msl(const SPIRType &type, uint32_t index) const
|
||||||
|
@ -531,7 +531,6 @@ protected:
|
|||||||
void align_struct(SPIRType &ib_type, std::unordered_set<uint32_t> &aligned_structs);
|
void align_struct(SPIRType &ib_type, std::unordered_set<uint32_t> &aligned_structs);
|
||||||
void ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t index);
|
void ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t index);
|
||||||
bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const;
|
bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const;
|
||||||
uint32_t get_member_packed_type(SPIRType &ib_type, uint32_t index);
|
|
||||||
std::string get_argument_address_space(const SPIRVariable &argument);
|
std::string get_argument_address_space(const SPIRVariable &argument);
|
||||||
std::string get_type_address_space(const SPIRType &type, uint32_t id);
|
std::string get_type_address_space(const SPIRType &type, uint32_t id);
|
||||||
const char *to_restrict(uint32_t id, bool space = true);
|
const char *to_restrict(uint32_t id, bool space = true);
|
||||||
|
Loading…
Reference in New Issue
Block a user