mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-30 08:00:51 +00:00
[util] Add simd 4x4 matrix functions
Currently just add, subtract, multiply (m m and m v).
This commit is contained in:
parent
9617bbef97
commit
45c0255643
4 changed files with 270 additions and 2 deletions
123
include/QF/simd/mat4f.h
Normal file
123
include/QF/simd/mat4f.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
QF/simd/mat4f.h
|
||||||
|
|
||||||
|
Matrix functions for mat4f_t (ie, float precision)
|
||||||
|
|
||||||
|
Copyright (C) 2021 Bill Currie <bill@taniwha.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to:
|
||||||
|
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
59 Temple Place - Suite 330
|
||||||
|
Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __QF_simd_mat4f_h
|
||||||
|
#define __QF_simd_mat4f_h
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
#include "QF/simd/types.h"
|
||||||
|
|
||||||
|
GNU89INLINE inline void maddf (mat4f_t c, const mat4f_t a, const mat4f_t b);
|
||||||
|
GNU89INLINE inline void msubf (mat4f_t c, const mat4f_t a, const mat4f_t b);
|
||||||
|
GNU89INLINE inline void mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b);
|
||||||
|
GNU89INLINE inline vec4f_t mvmulf (const mat4f_t m, vec4f_t v) __attribute__((const));
|
||||||
|
GNU89INLINE inline vec4f_t m3vmulf (const mat4f_t m, vec4f_t v) __attribute__((const));
|
||||||
|
GNU89INLINE inline void mat4fidentity (mat4f_t m);
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
maddf (mat4f_t c, const mat4f_t a, const mat4f_t b)
|
||||||
|
{
|
||||||
|
c[0] = a[0] + b[0];
|
||||||
|
c[1] = a[1] + b[1];
|
||||||
|
c[2] = a[2] + b[2];
|
||||||
|
c[3] = a[3] + b[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
msubf (mat4f_t c, const mat4f_t a, const mat4f_t b)
|
||||||
|
{
|
||||||
|
c[0] = a[0] - b[0];
|
||||||
|
c[1] = a[1] - b[1];
|
||||||
|
c[2] = a[2] - b[2];
|
||||||
|
c[3] = a[3] - b[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
mmulf (mat4f_t c, const mat4f_t a, const mat4f_t b)
|
||||||
|
{
|
||||||
|
c[0] = a[0] * b[0][0] + a[1] * b[0][1] + a[2] * b[0][2] + a[3] * b[0][3];
|
||||||
|
c[1] = a[0] * b[1][0] + a[1] * b[1][1] + a[2] * b[1][2] + a[3] * b[1][3];
|
||||||
|
c[2] = a[0] * b[2][0] + a[1] * b[2][1] + a[2] * b[2][2] + a[3] * b[2][3];
|
||||||
|
c[3] = a[0] * b[3][0] + a[1] * b[3][1] + a[2] * b[3][2] + a[3] * b[3][3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
vec4f_t
|
||||||
|
mvmulf (const mat4f_t m, vec4f_t v)
|
||||||
|
{
|
||||||
|
return m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3] * v[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
vec4f_t
|
||||||
|
m3vmulf (const mat4f_t m, vec4f_t v)
|
||||||
|
{
|
||||||
|
vec4f_t w;
|
||||||
|
w = m[0] * v[0] + m[1] * v[1] + m[2] * v[2];
|
||||||
|
w[3] = 1;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef IMPLEMENT_MAT4F_Funcs
|
||||||
|
GNU89INLINE inline
|
||||||
|
#else
|
||||||
|
VISIBLE
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
mat4fidentity (mat4f_t m)
|
||||||
|
{
|
||||||
|
m[0] = (vec4f_t) { 1, 0, 0, 0 };
|
||||||
|
m[1] = (vec4f_t) { 0, 1, 0, 0 };
|
||||||
|
m[2] = (vec4f_t) { 0, 0, 1, 0 };
|
||||||
|
m[3] = (vec4f_t) { 0, 0, 0, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif//__QF_simd_mat4f_h
|
|
@ -82,4 +82,8 @@ VEC_TYPE (int, vec4i_t);
|
||||||
#define VEC4I_FMT "[%d, %d, %d, %d]"
|
#define VEC4I_FMT "[%d, %d, %d, %d]"
|
||||||
#define VEC4_EXP(v) (v)[0], (v)[1], (v)[2], (v)[3]
|
#define VEC4_EXP(v) (v)[0], (v)[1], (v)[2], (v)[3]
|
||||||
|
|
||||||
|
#define MAT4_ROW(m, r) (m)[0][r], (m)[1][r], (m)[2][r], (m)[3][r]
|
||||||
|
|
||||||
|
typedef vec4f_t mat4f_t[4];
|
||||||
|
typedef vec4i_t mat4i_t[4];
|
||||||
#endif//__QF_simd_types_h
|
#endif//__QF_simd_types_h
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
|
|
||||||
#define IMPLEMENT_VEC4F_Funcs
|
#define IMPLEMENT_VEC4F_Funcs
|
||||||
#define IMPLEMENT_VEC4D_Funcs
|
#define IMPLEMENT_VEC4D_Funcs
|
||||||
|
#define IMPLEMENT_MAT4F_Funcs
|
||||||
|
|
||||||
#include "QF/simd/vec4d.h"
|
#include "QF/simd/vec4d.h"
|
||||||
#include "QF/simd/vec4f.h"
|
#include "QF/simd/vec4f.h"
|
||||||
|
#include "QF/simd/mat4f.h"
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "QF/simd/vec4d.h"
|
#include "QF/simd/vec4d.h"
|
||||||
#include "QF/simd/vec4f.h"
|
#include "QF/simd/vec4f.h"
|
||||||
|
#include "QF/simd/mat4f.h"
|
||||||
|
|
||||||
#define right { 1, 0, 0 }
|
#define right { 1, 0, 0 }
|
||||||
#define forward { 0, 1, 0 }
|
#define forward { 0, 1, 0 }
|
||||||
|
@ -25,6 +26,22 @@
|
||||||
#define none { -1, -1, -1, -1 }
|
#define none { -1, -1, -1, -1 }
|
||||||
#define nqident { 0, 0, 0, -1 }
|
#define nqident { 0, 0, 0, -1 }
|
||||||
|
|
||||||
|
#define identity \
|
||||||
|
{ { 1, 0, 0, 0 }, \
|
||||||
|
{ 0, 1, 0, 0 }, \
|
||||||
|
{ 0, 0, 1, 0 }, \
|
||||||
|
{ 0, 0, 0, 1 } }
|
||||||
|
#define rotate120 \
|
||||||
|
{ { 0, 1, 0, 0 }, \
|
||||||
|
{ 0, 0, 1, 0 }, \
|
||||||
|
{ 1, 0, 0, 0 }, \
|
||||||
|
{ 0, 0, 0, 1 } }
|
||||||
|
#define rotate240 \
|
||||||
|
{ { 0, 0, 1, 0 }, \
|
||||||
|
{ 1, 0, 0, 0 }, \
|
||||||
|
{ 0, 1, 0, 0 }, \
|
||||||
|
{ 0, 0, 0, 1 } }
|
||||||
|
|
||||||
#define s05 0.70710678118654757
|
#define s05 0.70710678118654757
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -43,6 +60,22 @@ typedef struct {
|
||||||
vec4f_t ulp_errors;
|
vec4f_t ulp_errors;
|
||||||
} vec4f_test_t;
|
} vec4f_test_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*op) (mat4f_t c, const mat4f_t a, const mat4f_t b);
|
||||||
|
mat4f_t a;
|
||||||
|
mat4f_t b;
|
||||||
|
mat4f_t expect;
|
||||||
|
mat4f_t ulp_errors;
|
||||||
|
} mat4f_test_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec4f_t (*op) (const mat4f_t a, vec4f_t b);
|
||||||
|
mat4f_t a;
|
||||||
|
vec4f_t b;
|
||||||
|
vec4f_t expect;
|
||||||
|
vec4f_t ulp_errors;
|
||||||
|
} mv4f_test_t;
|
||||||
|
|
||||||
static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore)
|
static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore)
|
||||||
{
|
{
|
||||||
return vtruncd (v);
|
return vtruncd (v);
|
||||||
|
@ -314,6 +347,26 @@ static vec4f_test_t vec4f_tests[] = {
|
||||||
};
|
};
|
||||||
#define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0])))
|
#define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0])))
|
||||||
|
|
||||||
|
static mat4f_test_t mat4f_tests[] = {
|
||||||
|
{ mmulf, identity, identity, identity },
|
||||||
|
{ mmulf, rotate120, identity, rotate120 },
|
||||||
|
{ mmulf, identity, rotate120, rotate120 },
|
||||||
|
{ mmulf, rotate120, rotate120, rotate240 },
|
||||||
|
{ mmulf, rotate120, rotate240, identity },
|
||||||
|
{ mmulf, rotate240, rotate120, identity },
|
||||||
|
};
|
||||||
|
#define num_mat4f_tests (sizeof (mat4f_tests) / (sizeof (mat4f_tests[0])))
|
||||||
|
|
||||||
|
static mv4f_test_t mv4f_tests[] = {
|
||||||
|
{ mvmulf, identity, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } },
|
||||||
|
{ mvmulf, identity, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } },
|
||||||
|
{ mvmulf, identity, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } },
|
||||||
|
{ mvmulf, identity, { 0, 0, 0, 1 }, { 0, 0, 0, 1 } },
|
||||||
|
{ mvmulf, rotate120, { 1, 2, 3, 4 }, { 3, 1, 2, 4 } },
|
||||||
|
{ mvmulf, rotate240, { 1, 2, 3, 4 }, { 2, 3, 1, 4 } },
|
||||||
|
};
|
||||||
|
#define num_mv4f_tests (sizeof (mv4f_tests) / (sizeof (mv4f_tests[0])))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
run_vec4d_tests (void)
|
run_vec4d_tests (void)
|
||||||
{
|
{
|
||||||
|
@ -326,7 +379,7 @@ run_vec4d_tests (void)
|
||||||
vec4l_t res = result != expect;
|
vec4l_t res = result != expect;
|
||||||
if (res[0] || res[1] || res[2] || res[3]) {
|
if (res[0] || res[1] || res[2] || res[3]) {
|
||||||
ret |= 1;
|
ret |= 1;
|
||||||
printf ("\nrun_vec4d_tests\n");
|
printf ("\nrun_vec4d_tests %zd\n", i);
|
||||||
printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a));
|
printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a));
|
||||||
printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b));
|
printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b));
|
||||||
printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result));
|
printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result));
|
||||||
|
@ -351,7 +404,7 @@ run_vec4f_tests (void)
|
||||||
vec4i_t res = result != expect;
|
vec4i_t res = result != expect;
|
||||||
if (res[0] || res[1] || res[2] || res[3]) {
|
if (res[0] || res[1] || res[2] || res[3]) {
|
||||||
ret |= 1;
|
ret |= 1;
|
||||||
printf ("\nrun_vec4f_tests\n");
|
printf ("\nrun_vec4f_tests %zd\n", i);
|
||||||
printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a));
|
printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a));
|
||||||
printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b));
|
printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b));
|
||||||
printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result));
|
printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result));
|
||||||
|
@ -364,11 +417,97 @@ run_vec4f_tests (void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run_mat4f_tests (void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_mat4f_tests; i++) {
|
||||||
|
__auto_type test = &mat4f_tests[i];
|
||||||
|
mat4f_t result;
|
||||||
|
mat4f_t expect;
|
||||||
|
mat4i_t res = {};
|
||||||
|
|
||||||
|
test->op (result, test->a, test->b);
|
||||||
|
maddf (expect, test->expect, test->ulp_errors);
|
||||||
|
|
||||||
|
int fail = 0;
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
res[j] = result[j] != expect[j];
|
||||||
|
fail |= res[j][0] || res[j][1] || res[j][2] || res[j][3];
|
||||||
|
}
|
||||||
|
if (fail) {
|
||||||
|
ret |= 1;
|
||||||
|
printf ("\nrun_mat4f_tests %zd\n", i);
|
||||||
|
printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3));
|
||||||
|
printf ("b: " VEC4F_FMT "\n", MAT4_ROW(test->b, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->b, 3));
|
||||||
|
printf ("r: " VEC4F_FMT "\n", MAT4_ROW(result, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(result, 3));
|
||||||
|
printf ("t: " VEC4I_FMT "\n", MAT4_ROW(res, 0));
|
||||||
|
printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 1));
|
||||||
|
printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 2));
|
||||||
|
printf (" " VEC4I_FMT "\n", MAT4_ROW(res, 3));
|
||||||
|
printf ("E: " VEC4F_FMT "\n", MAT4_ROW(expect, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(expect, 3));
|
||||||
|
printf ("e: " VEC4F_FMT "\n", MAT4_ROW(test->expect, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->expect, 3));
|
||||||
|
printf ("u: " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->ulp_errors, 3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run_mv4f_tests (void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_mv4f_tests; i++) {
|
||||||
|
__auto_type test = &mv4f_tests[i];
|
||||||
|
vec4f_t result = test->op (test->a, test->b);
|
||||||
|
vec4f_t expect = test->expect + test->ulp_errors;
|
||||||
|
vec4i_t res = result != expect;
|
||||||
|
|
||||||
|
if (res[0] || res[1] || res[2] || res[3]) {
|
||||||
|
ret |= 1;
|
||||||
|
printf ("\nrun_mat4f_tests %zd\n", i);
|
||||||
|
printf ("a: " VEC4F_FMT "\n", MAT4_ROW(test->a, 0));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 1));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 2));
|
||||||
|
printf (" " VEC4F_FMT "\n", MAT4_ROW(test->a, 3));
|
||||||
|
printf ("b: " VEC4F_FMT "\n", VEC4_EXP(test->b));
|
||||||
|
printf ("r: " VEC4F_FMT "\n", VEC4_EXP(result));
|
||||||
|
printf ("t: " VEC4I_FMT "\n", VEC4_EXP(res));
|
||||||
|
printf ("E: " VEC4F_FMT "\n", VEC4_EXP(expect));
|
||||||
|
printf ("e: " VEC4F_FMT "\n", VEC4_EXP(test->expect));
|
||||||
|
printf ("u: " VEC4F_FMT "\n", VEC4_EXP(test->ulp_errors));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (void)
|
main (void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
ret |= run_vec4d_tests ();
|
ret |= run_vec4d_tests ();
|
||||||
ret |= run_vec4f_tests ();
|
ret |= run_vec4f_tests ();
|
||||||
|
ret |= run_mat4f_tests ();
|
||||||
|
ret |= run_mv4f_tests ();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue