mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-14 10:09:32 +01:00
Merge pull request #13706 from hrydgard/vfpu-sincos-double-compat
Add back the old implementation of vfpu_sin/cos/sincos.
This commit is contained in:
6 files changed
+103
-27
No files matched your search
@@ -75,6 +75,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
|
||||
CheckSetting(iniFile, gameID, "MemstickFixedFree", &flags_.MemstickFixedFree);
|
||||
CheckSetting(iniFile, gameID, "DateLimited", &flags_.DateLimited);
|
||||
CheckSetting(iniFile, gameID, "ReinterpretFramebuffers", &flags_.ReinterpretFramebuffers);
|
||||
CheckSetting(iniFile, gameID, "DoublePrecisionSinCos", &flags_.DoublePrecisionSinCos);
|
||||
}
|
||||
|
||||
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
|
||||
|
||||
@@ -73,6 +73,7 @@ struct CompatFlags {
|
||||
bool MemstickFixedFree;
|
||||
bool DateLimited;
|
||||
bool ReinterpretFramebuffers;
|
||||
bool DoublePrecisionSinCos;
|
||||
};
|
||||
|
||||
class IniFile;
|
||||
|
||||
@@ -895,3 +895,86 @@ float vfpu_rsqrt(float a) {
|
||||
|
||||
return val.f;
|
||||
}
|
||||
|
||||
float vfpu_sin_single(float angle) {
|
||||
angle -= floorf(angle * 0.25f) * 4.f;
|
||||
if (angle == 0.0f || angle == 2.0f) {
|
||||
return 0.0f;
|
||||
} else if (angle == 1.0f) {
|
||||
return 1.0f;
|
||||
} else if (angle == 3.0f) {
|
||||
return -1.0f;
|
||||
}
|
||||
angle *= (float)M_PI_2;
|
||||
return sinf(angle);
|
||||
}
|
||||
|
||||
float vfpu_cos_single(float angle) {
|
||||
angle -= floorf(angle * 0.25f) * 4.f;
|
||||
if (angle == 1.0f || angle == 3.0f) {
|
||||
return 0.0f;
|
||||
} else if (angle == 0.0f) {
|
||||
return 1.0f;
|
||||
} else if (angle == 2.0f) {
|
||||
return -1.0f;
|
||||
}
|
||||
angle *= (float)M_PI_2;
|
||||
return cosf(angle);
|
||||
}
|
||||
|
||||
void vfpu_sincos_single(float angle, float &sine, float &cosine) {
|
||||
angle -= floorf(angle * 0.25f) * 4.f;
|
||||
if (angle == 0.0f) {
|
||||
sine = 0.0f;
|
||||
cosine = 1.0f;
|
||||
} else if (angle == 1.0f) {
|
||||
sine = 1.0f;
|
||||
cosine = 0.0f;
|
||||
} else if (angle == 2.0f) {
|
||||
sine = 0.0f;
|
||||
cosine = -1.0f;
|
||||
} else if (angle == 3.0f) {
|
||||
sine = -1.0f;
|
||||
cosine = 0.0f;
|
||||
} else {
|
||||
angle *= (float)M_PI_2;
|
||||
#if defined(__linux__)
|
||||
sincosf(angle, &sine, &cosine);
|
||||
#else
|
||||
sine = sinf(angle);
|
||||
cosine = cosf(angle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
float vfpu_sin_double(float angle) {
|
||||
return (float)sin((double)angle * M_PI_2);
|
||||
}
|
||||
|
||||
float vfpu_cos_double(float angle) {
|
||||
return (float)cos((double)angle * M_PI_2);
|
||||
}
|
||||
|
||||
void vfpu_sincos_double(float angle_f, float &sine, float &cosine) {
|
||||
double angle = (double)angle_f * M_PI_2;
|
||||
#if defined(__linux__)
|
||||
double d_sine;
|
||||
double d_cosine;
|
||||
sincos(angle, &d_sine, &d_cosine);
|
||||
sine = (float)d_sine;
|
||||
cosine = (float)d_cosine;
|
||||
#else
|
||||
sine = (float)sin(angle);
|
||||
cosine = (float)cos(angle);
|
||||
#endif
|
||||
}
|
||||
|
||||
float (*vfpu_sin)(float);
|
||||
float (*vfpu_cos)(float);
|
||||
void (*vfpu_sincos)(float, float&, float&);
|
||||
|
||||
void InitVFPUSinCos(bool useDoublePrecision) {
|
||||
vfpu_sin = useDoublePrecision ? vfpu_sin_double : vfpu_sin_single;
|
||||
vfpu_cos = useDoublePrecision ? vfpu_cos_double : vfpu_cos_single;
|
||||
vfpu_sincos = useDoublePrecision ? vfpu_sincos_double : vfpu_sincos_single;
|
||||
}
|
||||
+12
-26
@@ -35,44 +35,29 @@ inline int Xpose(int v) {
|
||||
#endif
|
||||
|
||||
// The VFPU uses weird angles where 4.0 represents a full circle. This makes it possible to return
|
||||
// exact 1.0/-1.0 values at certain angles. We get close enough for #2921 and #12900 by computing
|
||||
// things in double precision, multiplying the input by pi/2.
|
||||
// exact 1.0/-1.0 values at certain angles. We currently just scale, and special case the cardinal directions.
|
||||
//
|
||||
// Stepping down to [0, 2pi) helps, but we also check common exact-result values.
|
||||
// TODO: cos(1) and sin(2) should be -0.0, but doing that gives wrong results (possibly from floorf.)
|
||||
//
|
||||
// We also try an alternative solution, computing things in double precision, multiplying the input by pi/2.
|
||||
// This fixes #12900 (Hitman Reborn 2) but breaks #13705 (Cho Aniki Zero) and #13671 (Hajime no Ippo).
|
||||
// #2921 is still fine. So the alt solution (vfpu_sin_double etc) are behind a compat flag.
|
||||
//
|
||||
// A better solution would be to tailor some sine approximation for the 0..90 degrees range, compute
|
||||
// modulo manually and mirror that around the circle. Also correctly special casing for inf/nan inputs
|
||||
// and just trying to match it as closely as possible to the real PSP.
|
||||
//
|
||||
// Stepping down to [0, 2pi) helps, but we also check common exact-result values.
|
||||
// TODO: cos(1) and sin(2) should be -0.0, but doing that gives wrong results (possibly from floorf.)
|
||||
|
||||
// Messing around with the modulo functions? try https://www.desmos.com/calculator.
|
||||
|
||||
inline float vfpu_sin(float angle) {
|
||||
return (float)sin((double)angle * M_PI_2);
|
||||
}
|
||||
|
||||
inline float vfpu_cos(float angle) {
|
||||
return (float)cos((double)angle * M_PI_2);
|
||||
}
|
||||
extern float (*vfpu_sin)(float);
|
||||
extern float (*vfpu_cos)(float);
|
||||
extern void (*vfpu_sincos)(float, float&, float&);
|
||||
|
||||
inline float vfpu_asin(float angle) {
|
||||
return asinf(angle) / M_PI_2;
|
||||
}
|
||||
|
||||
inline void vfpu_sincos(float angle_f, float &sine, float &cosine) {
|
||||
double angle = (double)angle_f * M_PI_2;
|
||||
#if defined(__linux__)
|
||||
double d_sine;
|
||||
double d_cosine;
|
||||
sincos(angle, &d_sine, &d_cosine);
|
||||
sine = (float)d_sine;
|
||||
cosine = (float)d_cosine;
|
||||
#else
|
||||
sine = (float)sin(angle);
|
||||
cosine = (float)cos(angle);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline float vfpu_clamp(float v, float min, float max) {
|
||||
// Note: NAN is preserved, and -0.0 becomes +0.0 if min=+0.0.
|
||||
return v >= max ? max : (v <= min ? min : v);
|
||||
@@ -230,3 +215,4 @@ int GetVectorOverlap(int reg1, VectorSize size1, int reg2, VectorSize size2);
|
||||
bool GetVFPUCtrlMask(int reg, u32 *mask);
|
||||
|
||||
float Float16ToFloat32(unsigned short l);
|
||||
void InitVFPUSinCos(bool useDoublePrecision);
|
||||
+3
-1
@@ -44,6 +44,7 @@
|
||||
#include "Core/HDRemaster.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
#include "Core/MIPS/MIPSAnalyst.h"
|
||||
#include "Core/MIPS/MIPSVFPUUtils.h"
|
||||
#include "Core/Debugger/SymbolMap.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/System.h"
|
||||
@@ -66,7 +67,6 @@
|
||||
#include "Common/LogManager.h"
|
||||
#include "Common/ExceptionHandlerSetup.h"
|
||||
#include "Core/HLE/sceAudiocodec.h"
|
||||
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/Debugger/RecordFormat.h"
|
||||
@@ -287,6 +287,8 @@ bool CPU_Init() {
|
||||
// likely to collide with any commercial ones.
|
||||
coreParameter.compat.Load(discID);
|
||||
|
||||
InitVFPUSinCos(coreParameter.compat.flags().DoublePrecisionSinCos);
|
||||
|
||||
HLEPlugins::Init();
|
||||
if (!Memory::Init()) {
|
||||
// We're screwed.
|
||||
|
||||
@@ -808,3 +808,6 @@ ULKS46087 = true
|
||||
# ULJM05533 = true
|
||||
# NPJH50006 = true
|
||||
|
||||
[DoublePrecisionSinCos]
|
||||
# Hitman Reborn Battle Arena 2 (#12900)
|
||||
ULJS00218 = true
|
||||
Reference in new issue
Block a user