Fix bugs with row-major matrices inside flattened UBOs.

This commit is contained in:
Hans-Kristian Arntzen 2017-01-21 13:49:32 +01:00
parent d93dc38415
commit 3eb2e52c4e
5 changed files with 94 additions and 12 deletions

View File

@ -1,10 +1,11 @@
#version 310 es #version 310 es
uniform vec4 UBO[8]; uniform vec4 UBO[12];
in vec4 aVertex; in vec4 aVertex;
void main() void main()
{ {
vec2 v = mat4x2(UBO[8].xy, UBO[9].xy, UBO[10].xy, UBO[11].xy) * aVertex;
gl_Position = (mat4(UBO[0], UBO[1], UBO[2], UBO[3]) * aVertex) + (aVertex * mat4(UBO[4], UBO[5], UBO[6], UBO[7])); gl_Position = (mat4(UBO[0], UBO[1], UBO[2], UBO[3]) * aVertex) + (aVertex * mat4(UBO[4], UBO[5], UBO[6], UBO[7]));
} }

View File

@ -0,0 +1,25 @@
#version 310 es
struct Foo
{
mat3x4 MVP0;
mat3x4 MVP1;
};
uniform vec4 UBO[8];
layout(location = 0) in vec4 v0;
layout(location = 1) in vec4 v1;
layout(location = 0) out vec3 V0;
layout(location = 1) out vec3 V1;
void main()
{
Foo f;
f.MVP0 = Foo(transpose(mat4x3(UBO[0].xyz, UBO[1].xyz, UBO[2].xyz, UBO[3].xyz)), transpose(mat4x3(UBO[4].xyz, UBO[5].xyz, UBO[6].xyz, UBO[7].xyz))).MVP0;
f.MVP1 = Foo(transpose(mat4x3(UBO[0].xyz, UBO[1].xyz, UBO[2].xyz, UBO[3].xyz)), transpose(mat4x3(UBO[4].xyz, UBO[5].xyz, UBO[6].xyz, UBO[7].xyz))).MVP1;
vec3 a = v0 * f.MVP0;
vec3 b = v1 * f.MVP1;
V0 = a;
V1 = b;
}

View File

@ -4,11 +4,13 @@ layout(std140) uniform UBO
{ {
layout(column_major) mat4 uMVPR; layout(column_major) mat4 uMVPR;
layout(row_major) mat4 uMVPC; layout(row_major) mat4 uMVPC;
layout(row_major) mat2x4 uMVP;
}; };
in vec4 aVertex; in vec4 aVertex;
void main() void main()
{ {
vec2 v = aVertex * uMVP;
gl_Position = uMVPR * aVertex + uMVPC * aVertex; gl_Position = uMVPR * aVertex + uMVPC * aVertex;
} }

View File

@ -0,0 +1,26 @@
#version 310 es
struct Foo
{
mat3x4 MVP0;
mat3x4 MVP1;
};
layout(std140, binding = 0) uniform UBO
{
layout(row_major) Foo foo;
};
layout(location = 0) in vec4 v0;
layout(location = 1) in vec4 v1;
layout(location = 0) out vec3 V0;
layout(location = 1) out vec3 V1;
void main()
{
Foo f = foo;
vec3 a = v0 * f.MVP0;
vec3 b = v1 * f.MVP1;
V0 = a;
V1 = b;
}

View File

@ -18,6 +18,7 @@
#include "GLSL.std.450.h" #include "GLSL.std.450.h"
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
#include <utility>
using namespace spv; using namespace spv;
using namespace spirv_cross; using namespace spirv_cross;
@ -3352,15 +3353,30 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin
expr += type_to_glsl_constructor(target_type); expr += type_to_glsl_constructor(target_type);
expr += "("; expr += "(";
// Need to have an extra indices for the member so we can find matrix strides.
vector<uint32_t> indices_copy(indices, indices + count);
indices_copy.push_back(0);
for (size_t i = 0; i < target_type.member_types.size(); ++i) for (size_t i = 0; i < target_type.member_types.size(); ++i)
{ {
if (i != 0) if (i != 0)
expr += ", "; expr += ", ";
const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]); const SPIRType &member_type = get<SPIRType>(target_type.member_types[i]);
uint32_t member_offset = type_struct_member_offset(target_type, uint32_t(i));
expr += flattened_access_chain(base, indices, count, member_type, offset + member_offset); // The indices should be IDs, but to avoid creating new dummy SPIRConstant here,
// use MSB to indicate literals.
indices_copy.back() = uint32_t(i) | 0x80000000u;
bool need_transpose = false;
if (member_type.columns > 1)
flattened_access_chain_offset(base, indices_copy.data(), count + 1, offset, &need_transpose);
auto tmp = flattened_access_chain(base, indices_copy.data(), count + 1, member_type, offset);
if (need_transpose)
expr += convert_row_major_matrix(tmp);
else
expr += tmp;
} }
expr += ")"; expr += ")";
@ -3374,17 +3390,24 @@ std::string CompilerGLSL::flattened_access_chain_matrix(uint32_t base, const uin
std::string expr; std::string expr;
uint32_t matrix_stride = 0; uint32_t matrix_stride = 0;
flattened_access_chain_offset(base, indices, count, offset, nullptr, &matrix_stride); bool need_transpose = false;
flattened_access_chain_offset(base, indices, count, offset, &need_transpose, &matrix_stride);
expr += type_to_glsl_constructor(target_type); assert(matrix_stride);
SPIRType tmp_type = target_type;
if (need_transpose)
swap(tmp_type.vecsize, tmp_type.columns);
expr += type_to_glsl_constructor(tmp_type);
expr += "("; expr += "(";
for (uint32_t i = 0; i < target_type.columns; i++) for (uint32_t i = 0; i < tmp_type.columns; i++)
{ {
if (i != 0) if (i != 0)
expr += ", "; expr += ", ";
expr += flattened_access_chain_vector_scalar(base, indices, count, target_type, offset + i * matrix_stride); expr += flattened_access_chain_vector_scalar(base, indices, count, tmp_type, offset + i * matrix_stride);
} }
expr += ")"; expr += ")";
@ -3471,23 +3494,28 @@ std::pair<std::string, uint32_t> CompilerGLSL::flattened_access_chain_offset(uin
// We also check if this member is a builtin, since we then replace the entire expression with the builtin one. // We also check if this member is a builtin, since we then replace the entire expression with the builtin one.
else if (type->basetype == SPIRType::Struct) else if (type->basetype == SPIRType::Struct)
{ {
index = get<SPIRConstant>(index).scalar(); // The indices should be IDs, but to avoid creating new dummy SPIRConstant here,
// use MSB to indicate literals.
// See flattened_access_chain_struct.
index = (index & 0x80000000u) ? (index & 0x7fffffffu) : get<SPIRConstant>(index).scalar();
if (index >= type->member_types.size()) if (index >= type->member_types.size())
SPIRV_CROSS_THROW("Member index is out of bounds!"); SPIRV_CROSS_THROW("Member index is out of bounds!");
offset += type_struct_member_offset(*type, index); offset += type_struct_member_offset(*type, index);
row_major_matrix_needs_conversion =
(combined_decoration_for_member(*type, index) & (1ull << DecorationRowMajor)) != 0;
current_type = type->member_types[index]; current_type = type->member_types[index];
auto &struct_type = *type; auto &struct_type = *type;
type = &get<SPIRType>(type->member_types[index]); type = &get<SPIRType>(type->member_types[index]);
if (type->columns > 1) if (type->columns > 1)
{
matrix_stride = type_struct_member_matrix_stride(struct_type, index); matrix_stride = type_struct_member_matrix_stride(struct_type, index);
row_major_matrix_needs_conversion =
(combined_decoration_for_member(struct_type, index) & (1ull << DecorationRowMajor)) != 0;
}
else
row_major_matrix_needs_conversion = false;
} }
// Matrix -> Vector // Matrix -> Vector
else if (type->columns > 1) else if (type->columns > 1)