diff --git a/renderdoc/driver/shaders/spirv/spirv_debug.cpp b/renderdoc/driver/shaders/spirv/spirv_debug.cpp index ef3d5e6e7..11775c8e4 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug.cpp @@ -1455,6 +1455,21 @@ void ThreadState::StepNext(ShaderDebugState *state, const rdcarray 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); diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp index f18389138..62f9eaae3 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp @@ -24,6 +24,7 @@ #include "spirv_debug.h" #include +#include "maths/matrix.h" namespace rdcspv { @@ -179,6 +180,67 @@ ShaderVariable Pow(ThreadState &state, const rdcarray ¶ms) return var; } +ShaderVariable Determinant(ThreadState &state, const rdcarray ¶ms) +{ + 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 ¶ms) +{ + 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 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); diff --git a/renderdoc/maths/matrix.cpp b/renderdoc/maths/matrix.cpp index 61d21c81e..f3e12bb03 100644 --- a/renderdoc/maths/matrix.cpp +++ b/renderdoc/maths/matrix.cpp @@ -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; +} diff --git a/renderdoc/maths/matrix.h b/renderdoc/maths/matrix.h index 81cbd6196..9a406303a 100644 --- a/renderdoc/maths/matrix.h +++ b/renderdoc/maths/matrix.h @@ -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]; +}; diff --git a/util/test/demos/vk/vk_shader_debug_zoo.cpp b/util/test/demos/vk/vk_shader_debug_zoo.cpp index b222ee15d..7096b5578 100644 --- a/util/test/demos/vk/vk_shader_debug_zoo.cpp +++ b/util/test/demos/vk/vk_shader_debug_zoo.cpp @@ -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