Add support for matrix operations (transpose/determinant/inverse)

This commit is contained in:
baldurk committed 2020-04-15 20:33:57 +01:00
1 parent 26f5b6a4b4
commit c3a5d99bc0
5 files changed
+301 -6

No files matched your search

@@ -1455,6 +1455,21 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray<ThreadState>
SetDst(state, mul.result, var);
break;
}
case Op::Transpose:
{
OpTranspose transpose(it);
ShaderVariable matrix = GetSrc(transpose.matrix);
ShaderVariable var = matrix;
std::swap(var.rows, var.columns);
for(uint8_t r = 0; r < var.rows; r++)
for(uint8_t c = 0; c < var.columns; c++)
var.value.fv[r * var.columns + c] = matrix.value.fv[c * matrix.columns + r];
SetDst(state, transpose.result, var);
break;
}
case Op::MatrixTimesVector:
{
OpMatrixTimesVector mul(it);
@@ -24,6 +24,7 @@
#include "spirv_debug.h"
#include <math.h>
#include "maths/matrix.h"
namespace rdcspv
{
@@ -179,6 +180,67 @@ ShaderVariable Pow(ThreadState &state, const rdcarray<Id> &params)
return var;
}
ShaderVariable Determinant(ThreadState &state, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable m = state.GetSrc(params[0]);
RDCASSERTEQUAL(m.rows, m.columns);
if(m.rows == 4)
{
Matrix4f mat;
mat.SetFrom(m.value.fv);
m.value.f.x = mat.Determinant();
}
else if(m.rows == 3)
{
Matrix3f mat;
mat.SetFrom(m.value.fv);
m.value.f.x = mat.Determinant();
}
else if(m.rows == 2)
{
Matrix2f mat;
mat.SetFrom(m.value.fv);
m.value.f.x = mat.Determinant();
}
m.rows = m.columns = 1;
return m;
}
ShaderVariable MatrixInverse(ThreadState &state, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable m = state.GetSrc(params[0]);
RDCASSERTEQUAL(m.rows, m.columns);
if(m.rows == 4)
{
Matrix4f mat;
mat.SetFrom(m.value.fv);
memcpy(m.value.fv, mat.Inverse().Data(), sizeof(mat));
}
else if(m.rows == 3)
{
Matrix3f mat;
mat.SetFrom(m.value.fv);
memcpy(m.value.fv, mat.Inverse().Data(), sizeof(mat));
}
else if(m.rows == 2)
{
Matrix2f mat;
mat.SetFrom(m.value.fv);
memcpy(m.value.fv, mat.Inverse().Data(), sizeof(mat));
}
return m;
}
template <typename T>
static T GLSLMax(T x, T y)
{
@@ -457,6 +519,8 @@ void ConfigureGLSLStd450(ExtInstDispatcher &extinst)
EXT(Ceil);
EXT(Fract);
EXT(Pow);
EXT(Determinant);
EXT(MatrixInverse);
EXT(FMin);
EXT(UMin);
EXT(SMin);
+93 -6
View File
@@ -31,11 +31,6 @@
#include "quat.h"
#include "vec.h"
static inline size_t matIdx(const size_t x, const size_t y)
{
return x + y * 4;
}
Matrix4f Matrix4f::Mul(const Matrix4f &o) const
{
Matrix4f m;
@@ -62,6 +57,24 @@ Matrix4f Matrix4f::Transpose() const
return m;
}
float Matrix4f::Determinant() const
{
float a0 = (*this)[0] * (*this)[5] - (*this)[1] * (*this)[4];
float a1 = (*this)[0] * (*this)[6] - (*this)[2] * (*this)[4];
float a2 = (*this)[0] * (*this)[7] - (*this)[3] * (*this)[4];
float a3 = (*this)[1] * (*this)[6] - (*this)[2] * (*this)[5];
float a4 = (*this)[1] * (*this)[7] - (*this)[3] * (*this)[5];
float a5 = (*this)[2] * (*this)[7] - (*this)[3] * (*this)[6];
float b0 = (*this)[8] * (*this)[13] - (*this)[9] * (*this)[12];
float b1 = (*this)[8] * (*this)[14] - (*this)[10] * (*this)[12];
float b2 = (*this)[8] * (*this)[15] - (*this)[11] * (*this)[12];
float b3 = (*this)[9] * (*this)[14] - (*this)[10] * (*this)[13];
float b4 = (*this)[9] * (*this)[15] - (*this)[11] * (*this)[13];
float b5 = (*this)[10] * (*this)[15] - (*this)[11] * (*this)[14];
return a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
}
Matrix4f Matrix4f::Inverse() const
{
float a0 = (*this)[0] * (*this)[5] - (*this)[1] * (*this)[4];
@@ -120,7 +133,7 @@ Matrix4f Matrix4f::Inverse() const
}
// no inverse
return Matrix4f::Identity();
return Matrix4f::Zero();
}
Vec3f Matrix4f::Transform(const Vec3f &v, const float w) const
@@ -274,3 +287,77 @@ Matrix4f Matrix4f::ReversePerspective(const float degfov, const float N, const f
return Matrix4f(persp);
}
Matrix3f Matrix3f::Transpose() const
{
Matrix3f m;
for(size_t x = 0; x < 3; x++)
for(size_t y = 0; y < 3; y++)
m[matIdx(x, y)] = (*this)[matIdx(y, x)];
return m;
}
float Matrix3f::Determinant() const
{
return f[0] * (f[4] * f[8] - f[5] * f[7]) - f[1] * (f[3] * f[8] - f[5] * f[6]) +
f[2] * (f[3] * f[7] - f[4] * f[6]);
}
Matrix3f Matrix3f::Inverse() const
{
float det = Determinant();
Matrix3f m = {};
if(fabsf(det) > FLT_EPSILON)
{
m[0] = Matrix2f(f[matIdx(1, 1)], f[matIdx(2, 1)], f[matIdx(1, 2)], f[matIdx(2, 2)]).Determinant();
m[1] = Matrix2f(f[matIdx(1, 0)], f[matIdx(2, 0)], f[matIdx(1, 2)], f[matIdx(2, 2)]).Determinant();
m[2] = Matrix2f(f[matIdx(1, 0)], f[matIdx(2, 0)], f[matIdx(1, 1)], f[matIdx(2, 1)]).Determinant();
m[3] = Matrix2f(f[matIdx(0, 1)], f[matIdx(2, 1)], f[matIdx(0, 2)], f[matIdx(2, 2)]).Determinant();
m[4] = Matrix2f(f[matIdx(0, 0)], f[matIdx(2, 0)], f[matIdx(0, 2)], f[matIdx(2, 2)]).Determinant();
m[5] = Matrix2f(f[matIdx(0, 0)], f[matIdx(2, 0)], f[matIdx(0, 1)], f[matIdx(2, 1)]).Determinant();
m[6] = Matrix2f(f[matIdx(0, 1)], f[matIdx(1, 1)], f[matIdx(0, 2)], f[matIdx(1, 2)]).Determinant();
m[7] = Matrix2f(f[matIdx(0, 0)], f[matIdx(1, 0)], f[matIdx(0, 2)], f[matIdx(1, 2)]).Determinant();
m[8] = Matrix2f(f[matIdx(0, 0)], f[matIdx(1, 0)], f[matIdx(0, 1)], f[matIdx(1, 1)]).Determinant();
float invdet = 1.0f / Determinant();
for(size_t i = 0; i < 9; i++)
{
m[i] *= invdet;
if(i & 1)
m[i] *= -1.0f;
}
}
return m;
}
Matrix2f Matrix2f::Transpose() const
{
Matrix2f m = *this;
m[1] = f[2];
m[2] = f[1];
return m;
}
float Matrix2f::Determinant() const
{
return f[0] * f[3] - f[1] * f[2];
}
Matrix2f Matrix2f::Inverse() const
{
float det = Determinant();
Matrix2f m = {};
if(fabsf(det) > FLT_EPSILON)
{
float invdet = 1.0f / Determinant();
m[0] = invdet * f[3];
m[1] = invdet * -f[1];
m[2] = invdet * -f[2];
m[3] = invdet * f[0];
}
return m;
}
+44
View File
@@ -65,12 +65,14 @@ public:
inline float operator[](const size_t i) const { return f[i]; }
inline float &operator[](const size_t i) { return f[i]; }
Matrix4f Transpose() const;
float Determinant() const;
Matrix4f Inverse() const;
Matrix4f Mul(const Matrix4f &o) const;
Vec3f Transform(const Vec3f &v, const float w = 1.0f) const;
const float *Data() const { return &f[0]; }
void SetFrom(float data[16]) { memcpy(f, data, sizeof(Matrix4f)); }
const Vec3f GetPosition() const;
const Vec3f GetForward() const;
const Vec3f GetRight() const;
@@ -80,5 +82,47 @@ private:
Matrix4f(const float *d) { memcpy(f, d, sizeof(Matrix4f)); }
friend class Quatf;
constexpr inline size_t matIdx(const size_t x, const size_t y) const { return x + y * 4; }
float f[16];
};
class Matrix3f
{
public:
Matrix3f() {}
inline float operator[](const size_t i) const { return f[i]; }
inline float &operator[](const size_t i) { return f[i]; }
Matrix3f Transpose() const;
float Determinant() const;
Matrix3f Inverse() const;
const float *Data() const { return &f[0]; }
void SetFrom(float data[9]) { memcpy(f, data, sizeof(Matrix3f)); }
private:
constexpr inline size_t matIdx(const size_t x, const size_t y) const { return x + y * 3; }
float f[9];
};
class Matrix2f
{
public:
Matrix2f() {}
Matrix2f(float a, float b, float c, float d)
{
f[0] = a;
f[1] = b;
f[2] = c;
f[3] = d;
}
inline float operator[](const size_t i) const { return f[i]; }
inline float &operator[](const size_t i) { return f[i]; }
Matrix2f Transpose() const;
float Determinant() const;
Matrix2f Inverse() const;
const float *Data() const { return &f[0]; }
void SetFrom(float data[4]) { memcpy(f, data, sizeof(Matrix2f)); }
private:
constexpr inline size_t matIdx(const size_t x, const size_t y) const { return x + y * 2; }
float f[4];
};
@@ -953,6 +953,23 @@ void main()
%_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19
%_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec
)EOTEST",
R"EOTEST(
%_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3
%_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7
%_mat1 = OpCompositeConstruct %float4x2 %_cola %_colb
%_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11
%_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15
%_mat2 = OpCompositeConstruct %float4x2 %_colc %_cold
%_mat2t = OpTranspose %float2x4 %_mat2
%_mat = OpMatrixTimesMatrix %float4x4 %_mat1 %_mat2t
%_vec = OpCompositeConstruct %float4 %randf_16 %randf_17 %randf_18 %randf_19
%_out_float4 = OpMatrixTimesVector %float4 %_mat %_vec
)EOTEST",
R"EOTEST(
@@ -968,9 +985,76 @@ void main()
R"EOTEST(
%_vec = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3
%_out_float4 = OpVectorTimesScalar %float4 %_vec %randf_4
)EOTEST",
R"EOTEST(
%_cola = OpCompositeConstruct %float2 %randf_0 %randf_1
%_colb = OpCompositeConstruct %float2 %randf_4 %randf_5
%_colc = OpCompositeConstruct %float2 %randf_8 %randf_9
%_cold = OpCompositeConstruct %float2 %randf_12 %randf_13
%_mat1 = OpCompositeConstruct %float2x2 %_cola %_colb
%_out_float = OpExtInst %float %glsl450 Determinant %_mat1
)EOTEST",
R"EOTEST(
%_cola = OpCompositeConstruct %float3 %randf_0 %randf_1 %randf_2
%_colb = OpCompositeConstruct %float3 %randf_4 %randf_5 %randf_6
%_colc = OpCompositeConstruct %float3 %randf_8 %randf_9 %randf_10
%_mat1 = OpCompositeConstruct %float3x3 %_cola %_colb %_colc
%_out_float = OpExtInst %float %glsl450 Determinant %_mat1
)EOTEST",
R"EOTEST(
%_cola = OpCompositeConstruct %float4 %randf_0 %randf_1 %randf_2 %randf_3
%_colb = OpCompositeConstruct %float4 %randf_4 %randf_5 %randf_6 %randf_7
%_colc = OpCompositeConstruct %float4 %randf_8 %randf_9 %randf_10 %randf_11
%_cold = OpCompositeConstruct %float4 %randf_12 %randf_13 %randf_14 %randf_15
%_mat1 = OpCompositeConstruct %float4x4 %_cola %_colb %_colc %_cold
%_out_float = OpExtInst %float %glsl450 Determinant %_mat1
)EOTEST",
});
// test matrix inverse, but round the result to avoid needing to lower our global precision
// epsilon
for(int dim = 2; dim <= 4; dim++)
{
std::string test = fmt::format(R"EOTEST(
%_cola = OpCompositeConstruct %float{0} %randf_0 %randf_1 {1} %randf_2 {2} %randf_3
%_colb = OpCompositeConstruct %float{0} %randf_4 %randf_5 {1} %randf_6 {2} %randf_7
%_colc = OpCompositeConstruct %float{0} %randf_8 %randf_9 {1} %randf_10 {2} %randf_11
%_cold = OpCompositeConstruct %float{0} %randf_12 %randf_13 {1} %randf_14 {2} %randf_15
%_mat = OpCompositeConstruct %float{0}x{0} %_cola %_colb {1} %_colc {2} %_cold
%_vec = OpCompositeConstruct %float{0} %randf_16 %randf_17 {1} %randf_18 {2} %randf_19
%_mat0 = OpExtInst %float{0}x{0} %glsl450 MatrixInverse %_mat
)EOTEST",
dim, dim < 3 ? ";" : "", dim < 4 ? ";" : "");
int i = 0;
for(int col = 0; col < dim; col++)
{
for(int row = 0; row < dim; row++)
{
test += fmt::format(R"EOTEST(
%_mat{0}{1}a = OpCompositeExtract %float %_mat{2} {0} {1}
%_mat{0}{1}b = OpFMul %float %_mat{0}{1}a %float_500_0
%_mat{0}{1}c = OpExtInst %float %glsl450 RoundEven %_mat{0}{1}b
%_mat{0}{1}d = OpFDiv %float %_mat{0}{1}c %float_500_0
%_mat{3} = OpCompositeInsert %float{4}x{4} %_mat{0}{1}d %_mat{2} {0} {1}
)EOTEST",
col, row, i, i + 1, dim);
i++;
}
}
test += fmt::format("%_out_float{0} = OpMatrixTimesVector %float{0} %_mat{1} %_vec\n", dim, i);
asm_tests.push_back(test);
}
// test OpVectorShuffle
append_tests({
"%_out_float4 = OpVectorShuffle %float4 %float4_0000 %float4_1234 7 6 0 1",
@@ -1347,6 +1431,7 @@ void main()
%uint4 = OpTypeVector %uint 4
%float2x2 = OpTypeMatrix %float2 2
%float3x3 = OpTypeMatrix %float3 3
%float2x4 = OpTypeMatrix %float2 4
%float4x2 = OpTypeMatrix %float4 2
%float4x4 = OpTypeMatrix %float4 4