mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-11 21:31:30 +00:00
80c5e2c3f6
It seems gcc-11 does a pretty good job of emulating the instructions (it no longer requires avx2 for 256-bit wide vectors).
685 lines
23 KiB
C
685 lines
23 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "QF/mathlib.h"
|
|
#include "QF/simd/vec4d.h"
|
|
#include "QF/simd/vec4f.h"
|
|
#include "QF/simd/mat4f.h"
|
|
|
|
#define right { 1, 0, 0 }
|
|
#define forward { 0, 1, 0 }
|
|
#define up { 0, 0, 1 }
|
|
#define one { 1, 1, 1, 1 }
|
|
#define half { 0.5, 0.5, 0.5, 0.5 }
|
|
#define zero { 0, 0, 0, 0 }
|
|
#define qident { 0, 0, 0, 1 }
|
|
#define qtest { 0.64, 0.48, 0, 0.6 }
|
|
|
|
#define nright { -1, 0, 0 }
|
|
#define nforward { 0, -1, 0 }
|
|
#define nup { 0, 0, -1 }
|
|
#define none { -1, -1, -1, -1 }
|
|
#define nqident { 0, 0, 0, -1 }
|
|
|
|
#define pi { M_PI, M_PI, M_PI, M_PI } // lots of bits
|
|
#define pmpi { -M_PI, M_PI, -M_PI, M_PI } // lots of bits
|
|
|
|
#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
|
|
|
|
typedef struct {
|
|
int line;
|
|
vec4d_t (*op) (vec4d_t a, vec4d_t b);
|
|
vec4d_t a;
|
|
vec4d_t b;
|
|
vec4d_t expect;
|
|
vec4d_t ulp_errors;
|
|
} vec4d_test_t;
|
|
|
|
typedef struct {
|
|
int line;
|
|
vec4f_t (*op) (vec4f_t a, vec4f_t b);
|
|
vec4f_t a;
|
|
vec4f_t b;
|
|
vec4f_t expect;
|
|
vec4f_t ulp_errors;
|
|
} vec4f_test_t;
|
|
|
|
typedef struct {
|
|
int line;
|
|
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 {
|
|
int line;
|
|
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;
|
|
|
|
typedef struct {
|
|
int line;
|
|
void (*op) (mat4f_t m, vec4f_t q);
|
|
vec4f_t q;
|
|
mat4f_t expect;
|
|
mat4f_t ulp_errors;
|
|
} mq4f_test_t;
|
|
|
|
static vec4d_t tvtruncd (vec4d_t v, vec4d_t ignore)
|
|
{
|
|
return vtrunc4d (v);
|
|
}
|
|
|
|
static vec4d_t tvceild (vec4d_t v, vec4d_t ignore)
|
|
{
|
|
return vceil4d (v);
|
|
}
|
|
|
|
static vec4d_t tvfloord (vec4d_t v, vec4d_t ignore)
|
|
{
|
|
return vfloor4d (v);
|
|
}
|
|
|
|
static vec4d_t tqconjd (vec4d_t v, vec4d_t ignore)
|
|
{
|
|
return qconjd (v);
|
|
}
|
|
|
|
static vec4f_t tvtruncf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return vtrunc4f (v);
|
|
}
|
|
|
|
static vec4f_t tvceilf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return vceil4f (v);
|
|
}
|
|
|
|
static vec4f_t tvfloorf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return vfloor4f (v);
|
|
}
|
|
|
|
static vec4f_t tqconjf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return qconjf (v);
|
|
}
|
|
|
|
static vec4f_t tvabsf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return vabs4f (v);
|
|
}
|
|
|
|
static vec4f_t tvsqrtf (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return vsqrt4f (v);
|
|
}
|
|
|
|
static vec4f_t tmagnitudef (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return magnitudef (v);
|
|
}
|
|
|
|
static vec4f_t tmagnitude3f (vec4f_t v, vec4f_t ignore)
|
|
{
|
|
return magnitude3f (v);
|
|
}
|
|
|
|
#define T(t...) { __LINE__, t }
|
|
|
|
static vec4d_test_t vec4d_tests[] = {
|
|
// 3D dot products
|
|
T(dotd, right, right, one ),
|
|
T(dotd, right, forward, zero ),
|
|
T(dotd, right, up, zero ),
|
|
T(dotd, forward, right, zero ),
|
|
T(dotd, forward, forward, one ),
|
|
T(dotd, forward, up, zero ),
|
|
T(dotd, up, right, zero ),
|
|
T(dotd, up, forward, zero ),
|
|
T(dotd, up, up, one ),
|
|
|
|
// one is 4D, so its self dot product is 4
|
|
T(dotd, one, one, { 4, 4, 4, 4} ),
|
|
T(dotd, one, none, {-4, -4, -4, -4} ),
|
|
|
|
// 3D cross products
|
|
T(crossd, right, right, zero ),
|
|
T(crossd, right, forward, up ),
|
|
T(crossd, right, up, nforward ),
|
|
T(crossd, forward, right, nup ),
|
|
T(crossd, forward, forward, zero ),
|
|
T(crossd, forward, up, right ),
|
|
T(crossd, up, right, forward ),
|
|
T(crossd, up, forward, nright ),
|
|
T(crossd, up, up, zero ),
|
|
// double whammy tests: cross product with an angled vector and
|
|
// ensuring that a 4d vector (non-zero w component) does not affect
|
|
// the result, including the result's w component remaining zero.
|
|
T(crossd, right, one, { 0, -1, 1} ),
|
|
T(crossd, forward, one, { 1, 0, -1} ),
|
|
T(crossd, up, one, {-1, 1, 0} ),
|
|
T(crossd, one, right, { 0, 1, -1} ),
|
|
T(crossd, one, forward, {-1, 0, 1} ),
|
|
T(crossd, one, up, { 1, -1, 0} ),
|
|
// This one fails when optimizing with -mfma (which is why fma is not
|
|
// used): ulp errors in z and w
|
|
T(crossd, qtest, qtest, {0, 0, 0, 0} ),
|
|
|
|
T(qmuld, qident, qident, qident ),
|
|
T(qmuld, qident, right, right ),
|
|
T(qmuld, qident, forward, forward ),
|
|
T(qmuld, qident, up, up ),
|
|
T(qmuld, right, qident, right ),
|
|
T(qmuld, forward, qident, forward ),
|
|
T(qmuld, up, qident, up ),
|
|
T(qmuld, right, right, nqident ),
|
|
T(qmuld, right, forward, up ),
|
|
T(qmuld, right, up, nforward ),
|
|
T(qmuld, forward, right, nup ),
|
|
T(qmuld, forward, forward, nqident ),
|
|
T(qmuld, forward, up, right ),
|
|
T(qmuld, up, right, forward ),
|
|
T(qmuld, up, forward, nright ),
|
|
T(qmuld, up, up, nqident ),
|
|
T(qmuld, one, one, { 2, 2, 2, -2 } ),
|
|
T(qmuld, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } ),
|
|
// This one fails when optimizing with -mfma (which is why fma is not
|
|
// used): ulp error in z
|
|
T(qmuld, qtest, qtest, {0.768, 0.576, 0, -0.28} ),
|
|
|
|
// The one vector is not unit (magnitude 2), so using it as a rotation
|
|
// quaternion results in scaling by 4. However, it still has the effect
|
|
// of rotating 120 degrees around the axis equidistant from the three
|
|
// orthogonal axes such that x->y->z->x
|
|
T(qvmuld, one, right, { 0, 4, 0, 0 } ),
|
|
T(qvmuld, one, forward, { 0, 0, 4, 0 } ),
|
|
T(qvmuld, one, up, { 4, 0, 0, 0 } ),
|
|
T(qvmuld, one, {1,1,1,0}, { 4, 4, 4, 0 } ),
|
|
T(qvmuld, one, one, { 4, 4, 4, -2 } ),
|
|
// inverse rotation, so x->z->y->x
|
|
T(vqmuld, right, one, { 0, 0, 4, 0 } ),
|
|
T(vqmuld, forward, one, { 4, 0, 0, 0 } ),
|
|
T(vqmuld, up, one, { 0, 4, 0, 0 } ),
|
|
T(vqmuld, {1,1,1,0}, one, { 4, 4, 4, 0 } ),
|
|
T(vqmuld, one, one, { 4, 4, 4, -2 } ),
|
|
// The half vector is unit.
|
|
T(qvmuld, half, right, forward ),
|
|
T(qvmuld, half, forward, up ),
|
|
T(qvmuld, half, up, right ),
|
|
T(qvmuld, half, {1,1,1,0}, { 1, 1, 1, 0 } ),
|
|
// inverse
|
|
T(vqmuld, right, half, up ),
|
|
T(vqmuld, forward, half, right ),
|
|
T(vqmuld, up, half, forward ),
|
|
T(vqmuld, {1,1,1,0}, half, { 1, 1, 1, 0 } ),
|
|
// one is a 4D vector and qvmuld is meant for 3D vectors. However, it
|
|
// seems that the vector's w has no effect on the 3d portion of the
|
|
// result, but the result's w is cosine of the full rotation angle
|
|
// scaled by quaternion magnitude and vector w
|
|
T(qvmuld, half, one, { 1, 1, 1, -0.5 } ),
|
|
T(qvmuld, half, {2,2,2,2}, { 2, 2, 2, -1 } ),
|
|
T(qvmuld, qtest, right, {0.5392, 0.6144, -0.576, 0} ),
|
|
T(qvmuld, qtest, forward, {0.6144, 0.1808, 0.768, 0},
|
|
{0, -2.7e-17, 0, 0} ),
|
|
T(qvmuld, qtest, up, {0.576, -0.768, -0.28, 0} ),
|
|
// inverse
|
|
T(vqmuld, one, half, { 1, 1, 1, -0.5 } ),
|
|
T(vqmuld, {2,2,2,2}, half, { 2, 2, 2, -1 } ),
|
|
T(vqmuld, right, qtest, {0.5392, 0.6144, 0.576, 0} ),
|
|
T(vqmuld, forward, qtest, {0.6144, 0.1808, -0.768, 0},
|
|
{0, -2.7e-17, 0, 0} ),
|
|
T(vqmuld, up, qtest, {-0.576, 0.768, -0.28, 0} ),
|
|
|
|
T(qrotd, right, right, qident ),
|
|
T(qrotd, right, forward, { 0, 0, s05, s05 },
|
|
{0, 0, -1.1e-16, 0} ),
|
|
T(qrotd, right, up, { 0, -s05, 0, s05 },
|
|
{0, 1.1e-16, 0, 0} ),
|
|
T(qrotd, forward, right, { 0, 0, -s05, s05 },
|
|
{0, 0, 1.1e-16, 0} ),
|
|
T(qrotd, forward, forward, qident ),
|
|
T(qrotd, forward, up, { s05, 0, 0, s05 },
|
|
{-1.1e-16, 0, 0, 0} ),
|
|
T(qrotd, up, right, { 0, s05, 0, s05 },
|
|
{0, -1.1e-16, 0, 0} ),
|
|
T(qrotd, up, forward, { -s05, 0, 0, s05 },
|
|
{ 1.1e-16, 0, 0, 0} ),
|
|
T(qrotd, up, up, qident ),
|
|
|
|
T(tvtruncd, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } ),
|
|
T(tvceild, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } ),
|
|
T(tvfloord, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } ),
|
|
T(tqconjd, one, {}, { -1, -1, -1, 1 } ),
|
|
};
|
|
#define num_vec4d_tests (sizeof (vec4d_tests) / (sizeof (vec4d_tests[0])))
|
|
|
|
static vec4f_test_t vec4f_tests[] = {
|
|
// 3D dot products
|
|
T(dotf, right, right, one ),
|
|
T(dotf, right, forward, zero ),
|
|
T(dotf, right, up, zero ),
|
|
T(dotf, forward, right, zero ),
|
|
T(dotf, forward, forward, one ),
|
|
T(dotf, forward, up, zero ),
|
|
T(dotf, up, right, zero ),
|
|
T(dotf, up, forward, zero ),
|
|
T(dotf, up, up, one ),
|
|
|
|
// one is 4D, so its self dot product is 4
|
|
T(dotf, one, one, { 4, 4, 4, 4} ),
|
|
T(dotf, one, none, {-4, -4, -4, -4} ),
|
|
|
|
// 3D cross products
|
|
T(crossf, right, right, zero ),
|
|
T(crossf, right, forward, up ),
|
|
T(crossf, right, up, nforward ),
|
|
T(crossf, forward, right, nup ),
|
|
T(crossf, forward, forward, zero ),
|
|
T(crossf, forward, up, right ),
|
|
T(crossf, up, right, forward ),
|
|
T(crossf, up, forward, nright ),
|
|
T(crossf, up, up, zero ),
|
|
// double whammy tests: cross product with an angled vector and
|
|
// ensuring that a 4d vector (non-zero w component) does not affect
|
|
// the result, including the result's w component remaining zero.
|
|
T(crossf, right, one, { 0, -1, 1} ),
|
|
T(crossf, forward, one, { 1, 0, -1} ),
|
|
T(crossf, up, one, {-1, 1, 0} ),
|
|
T(crossf, one, right, { 0, 1, -1} ),
|
|
T(crossf, one, forward, {-1, 0, 1} ),
|
|
T(crossf, one, up, { 1, -1, 0} ),
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
// when not optimizing and SSE is not available (but ok when
|
|
// optimizing)
|
|
T(crossf, qtest, qtest, {0, 0, -1.47819534e-09, 0} ),
|
|
#else
|
|
T(crossf, qtest, qtest, {0, 0, 0, 0} ),
|
|
#endif
|
|
|
|
T(qmulf, qident, qident, qident ),
|
|
T(qmulf, qident, right, right ),
|
|
T(qmulf, qident, forward, forward ),
|
|
T(qmulf, qident, up, up ),
|
|
T(qmulf, right, qident, right ),
|
|
T(qmulf, forward, qident, forward ),
|
|
T(qmulf, up, qident, up ),
|
|
T(qmulf, right, right, nqident ),
|
|
T(qmulf, right, forward, up ),
|
|
T(qmulf, right, up, nforward ),
|
|
T(qmulf, forward, right, nup ),
|
|
T(qmulf, forward, forward, nqident ),
|
|
T(qmulf, forward, up, right ),
|
|
T(qmulf, up, right, forward ),
|
|
T(qmulf, up, forward, nright ),
|
|
T(qmulf, up, up, nqident ),
|
|
T(qmulf, one, one, { 2, 2, 2, -2 } ),
|
|
T(qmulf, one, { 2, 2, 2, -2 }, { 0, 0, 0, -8 } ),
|
|
T(qmulf, qtest, qtest, {0.768, 0.576, 0, -0.28},
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
// when not optimizing and SSE is not available (but ok when
|
|
// optimizing)
|
|
{0, 6e-8, -1.47819534e-09, 3e-8}
|
|
#elif !defined( __SSE__)
|
|
{0, 6e-8, 0, 6e-8}
|
|
#else
|
|
{0, 6e-8, 0, 3e-8}
|
|
#endif
|
|
),
|
|
|
|
// The one vector is not unit (magnitude 2), so using it as a rotation
|
|
// quaternion results in scaling by 4. However, it still has the effect
|
|
// of rotating 120 degrees around the axis equidistant from the three
|
|
// orthogonal axes such that x->y->z->x
|
|
T(qvmulf, one, right, { 0, 4, 0, 0 } ),
|
|
T(qvmulf, one, forward, { 0, 0, 4, 0 } ),
|
|
T(qvmulf, one, up, { 4, 0, 0, 0 } ),
|
|
T(qvmulf, one, {1,1,1,0}, { 4, 4, 4, 0 } ),
|
|
T(qvmulf, one, one, { 4, 4, 4, -2 } ),
|
|
// inverse rotation, so x->z->y->x
|
|
T(vqmulf, right, one, { 0, 0, 4, 0 } ),
|
|
T(vqmulf, forward, one, { 4, 0, 0, 0 } ),
|
|
T(vqmulf, up, one, { 0, 4, 0, 0 } ),
|
|
T(vqmulf, {1,1,1,0}, one, { 4, 4, 4, 0 } ),
|
|
T(vqmulf, one, one, { 4, 4, 4, -2 } ),
|
|
//
|
|
T(qvmulf, qtest, right, {0.5392, 0.6144, -0.576, 0},
|
|
{0, -5.9e-8, -6e-8, 0} ),
|
|
T(qvmulf, qtest, forward, {0.6144, 0.1808, 0.768, 0},
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
{-5.9e-8, 0, 0, 0}
|
|
#elif !defined(__SSE__)
|
|
{-5.9e-8, 3e-8, 0, 0}
|
|
#else
|
|
{-5.9e-8, 1.5e-8, 0, 0}
|
|
#endif
|
|
),
|
|
T(qvmulf, qtest, up, {0.576, -0.768, -0.28, 0},
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
{6e-8, 0, 3e-8, 0}
|
|
#elif !defined(__SSE__)
|
|
{6e-8, 0, 6e-8, 0}
|
|
#else
|
|
{6e-8, 0, 3e-8, 0}
|
|
#endif
|
|
),
|
|
T(vqmulf, right, qtest, {0.5392, 0.6144, 0.576, 0},
|
|
{0, -5.9e-8, 5.9e-8, 0} ),
|
|
T(vqmulf, forward, qtest, {0.6144, 0.1808, -0.768, 0},
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
{-5.9e-8, 0, 0, 0}
|
|
#elif !defined(__SSE__)
|
|
{-5.9e-8, 3e-8, 0, 0}
|
|
#else
|
|
{-5.9e-8, 1.5e-8, 0, 0}
|
|
#endif
|
|
),
|
|
T(vqmulf, up, qtest, {-0.576, 0.768, -0.28, 0},
|
|
#if !defined(__SSE__) && !defined(__OPTIMIZE__)
|
|
{-5.9e-8, 0, 3e-8, 0}
|
|
#elif !defined(__SSE__)
|
|
{-5.9e-8, 0, 6e-8, 0}
|
|
#else
|
|
{-5.9e-8, 0, 3e-8, 0}
|
|
#endif
|
|
),
|
|
|
|
T(qrotf, right, right, qident ),
|
|
T(qrotf, right, forward, { 0, 0, s05, s05 } ),
|
|
T(qrotf, right, up, { 0, -s05, 0, s05 } ),
|
|
T(qrotf, forward, right, { 0, 0, -s05, s05 } ),
|
|
T(qrotf, forward, forward, qident ),
|
|
T(qrotf, forward, up, { s05, 0, 0, s05 } ),
|
|
T(qrotf, up, right, { 0, s05, 0, s05 } ),
|
|
T(qrotf, up, forward, { -s05, 0, 0, s05 } ),
|
|
T(qrotf, up, up, qident ),
|
|
|
|
T(tvabsf, pmpi, {}, pi ),
|
|
T(tvsqrtf, { 1, 4, 9, 16}, {}, {1, 2, 3, 4} ),
|
|
T(tvtruncf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -1, -2 } ),
|
|
T(tvceilf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 2, 3, -1, -2 } ),
|
|
T(tvfloorf, { 1.1, 2.9, -1.1, -2.9 }, {}, { 1, 2, -2, -3 } ),
|
|
T(tqconjf, one, {}, { -1, -1, -1, 1 } ),
|
|
T(tmagnitudef, { 3, 4, 12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, 4, 12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, 4, -12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, 4, -12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, -4, 12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, -4, 12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, -4, -12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { 3, -4, -12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, 4, 12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, 4, 12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, 4, -12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, 4, -12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, -4, 12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, -4, 12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, -4, -12, 84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitudef, { -3, -4, -12, -84}, {}, {85, 85, 85, 85} ),
|
|
T(tmagnitude3f, { -3, -4, -12, -84}, {}, {13, 13, 13, 13} ),
|
|
};
|
|
#define num_vec4f_tests (sizeof (vec4f_tests) / (sizeof (vec4f_tests[0])))
|
|
|
|
static mat4f_test_t mat4f_tests[] = {
|
|
T(mmulf, identity, identity, identity ),
|
|
T(mmulf, rotate120, identity, rotate120 ),
|
|
T(mmulf, identity, rotate120, rotate120 ),
|
|
T(mmulf, rotate120, rotate120, rotate240 ),
|
|
T(mmulf, rotate120, rotate240, identity ),
|
|
T(mmulf, rotate240, rotate120, identity ),
|
|
};
|
|
#define num_mat4f_tests (sizeof (mat4f_tests) / (sizeof (mat4f_tests[0])))
|
|
|
|
static mv4f_test_t mv4f_tests[] = {
|
|
T(mvmulf, identity, { 1, 0, 0, 0 }, { 1, 0, 0, 0 } ),
|
|
T(mvmulf, identity, { 0, 1, 0, 0 }, { 0, 1, 0, 0 } ),
|
|
T(mvmulf, identity, { 0, 0, 1, 0 }, { 0, 0, 1, 0 } ),
|
|
T(mvmulf, identity, { 0, 0, 0, 1 }, { 0, 0, 0, 1 } ),
|
|
T(mvmulf, rotate120, { 1, 2, 3, 4 }, { 3, 1, 2, 4 } ),
|
|
T(mvmulf, rotate240, { 1, 2, 3, 4 }, { 2, 3, 1, 4 } ),
|
|
};
|
|
#define num_mv4f_tests (sizeof (mv4f_tests) / (sizeof (mv4f_tests[0])))
|
|
|
|
// expect filled in using non-simd QuatToMatrix (has its own tests)
|
|
static mq4f_test_t mq4f_tests[] = {
|
|
T(mat4fquat, { 0, 0, 0, 1 } ),
|
|
T(mat4fquat, { 0.5, 0.5, 0.5, 0.5 } ),
|
|
T(mat4fquat, { 0.5, 0.5, -0.5, 0.5 } ),
|
|
T(mat4fquat, { 0.5, -0.5, 0.5, 0.5 } ),
|
|
T(mat4fquat, { 0.5, -0.5, -0.5, 0.5 } ),
|
|
T(mat4fquat, { -0.5, 0.5, 0.5, 0.5 } ),
|
|
T(mat4fquat, { -0.5, 0.5, -0.5, 0.5 } ),
|
|
T(mat4fquat, { -0.5, -0.5, 0.5, 0.5 } ),
|
|
T(mat4fquat, { -0.5, -0.5, -0.5, 0.5 } ),
|
|
};
|
|
#define num_mq4f_tests (sizeof (mq4f_tests) / (sizeof (mq4f_tests[0])))
|
|
|
|
static int
|
|
run_vec4d_tests (void)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (size_t i = 0; i < num_vec4d_tests; i++) {
|
|
__auto_type test = &vec4d_tests[i];
|
|
vec4d_t result = test->op (test->a, test->b);
|
|
vec4d_t expect = test->expect + test->ulp_errors;
|
|
vec4l_t res = result != expect;
|
|
if (res[0] || res[1] || res[2] || res[3]) {
|
|
ret |= 1;
|
|
printf ("\nrun_vec4d_tests %zd, line %d\n", i, test->line);
|
|
printf ("a: " VEC4D_FMT "\n", VEC4_EXP(test->a));
|
|
printf ("b: " VEC4D_FMT "\n", VEC4_EXP(test->b));
|
|
printf ("r: " VEC4D_FMT "\n", VEC4_EXP(result));
|
|
printf ("t: " VEC4L_FMT "\n", VEC4_EXP(res));
|
|
printf ("E: " VEC4D_FMT "\n", VEC4_EXP(expect));
|
|
printf ("e: " VEC4D_FMT "\n", VEC4_EXP(test->expect));
|
|
printf ("u: " VEC4D_FMT "\n", VEC4_EXP(test->ulp_errors));
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
run_vec4f_tests (void)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (size_t i = 0; i < num_vec4f_tests; i++) {
|
|
__auto_type test = &vec4f_tests[i];
|
|
vec4f_t result = test->op (test->a, test->b);
|
|
vec4f_t expect = test->expect + test->ulp_errors;
|
|
vec4i_t res = (vec4i_t) result != (vec4i_t) expect;
|
|
if (res[0] || res[1] || res[2] || res[3]) {
|
|
ret |= 1;
|
|
printf ("\nrun_vec4f_tests %zd, line %d\n", i, test->line);
|
|
printf ("a: " VEC4F_FMT "\n", VEC4_EXP(test->a));
|
|
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;
|
|
}
|
|
|
|
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, line %d\n", i, test->line);
|
|
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_mv4f_tests %zd, line %d\n", i, test->line);
|
|
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;
|
|
}
|
|
|
|
static int
|
|
run_mq4f_tests (void)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (size_t i = 0; i < num_mq4f_tests; i++) {
|
|
__auto_type test = &mq4f_tests[i];
|
|
quat_t q;
|
|
vec_t m[16];
|
|
memcpy (q, &test->q, sizeof (quat_t));
|
|
QuatToMatrix (q, m, 1, 1);
|
|
memcpy (&test->expect, m, sizeof (mat4f_t));
|
|
}
|
|
for (size_t i = 0; i < num_mq4f_tests; i++) {
|
|
__auto_type test = &mq4f_tests[i];
|
|
mat4f_t result;
|
|
mat4f_t expect;
|
|
mat4i_t res = {};
|
|
|
|
test->op (result, test->q);
|
|
maddf (expect, test->expect, test->ulp_errors);
|
|
memcpy (expect, (void *) &test->expect, sizeof (mat4f_t));
|
|
|
|
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_mq4f_tests %zd, line %d\n", i, test->line);
|
|
printf ("q: " VEC4F_FMT "\n", VEC4_EXP(test->q));
|
|
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;
|
|
}
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
int ret = 0;
|
|
ret |= run_vec4d_tests ();
|
|
ret |= run_vec4f_tests ();
|
|
ret |= run_mat4f_tests ();
|
|
ret |= run_mv4f_tests ();
|
|
ret |= run_mq4f_tests ();
|
|
return ret;
|
|
}
|