mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 09:39:33 +01:00
Merge pull request #19925 from hrydgard/cross-simd-no-simd
Add no-SIMD fallback for CrossSIMD
This commit is contained in:
8 files changed
+569
-20
No files matched your search
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(lldb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "",
|
||||
"osx": {
|
||||
"program": "${workspaceFolder}/build/PPSSPPSDL.app/Contents/MacOS/PPSSPPSDL"
|
||||
},
|
||||
"linux": {
|
||||
"program": "${workspaceRoot}/build/PPSSPPSDL"
|
||||
},
|
||||
"args": [],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "lldb"
|
||||
}
|
||||
]
|
||||
}
|
||||
+523
-8
@@ -185,6 +185,19 @@ struct Vec4F32 {
|
||||
|
||||
static Vec4F32 Load(const float *src) { return Vec4F32{ _mm_loadu_ps(src) }; }
|
||||
static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ _mm_load_ps(src) }; }
|
||||
static Vec4F32 LoadS8Norm(const int8_t *src) {
|
||||
__m128i value = _mm_set1_epi32(*((uint32_t *)src));
|
||||
__m128i value32 = _mm_unpacklo_epi16(_mm_unpacklo_epi8(value, value), value);
|
||||
// Sign extension. A bit ugly without SSE4.
|
||||
value32 = _mm_srai_epi32(value32, 24);
|
||||
return Vec4F32 { _mm_mul_ps(_mm_cvtepi32_ps(value32), _mm_set1_ps(1.0f / 128.0f)) };
|
||||
}
|
||||
static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f
|
||||
__m128i bits = _mm_castpd_si128(_mm_load_sd((const double *)src));
|
||||
// Sign extension. A bit ugly without SSE4.
|
||||
bits = _mm_srai_epi32(_mm_unpacklo_epi16(bits, bits), 16);
|
||||
return Vec4F32 { _mm_mul_ps(_mm_cvtepi32_ps(bits), _mm_set1_ps(1.0f / 32768.0f)) };
|
||||
}
|
||||
void Store(float *dst) { _mm_storeu_ps(dst, v); }
|
||||
void Store2(float *dst) { _mm_storel_epi64((__m128i *)dst, _mm_castps_si128(v)); }
|
||||
void StoreAligned (float *dst) { _mm_store_ps(dst, v); }
|
||||
@@ -194,8 +207,6 @@ struct Vec4F32 {
|
||||
_mm_store_ss(dst + 2, _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2)));
|
||||
}
|
||||
|
||||
static Vec4F32 LoadVec2(const float *src) { return Vec4F32{ _mm_castsi128_ps(_mm_loadl_epi64((const __m128i *)src)) }; }
|
||||
|
||||
static Vec4F32 LoadConvertS16(const int16_t *src) { // Note: will load 8 bytes
|
||||
__m128i value = _mm_loadl_epi64((const __m128i *)src);
|
||||
// 16-bit to 32-bit, use the upper words and an arithmetic shift right to sign extend
|
||||
@@ -237,7 +248,7 @@ struct Vec4F32 {
|
||||
Vec4F32 RecipApprox() const { return Vec4F32{ _mm_rcp_ps(v) }; }
|
||||
Vec4F32 Recip() const { return Vec4F32{ _mm_div_ps(_mm_set1_ps(1.0f), v) }; }
|
||||
|
||||
Vec4F32 Clamp(float lower, float higher) {
|
||||
Vec4F32 Clamp(float lower, float higher) const {
|
||||
return Vec4F32{
|
||||
_mm_min_ps(_mm_max_ps(v, _mm_set1_ps(lower)), _mm_set1_ps(higher))
|
||||
};
|
||||
@@ -506,6 +517,14 @@ struct Vec4F32 {
|
||||
static Vec4F32 Splat(float lane) { return Vec4F32{ vdupq_n_f32(lane) }; }
|
||||
|
||||
static Vec4F32 Load(const float *src) { return Vec4F32{ vld1q_f32(src) }; }
|
||||
static Vec4F32 LoadS8Norm(const int8_t *src) {
|
||||
const int8x8_t value = (int8x8_t)vdup_n_u32(*((uint32_t *)src));
|
||||
const int16x8_t value16 = vmovl_s8(value);
|
||||
return Vec4F32 { vcvtq_n_f32_s32(vmovl_s16(vget_low_u16(value16)), 7) };
|
||||
}
|
||||
static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f
|
||||
return Vec4F32 { vcvtq_n_f32_s32(vmovl_s16(vld1_s16(src)), 15) };
|
||||
}
|
||||
static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ vld1q_f32(src) }; }
|
||||
void Store(float *dst) { vst1q_f32(dst, v); }
|
||||
void Store2(float *dst) { vst1_f32(dst, vget_low_f32(v)); }
|
||||
@@ -516,8 +535,6 @@ struct Vec4F32 {
|
||||
dst[2] = vgetq_lane_f32(v, 2);
|
||||
}
|
||||
|
||||
static Vec4F32 LoadVec2(const float *src) { return Vec4F32{ vcombine_f32(vld1_f32(src), vdup_n_f32(0.0f)) }; } // TODO: Feels like there should be a better way.
|
||||
|
||||
static Vec4F32 LoadConvertS16(const int16_t *src) {
|
||||
int16x4_t value = vld1_s16(src);
|
||||
return Vec4F32{ vcvtq_f32_s32(vmovl_s16(value)) };
|
||||
@@ -548,7 +565,12 @@ struct Vec4F32 {
|
||||
void operator +=(Vec4F32 other) { v = vaddq_f32(v, other.v); }
|
||||
void operator -=(Vec4F32 other) { v = vsubq_f32(v, other.v); }
|
||||
void operator *=(Vec4F32 other) { v = vmulq_f32(v, other.v); }
|
||||
#if PPSSPP_ARCH(ARM64_NEON)
|
||||
void operator /=(Vec4F32 other) { v = vdivq_f32(v, other.v); }
|
||||
#else
|
||||
// ARM32 doesn't have vdivq.
|
||||
void operator /=(Vec4F32 other) { v = vmulq_f32(v, other.Recip().v); }
|
||||
#endif
|
||||
void operator &=(Vec4S32 other) { v = vreinterpretq_f32_s32(vandq_s32(vreinterpretq_s32_f32(v), other.v)); }
|
||||
Vec4F32 operator *(float f) const { return Vec4F32{ vmulq_f32(v, vdupq_n_f32(f)) }; }
|
||||
|
||||
@@ -570,7 +592,7 @@ struct Vec4F32 {
|
||||
return Vec4F32{ recip };
|
||||
}
|
||||
|
||||
Vec4F32 Clamp(float lower, float higher) {
|
||||
Vec4F32 Clamp(float lower, float higher) const {
|
||||
return Vec4F32{
|
||||
vminq_f32(vmaxq_f32(v, vdupq_n_f32(lower)), vdupq_n_f32(higher))
|
||||
};
|
||||
@@ -678,7 +700,6 @@ inline bool AnyZeroSignBit(Vec4F32 value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct Vec4U16 {
|
||||
uint16x4_t v; // 64 bits.
|
||||
|
||||
@@ -724,8 +745,92 @@ struct Vec8U16 {
|
||||
|
||||
#else
|
||||
|
||||
#define CROSSSIMD_SLOW 1
|
||||
|
||||
// Fake SIMD by using scalar.
|
||||
|
||||
struct Mat4F32 {
|
||||
Mat4F32() {}
|
||||
Mat4F32(const float *src) {
|
||||
memcpy(m, src, sizeof(m));
|
||||
}
|
||||
void Store(float *dest) {
|
||||
memcpy(dest, m, sizeof(m));
|
||||
}
|
||||
static Mat4F32 Load4x3(const float *src) {
|
||||
Mat4F32 mat;
|
||||
mat.m[0] = src[0];
|
||||
mat.m[1] = src[1];
|
||||
mat.m[2] = src[2];
|
||||
mat.m[3] = 0.0f;
|
||||
mat.m[0] = src[3];
|
||||
mat.m[1] = src[4];
|
||||
mat.m[2] = src[5];
|
||||
mat.m[3] = 0.0f;
|
||||
mat.m[0] = src[6];
|
||||
mat.m[1] = src[7];
|
||||
mat.m[2] = src[8];
|
||||
mat.m[3] = 0.0f;
|
||||
mat.m[0] = src[9];
|
||||
mat.m[1] = src[10];
|
||||
mat.m[2] = src[11];
|
||||
mat.m[3] = 1.0f;
|
||||
return mat;
|
||||
}
|
||||
|
||||
// cols are consecutive
|
||||
float m[16];
|
||||
};
|
||||
|
||||
// The columns are consecutive but missing the last row (implied 0,0,0,1).
|
||||
// This is just intermediate storage for multiplication.
|
||||
struct Mat4x3F32 {
|
||||
Mat4x3F32(const float *matrix) {
|
||||
memcpy(m, matrix, 12 * sizeof(float));
|
||||
}
|
||||
float m[12];
|
||||
};
|
||||
|
||||
struct Vec4S32 {
|
||||
s32 v[4];
|
||||
int32_t v[4];
|
||||
|
||||
static Vec4S32 Zero() { return Vec4S32{}; }
|
||||
static Vec4S32 Splat(int lane) { return Vec4S32{ { lane, lane, lane, lane } }; }
|
||||
|
||||
static Vec4S32 Load(const int *src) { return Vec4S32{ { src[0], src[1], src[2], src[3] }}; }
|
||||
static Vec4S32 LoadAligned(const int *src) { return Load(src); }
|
||||
void Store(int *dst) { memcpy(dst, v, sizeof(v)); }
|
||||
void Store2(int *dst) { memcpy(dst, v, sizeof(v[0]) * 2); }
|
||||
void StoreAligned(int *dst) { memcpy(dst, v, sizeof(v)); }
|
||||
|
||||
// Warning: Unlike on x86 SSE2, this is a full 32-bit multiplication.
|
||||
Vec4S32 Mul16(Vec4S32 other) const { return Vec4S32{ { v[0] * other.v[0], v[1] * other.v[1], v[2] * other.v[2], v[3] * other.v[3] } }; }
|
||||
|
||||
Vec4S32 SignExtend16() const {
|
||||
Vec4S32 tmp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp.v[i] = (int32_t)(int16_t)v[i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
// NOTE: These can be done in sequence, but when done, you must FixupAfterMinMax to get valid output (on SSE2 at least).
|
||||
Vec4S32 Min16(Vec4S32 other) const {
|
||||
Vec4S32 tmp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp.v[i] = other.v[i] < v[i] ? other.v[i] : v[i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
Vec4S32 Max16(Vec4S32 other) const {
|
||||
Vec4S32 tmp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tmp.v[i] = other.v[i] > v[i] ? other.v[i] : v[i];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
Vec4S32 FixupAfterMinMax() const { return *this; }
|
||||
|
||||
int operator[](size_t index) const { return v[index]; }
|
||||
|
||||
Vec4S32 operator +(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2], v[3] + other.v[3], } };
|
||||
@@ -733,6 +838,416 @@ struct Vec4S32 {
|
||||
Vec4S32 operator -(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2], v[3] - other.v[3], } };
|
||||
}
|
||||
Vec4S32 operator *(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] * other.v[0], v[1] * other.v[1], v[2] * other.v[2], v[3] * other.v[3], } };
|
||||
}
|
||||
// TODO: Can optimize the bitwise ones with 64-bit operations.
|
||||
Vec4S32 operator |(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] | other.v[0], v[1] | other.v[1], v[2] | other.v[2], v[3] | other.v[3], } };
|
||||
}
|
||||
Vec4S32 operator &(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] & other.v[0], v[1] & other.v[1], v[2] & other.v[2], v[3] & other.v[3], } };
|
||||
}
|
||||
Vec4S32 operator ^(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] ^ other.v[0], v[1] ^ other.v[1], v[2] ^ other.v[2], v[3] ^ other.v[3], } };
|
||||
}
|
||||
Vec4S32 AndNot(Vec4S32 other) const {
|
||||
return Vec4S32{ { v[0] & ~other.v[0], v[1] & ~other.v[1], v[2] & ~other.v[2], v[3] & ~other.v[3], } };
|
||||
}
|
||||
Vec4S32 Mul(Vec4S32 other) const { return *this * other; }
|
||||
|
||||
void operator &=(Vec4S32 other) { for (int i = 0; i < 4; i++) v[i] &= other.v[i]; }
|
||||
void operator +=(Vec4S32 other) { for (int i = 0; i < 4; i++) v[i] += other.v[i]; }
|
||||
void operator -=(Vec4S32 other) { for (int i = 0; i < 4; i++) v[i] -= other.v[i]; }
|
||||
|
||||
template<int imm>
|
||||
Vec4S32 Shl() const { return Vec4S32{ { v[0] << imm, v[1] << imm, v[2] << imm, v[3] << imm } }; }
|
||||
|
||||
Vec4S32 CompareEq(Vec4S32 other) const {
|
||||
Vec4S32 out;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out.v[i] = v[i] == other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Vec4S32 CompareLt(Vec4S32 other) const {
|
||||
Vec4S32 out;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out.v[i] = v[i] < other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Vec4S32 CompareGt(Vec4S32 other) const {
|
||||
Vec4S32 out;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out.v[i] = v[i] > other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
Vec4S32 CompareGtZero() const {
|
||||
Vec4S32 out;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out.v[i] = v[i] > 0 ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec4F32 {
|
||||
float v[4];
|
||||
|
||||
static Vec4F32 Zero() { return Vec4F32{}; }
|
||||
static Vec4F32 Splat(float lane) { return Vec4F32{ { lane, lane, lane, lane } }; }
|
||||
|
||||
static Vec4F32 Load(const float *src) { return Vec4F32{ { src[0], src[1], src[2], src[3] } }; }
|
||||
static Vec4F32 LoadAligned(const float *src) { return Vec4F32{ { src[0], src[1], src[2], src[3] } }; }
|
||||
static Vec4F32 LoadS8Norm(const int8_t *src) {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = (float)src[i] * (1.0f / 128.0f);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
static Vec4F32 LoadS16Norm(const int16_t *src) { // Divides by 32768.0f
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = (float)src[i] * (1.0f / 32768.0f);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
void Store(float *dst) { memcpy(dst, v, sizeof(v)); }
|
||||
void Store2(float *dst) { memcpy(dst, v, sizeof(v[0]) * 2); }
|
||||
void StoreAligned(float *dst) { memcpy(dst, v, sizeof(v)); }
|
||||
void Store3(float *dst) {
|
||||
memcpy(dst, v, sizeof(v[0]) * 3);
|
||||
}
|
||||
|
||||
static Vec4F32 LoadConvertS16(const int16_t *src) {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = (float)src[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
static Vec4F32 LoadConvertS8(const int8_t *src) { // Note: will load 8 bytes, not 4. Only the first 4 bytes will be used.
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = (float)src[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
static Vec4F32 LoadF24x3_One(const uint32_t *src) {
|
||||
uint32_t shifted[4] = { src[0] << 8, src[1] << 8, src[2] << 8, 0 };
|
||||
Vec4F32 temp;
|
||||
memcpy(temp.v, shifted, sizeof(temp.v));
|
||||
return temp;
|
||||
}
|
||||
|
||||
static Vec4F32 FromVec4S32(Vec4S32 src) {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = (float)src[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
float operator[](size_t index) const { return v[index]; }
|
||||
|
||||
Vec4F32 operator +(Vec4F32 other) const {
|
||||
return Vec4F32{ { v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2], v[3] + other.v[3], } };
|
||||
}
|
||||
Vec4F32 operator -(Vec4F32 other) const {
|
||||
return Vec4F32{ { v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2], v[3] - other.v[3], } };
|
||||
}
|
||||
Vec4F32 operator *(Vec4F32 other) const {
|
||||
return Vec4F32{ { v[0] * other.v[0], v[1] * other.v[1], v[2] * other.v[2], v[3] * other.v[3], } };
|
||||
}
|
||||
Vec4F32 Min(Vec4F32 other) const {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] < other.v[i] ? v[i] : other.v[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4F32 Max(Vec4F32 other) const {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] > other.v[i] ? v[i] : other.v[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
void operator +=(Vec4F32 other) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v[i] += other.v[i];
|
||||
}
|
||||
}
|
||||
void operator -=(Vec4F32 other) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v[i] -= other.v[i];
|
||||
}
|
||||
}
|
||||
void operator *=(Vec4F32 other) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v[i] *= other.v[i];
|
||||
}
|
||||
}
|
||||
void operator /=(Vec4F32 other) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v[i] /= other.v[i];
|
||||
}
|
||||
}
|
||||
void operator &=(Vec4S32 other) {
|
||||
// TODO: This can be done simpler, although with some ugly casts.
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint32_t val;
|
||||
memcpy(&val, &v[i], 4);
|
||||
val &= other.v[i];
|
||||
memcpy(&v[i], &val, 4);
|
||||
}
|
||||
}
|
||||
Vec4F32 operator *(float f) const {
|
||||
return Vec4F32{ { v[0] * f, v[1] * f, v[2] * f, v[3] * f } };
|
||||
}
|
||||
|
||||
Vec4F32 Mul(float f) const {
|
||||
return Vec4F32{ { v[0] * f, v[1] * f, v[2] * f, v[3] * f } };
|
||||
}
|
||||
|
||||
Vec4F32 Recip() const {
|
||||
return Vec4F32{ { 1.0f / v[0], 1.0f / v[1], 1.0f / v[2], 1.0f / v[3] } };
|
||||
}
|
||||
|
||||
Vec4F32 RecipApprox() const {
|
||||
return Vec4F32{ { 1.0f / v[0], 1.0f / v[1], 1.0f / v[2], 1.0f / v[3] } };
|
||||
}
|
||||
|
||||
Vec4F32 Clamp(float lower, float higher) const {
|
||||
Vec4F32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (v[i] > higher) {
|
||||
temp.v[i] = higher;
|
||||
} else if (v[i] < lower) {
|
||||
temp.v[i] = lower;
|
||||
} else {
|
||||
temp.v[i] = v[i];
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
Vec4F32 WithLane3Zero() const {
|
||||
return Vec4F32{ { v[0], v[1], v[2], 0.0f } };
|
||||
}
|
||||
|
||||
Vec4F32 WithLane3One() const {
|
||||
return Vec4F32{ { v[0], v[1], v[2], 1.0f } };
|
||||
}
|
||||
|
||||
Vec4S32 CompareEq(Vec4F32 other) const {
|
||||
Vec4S32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] == other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4S32 CompareLt(Vec4F32 other) const {
|
||||
Vec4S32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] < other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4S32 CompareGt(Vec4F32 other) const {
|
||||
Vec4S32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] > other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4S32 CompareLe(Vec4F32 other) const {
|
||||
Vec4S32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] <= other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4S32 CompareGe(Vec4F32 other) const {
|
||||
Vec4S32 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] >= other.v[i] ? 0xFFFFFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
// In-place transpose. Fast on SIMD, not ideal on not.
|
||||
static void Transpose(Vec4F32 &col0, Vec4F32 &col1, Vec4F32 &col2, Vec4F32 &col3) {
|
||||
std::swap(col0.v[1], col1.v[0]);
|
||||
std::swap(col0.v[2], col2.v[0]);
|
||||
std::swap(col0.v[3], col3.v[0]);
|
||||
|
||||
std::swap(col1.v[0], col0.v[1]);
|
||||
std::swap(col1.v[2], col2.v[1]);
|
||||
std::swap(col1.v[3], col3.v[1]);
|
||||
|
||||
std::swap(col2.v[0], col0.v[2]);
|
||||
std::swap(col2.v[1], col1.v[2]);
|
||||
std::swap(col2.v[3], col3.v[2]);
|
||||
|
||||
std::swap(col3.v[0], col0.v[3]);
|
||||
std::swap(col3.v[1], col1.v[3]);
|
||||
std::swap(col3.v[2], col2.v[3]);
|
||||
}
|
||||
|
||||
inline Vec4F32 AsVec3ByMatrix44(const Mat4F32 &m) {
|
||||
float x = m.m[0] * v[0] + m.m[4] * v[1] + m.m[8] * v[2] + m.m[12];
|
||||
float y = m.m[1] * v[0] + m.m[5] * v[1] + m.m[9] * v[2] + m.m[13];
|
||||
float z = m.m[2] * v[0] + m.m[6] * v[1] + m.m[10] * v[2] + m.m[14];
|
||||
|
||||
return Vec4F32{ { x, y, z, 1.0f } };
|
||||
}
|
||||
};
|
||||
|
||||
inline bool AnyZeroSignBit(Vec4S32 value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (value.v[i] >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool AnyZeroSignBit(Vec4F32 value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (value.v[i] >= 0.0f) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct Vec4U16 {
|
||||
uint16_t v[4]; // 64 bits.
|
||||
|
||||
static Vec4U16 Zero() { return Vec4U16{}; }
|
||||
static Vec4U16 Splat(uint16_t lane) { return Vec4U16{ { lane, lane, lane, lane } }; }
|
||||
|
||||
static Vec4U16 Load(const uint16_t *mem) { return Vec4U16{ { mem[0], mem[1], mem[2], mem[3] }}; }
|
||||
void Store(uint16_t *mem) { memcpy(mem, v, sizeof(v)); }
|
||||
|
||||
static Vec4U16 FromVec4S32(Vec4S32 v) {
|
||||
return Vec4U16{ { (uint16_t)v.v[0], (uint16_t)v.v[1], (uint16_t)v.v[2], (uint16_t)v.v[3] }};
|
||||
}
|
||||
static Vec4U16 FromVec4F32(Vec4F32 v) {
|
||||
return Vec4U16{ { (uint16_t)v.v[0], (uint16_t)v.v[1], (uint16_t)v.v[2], (uint16_t)v.v[3] }};
|
||||
}
|
||||
|
||||
Vec4U16 operator |(Vec4U16 other) const { return Vec4U16{ { (uint16_t)(v[0] | other.v[0]), (uint16_t)(v[1] | other.v[1]), (uint16_t)(v[2] | other.v[2]), (uint16_t)(v[3] | other.v[3]), } }; }
|
||||
Vec4U16 operator &(Vec4U16 other) const { return Vec4U16{ { (uint16_t)(v[0] & other.v[0]), (uint16_t)(v[1] & other.v[1]), (uint16_t)(v[2] & other.v[2]), (uint16_t)(v[3] & other.v[3]), } }; }
|
||||
Vec4U16 operator ^(Vec4U16 other) const { return Vec4U16{ { (uint16_t) (v[0] ^ other.v[0]), (uint16_t)(v[1] ^ other.v[1]), (uint16_t)(v[2] ^ other.v[2]), (uint16_t)(v[3] ^ other.v[3]), } }; }
|
||||
|
||||
Vec4U16 Max(Vec4U16 other) const {
|
||||
Vec4U16 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] > other.v[i] ? v[i] : other.v[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4U16 Min(Vec4U16 other) const {
|
||||
Vec4U16 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] < other.v[i] ? v[i] : other.v[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4U16 CompareLT(Vec4U16 other) const {
|
||||
Vec4U16 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] < other.v[i] ? 0xFFFF : 0;
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
Vec4U16 AndNot(Vec4U16 other) const {
|
||||
Vec4U16 temp;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
temp.v[i] = v[i] & ~other.v[i];
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
};
|
||||
|
||||
struct Vec8U16 {
|
||||
uint16_t v[8];
|
||||
|
||||
static Vec8U16 Zero() { return Vec8U16{}; }
|
||||
static Vec8U16 Splat(uint16_t value) { return Vec8U16{ {
|
||||
value, value, value, value, value, value, value, value,
|
||||
}}; }
|
||||
|
||||
static Vec8U16 Load(const uint16_t *mem) { Vec8U16 tmp; memcpy(tmp.v, mem, sizeof(v)); return tmp; }
|
||||
void Store(uint16_t *mem) { memcpy(mem, v, sizeof(v)); }
|
||||
};
|
||||
|
||||
inline Vec4U16 SignBits32ToMaskU16(Vec4S32 v) {
|
||||
return Vec4U16{ { (uint16_t)(v.v[0] >> 31), (uint16_t)(v.v[1] >> 31), (uint16_t)(v.v[2] >> 31), (uint16_t)(v.v[3] >> 31), } };
|
||||
}
|
||||
|
||||
inline Vec4S32 Vec4S32FromF32(Vec4F32 f) {
|
||||
return Vec4S32{ { (int32_t)f.v[0], (int32_t)f.v[1], (int32_t)f.v[2], (int32_t)f.v[3] } };
|
||||
}
|
||||
|
||||
inline Vec4F32 Vec4F32FromS32(Vec4S32 f) {
|
||||
return Vec4F32{ { (float)f.v[0], (float)f.v[1], (float)f.v[2], (float)f.v[3] } };
|
||||
}
|
||||
|
||||
// Make sure the W component of scale is 1.0f.
|
||||
inline void ScaleInplace(Mat4F32 &m, Vec4F32 scale) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m.m[i * 4 + 0] *= scale.v[0];
|
||||
m.m[i * 4 + 1] *= scale.v[1];
|
||||
m.m[i * 4 + 2] *= scale.v[2];
|
||||
m.m[i * 4 + 3] *= scale.v[3];
|
||||
}
|
||||
}
|
||||
|
||||
inline void TranslateAndScaleInplace(Mat4F32 &m, Vec4F32 scale, Vec4F32 translate) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m.m[i * 4 + 0] = m.m[i * 4 + 0] * scale.v[0] + translate.v[0] * m.m[i * 4 + 3];
|
||||
m.m[i * 4 + 1] = m.m[i * 4 + 1] * scale.v[1] + translate.v[1] * m.m[i * 4 + 3];
|
||||
m.m[i * 4 + 2] = m.m[i * 4 + 2] * scale.v[2] + translate.v[2] * m.m[i * 4 + 3];
|
||||
m.m[i * 4 + 3] = m.m[i * 4 + 3] * scale.v[3] + translate.v[3] * m.m[i * 4 + 3];
|
||||
}
|
||||
}
|
||||
|
||||
inline Mat4F32 Mul4x4By4x4(Mat4F32 a, Mat4F32 b) {
|
||||
Mat4F32 result;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float sum = 0.0f;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
sum += b.m[i * 4 + k] * a.m[k * 4 + j];
|
||||
}
|
||||
result.m[j * 4 + i] = sum;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Mat4F32 Mul4x3By4x4(Mat4x3F32 a, Mat4F32 b) {
|
||||
Mat4F32 result;
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float sum = 0.0f;
|
||||
for (int k = 0; k < 3; k++) {
|
||||
sum += b.m[i * 4 + k] * a.m[k * 3 + j];
|
||||
}
|
||||
result.m[j * 4 + i] = sum + b.m[i * 4 + 3];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -140,11 +140,22 @@ std::string DefaultLangRegion() {
|
||||
}
|
||||
|
||||
static int DefaultDepthRaster() {
|
||||
|
||||
// For 64-bit ARM and x86 with SIMD, enable depth raster.
|
||||
#if PPSSPP_ARCH(ARM64_NEON) || PPSSPP_ARCH(SSE2)
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
return (int)DepthRasterMode::LOW_QUALITY;
|
||||
#else
|
||||
return (int)DepthRasterMode::DEFAULT;
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// 32-bit ARM or no SIMD, the depth raster will be too slow.
|
||||
return (int)DepthRasterMode::OFF;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string CreateRandMAC() {
|
||||
|
||||
@@ -56,6 +56,9 @@ DrawEngineCommon::DrawEngineCommon() : decoderMap_(32) {
|
||||
decIndex_ = (u16 *)AllocateMemoryPages(DECODED_INDEX_BUFFER_SIZE, MEM_PROT_READ | MEM_PROT_WRITE);
|
||||
indexGen.Setup(decIndex_);
|
||||
|
||||
#ifdef CROSSSIMD_SLOW
|
||||
useDepthRaster_ = false;
|
||||
#else
|
||||
switch ((DepthRasterMode)g_Config.iDepthRasterMode) {
|
||||
case DepthRasterMode::DEFAULT:
|
||||
case DepthRasterMode::LOW_QUALITY:
|
||||
@@ -67,6 +70,7 @@ DrawEngineCommon::DrawEngineCommon() : decoderMap_(32) {
|
||||
case DepthRasterMode::OFF:
|
||||
useDepthRaster_ = false;
|
||||
}
|
||||
#endif
|
||||
if (useDepthRaster_) {
|
||||
depthDraws_.reserve(256);
|
||||
}
|
||||
|
||||
@@ -155,14 +155,6 @@ WorldCoords TransformUnit::ModelToWorldNormal(const ModelCoords &coords) {
|
||||
return Norm3ByMatrix43(coords, gstate.worldMatrix);
|
||||
}
|
||||
|
||||
ViewCoords TransformUnit::WorldToView(const WorldCoords &coords) {
|
||||
return Vec3ByMatrix43(coords, gstate.viewMatrix);
|
||||
}
|
||||
|
||||
ClipCoords TransformUnit::ViewToClip(const ViewCoords &coords) {
|
||||
return Vec3ByMatrix44(coords, gstate.projMatrix);
|
||||
}
|
||||
|
||||
template <bool depthClamp, bool alwaysCheckRange>
|
||||
static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords, bool *outside_range_flag) {
|
||||
ScreenCoords ret;
|
||||
|
||||
@@ -121,8 +121,6 @@ public:
|
||||
|
||||
static WorldCoords ModelToWorldNormal(const ModelCoords& coords);
|
||||
static WorldCoords ModelToWorld(const ModelCoords& coords);
|
||||
static ViewCoords WorldToView(const WorldCoords& coords);
|
||||
static ClipCoords ViewToClip(const ViewCoords& coords);
|
||||
static ScreenCoords ClipToScreen(const ClipCoords &coords, bool *outsideRangeFlag);
|
||||
static inline DrawingCoords ScreenToDrawing(int x, int y) {
|
||||
DrawingCoords ret;
|
||||
|
||||
@@ -679,6 +679,8 @@ static void ShowFpsLimitNotice() {
|
||||
case FPSLimit::CUSTOM2:
|
||||
fpsLimit = g_Config.iFpsLimit2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Now display it.
|
||||
|
||||
@@ -466,7 +466,7 @@ bool TestVFPUSinCos() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestMatrixTranspose() {
|
||||
bool TestVFPUMatrixTranspose() {
|
||||
MatrixSize sz = M_4x4;
|
||||
int matrix = 0; // M000
|
||||
u8 cols[4];
|
||||
@@ -489,6 +489,7 @@ bool TestMatrixTranspose() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Hook this up again!
|
||||
void TestGetMatrix(int matrix, MatrixSize sz) {
|
||||
INFO_LOG(Log::System, "Testing matrix %s", GetMatrixNotation(matrix, sz).c_str());
|
||||
u8 fullMatrix[16];
|
||||
@@ -1182,7 +1183,7 @@ TestItem availableTests[] = {
|
||||
TEST_ITEM(Parsers),
|
||||
TEST_ITEM(IRPassSimplify),
|
||||
TEST_ITEM(Jit),
|
||||
TEST_ITEM(MatrixTranspose),
|
||||
TEST_ITEM(VFPUMatrixTranspose),
|
||||
TEST_ITEM(ParseLBN),
|
||||
TEST_ITEM(QuickTexHash),
|
||||
TEST_ITEM(CLZ),
|
||||
|
||||
Reference in new issue
Block a user