diff --git a/CMakeLists.txt b/CMakeLists.txt
index b3b33d1f22..86ddf08cb1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1595,6 +1595,8 @@ set(GPU_SOURCES
GPU/Software/Rasterizer.h
GPU/Software/RasterizerRectangle.cpp
GPU/Software/RasterizerRectangle.h
+ GPU/Software/RasterizerRegCache.cpp
+ GPU/Software/RasterizerRegCache.h
GPU/Software/Sampler.cpp
GPU/Software/Sampler.h
GPU/Software/SoftGpu.cpp
diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj
index 9ef8aa4f24..9bb00dde1b 100644
--- a/GPU/GPU.vcxproj
+++ b/GPU/GPU.vcxproj
@@ -458,6 +458,7 @@
+
@@ -636,6 +637,7 @@
+
diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters
index 0f3248dc0b..d747ccec4a 100644
--- a/GPU/GPU.vcxproj.filters
+++ b/GPU/GPU.vcxproj.filters
@@ -270,6 +270,9 @@
Software
+
+ Software
+
@@ -545,5 +548,8 @@
Software
+
+ Software
+
\ No newline at end of file
diff --git a/GPU/Math3D.h b/GPU/Math3D.h
index ff05280c43..b8ede12cb8 100644
--- a/GPU/Math3D.h
+++ b/GPU/Math3D.h
@@ -64,6 +64,9 @@ public:
#if defined(_M_SSE)
__m128i ivec;
__m128 vec;
+#elif PPSSPP_ARCH(ARM64)
+ int32x4_t ivec;
+ float32x4_t vec;
#endif
};
@@ -76,6 +79,11 @@ public:
#if defined(_M_SSE)
Vec2(const __m128 &_vec) : vec(_vec) {}
Vec2(const __m128i &_ivec) : ivec(_ivec) {}
+#elif PPSSPP_ARCH(ARM64)
+ Vec2(const float32x4_t &_vec) : vec(_vec) {}
+#if !defined(_MSC_VER)
+ Vec2(const int32x4_t &_ivec) : ivec(_ivec) {}
+#endif
#endif
template
@@ -204,6 +212,9 @@ public:
#if defined(_M_SSE)
__m128i ivec;
__m128 vec;
+#elif PPSSPP_ARCH(ARM64)
+ int32x4_t ivec;
+ float32x4_t vec;
#endif
};
@@ -220,6 +231,14 @@ public:
Vec3(const Vec3Packed &_xyz) {
vec = _mm_loadu_ps(_xyz.AsArray());
}
+#elif PPSSPP_ARCH(ARM64)
+ Vec3(const float32x4_t &_vec) : vec(_vec) {}
+#if !defined(_MSC_VER)
+ Vec3(const int32x4_t &_ivec) : ivec(_ivec) {}
+#endif
+ Vec3(const Vec3Packed &_xyz) {
+ vec = vld1q_f32(_xyz.AsArray());
+ }
#else
Vec3(const Vec3Packed &_xyz) : x(_xyz.x), y(_xyz.y), z(_xyz.z) {}
#endif
@@ -552,6 +571,9 @@ public:
#if defined(_M_SSE)
__m128i ivec;
__m128 vec;
+#elif PPSSPP_ARCH(ARM64)
+ int32x4_t ivec;
+ float32x4_t vec;
#endif
};
@@ -566,6 +588,11 @@ public:
#if defined(_M_SSE)
Vec4(const __m128 &_vec) : vec(_vec) {}
Vec4(const __m128i &_ivec) : ivec(_ivec) {}
+#elif PPSSPP_ARCH(ARM64)
+ Vec4(const float32x4_t &_vec) : vec(_vec) {}
+#if !defined(_MSC_VER)
+ Vec4(const int32x4_t &_ivec) : ivec(_ivec) {}
+#endif
#endif
template
diff --git a/GPU/Software/DrawPixel.cpp b/GPU/Software/DrawPixel.cpp
index e81b8dc7c4..e3c7534523 100644
--- a/GPU/Software/DrawPixel.cpp
+++ b/GPU/Software/DrawPixel.cpp
@@ -378,7 +378,7 @@ static inline u32 ApplyLogicOp(GELogicOp op, u32 old_color, u32 new_color) {
}
template
-void SOFTPIXEL_CALL DrawSinglePixel(int x, int y, int z, int fog, SOFTPIXEL_VEC4I color_in, const PixelFuncID &pixelID) {
+void SOFTRAST_CALL DrawSinglePixel(int x, int y, int z, int fog, Vec4IntArg color_in, const PixelFuncID &pixelID) {
Vec4 prim_color = Vec4(color_in).Clamp(0, 255);
// Depth range test - applied in clear mode, if not through mode.
if (pixelID.applyDepthRange)
@@ -635,142 +635,4 @@ void ComputePixelBlendState(PixelBlendState &state, const PixelFuncID &id) {
}
}
-void PixelRegCache::Reset() {
- regs.clear();
-}
-
-void PixelRegCache::Release(PixelRegCache::Reg r, PixelRegCache::Type t, PixelRegCache::Purpose p) {
- RegStatus *status = FindReg(r, t);
- if (status) {
- _assert_msg_(status->locked > 0, "softjit Release() reg that isn't locked");
- _assert_msg_(!status->forceLocked, "softjit Release() reg that is force locked");
- status->purpose = p;
- status->locked--;
- return;
- }
-
- RegStatus newStatus;
- newStatus.reg = r;
- newStatus.purpose = p;
- newStatus.type = t;
- regs.push_back(newStatus);
-}
-
-void PixelRegCache::Unlock(PixelRegCache::Reg r, PixelRegCache::Type t) {
- RegStatus *status = FindReg(r, t);
- if (status) {
- _assert_msg_(status->locked > 0, "softjit Unlock() reg that isn't locked");
- status->locked--;
- return;
- }
-
- _assert_msg_(false, "softjit Unlock() reg that isn't there");
-}
-
-bool PixelRegCache::Has(PixelRegCache::Purpose p, PixelRegCache::Type t) {
- for (auto ® : regs) {
- if (reg.purpose == p && reg.type == t) {
- return true;
- }
- }
- return false;
-}
-
-PixelRegCache::Reg PixelRegCache::Find(PixelRegCache::Purpose p, PixelRegCache::Type t) {
- for (auto ® : regs) {
- if (reg.purpose == p && reg.type == t) {
- _assert_msg_(reg.locked <= 255, "softjit Find() reg has lots of locks");
- reg.locked++;
- return reg.reg;
- }
- }
- _assert_msg_(false, "softjit Find() reg that isn't there (%d)", p);
- return Reg(-1);
-}
-
-PixelRegCache::Reg PixelRegCache::Alloc(PixelRegCache::Purpose p, PixelRegCache::Type t) {
- _assert_msg_(!Has(p, t), "softjit Alloc() reg duplicate");
- RegStatus *best = nullptr;
- for (auto ® : regs) {
- if (reg.locked != 0 || reg.forceLocked || reg.type != t)
- continue;
-
- if (best == nullptr)
- best = ®
- // Prefer a free/purposeless reg.
- if (reg.purpose == INVALID || reg.purpose >= TEMP0) {
- best = ®
- break;
- }
- // But also prefer a lower priority reg.
- if (reg.purpose < best->purpose)
- best = ®
- }
-
- if (best) {
- best->locked = 1;
- best->purpose = p;
- return best->reg;
- }
-
- _assert_msg_(false, "softjit Alloc() reg with none free (%d)", p);
- return Reg();
-}
-
-void PixelRegCache::ForceLock(PixelRegCache::Purpose p, PixelRegCache::Type t, bool state) {
- for (auto ® : regs) {
- if (reg.purpose == p && reg.type == t) {
- reg.forceLocked = state;
- return;
- }
- }
-
- _assert_msg_(false, "softjit ForceLock() reg that isn't there");
-}
-
-void PixelRegCache::GrabReg(PixelRegCache::Reg r, PixelRegCache::Purpose p, PixelRegCache::Type t, bool &needsSwap, PixelRegCache::Reg swapReg) {
- for (auto ® : regs) {
- if (reg.reg != r || reg.type != t)
- continue;
-
- // Easy version, it's free.
- if (reg.locked == 0 && !reg.forceLocked) {
- needsSwap = false;
- reg.purpose = p;
- reg.locked = 1;
- return;
- }
-
- // Okay, we need to swap. Find that reg.
- needsSwap = true;
- RegStatus *swap = FindReg(swapReg, t);
- if (swap) {
- swap->purpose = reg.purpose;
- swap->forceLocked = reg.forceLocked;
- swap->locked = reg.locked;
- } else {
- RegStatus newStatus = reg;
- newStatus.reg = swapReg;
- regs.push_back(newStatus);
- }
-
- reg.purpose = p;
- reg.locked = 1;
- reg.forceLocked = false;
- return;
- }
-
- _assert_msg_(false, "softjit GrabReg() reg that isn't there");
-}
-
-PixelRegCache::RegStatus *PixelRegCache::FindReg(PixelRegCache::Reg r, PixelRegCache::Type t) {
- for (auto ® : regs) {
- if (reg.reg == r && reg.type == t) {
- return ®
- }
- }
-
- return nullptr;
-}
-
};
diff --git a/GPU/Software/DrawPixel.h b/GPU/Software/DrawPixel.h
index 936ce5537f..f3e803c9f1 100644
--- a/GPU/Software/DrawPixel.h
+++ b/GPU/Software/DrawPixel.h
@@ -22,37 +22,13 @@
#include
#include
#include
-#if PPSSPP_ARCH(ARM)
-#include "Common/ArmEmitter.h"
-#elif PPSSPP_ARCH(ARM64)
-#include "Common/Arm64Emitter.h"
-#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
-#include "Common/x64Emitter.h"
-#elif PPSSPP_ARCH(MIPS)
-#include "Common/MipsEmitter.h"
-#else
-#include "Common/FakeEmitter.h"
-#endif
#include "GPU/Math3D.h"
#include "GPU/Software/FuncId.h"
+#include "GPU/Software/RasterizerRegCache.h"
namespace Rasterizer {
-#if PPSSPP_ARCH(AMD64) && PPSSPP_PLATFORM(WINDOWS) && (defined(_MSC_VER) || defined(__clang__))
-#define SOFTPIXEL_CALL __vectorcall
-#define SOFTPIXEL_VEC4I __m128i
-#define SOFTPIXEL_TO_VEC4I(x) (x).ivec
-#elif PPSSPP_ARCH(AMD64)
-#define SOFTPIXEL_CALL
-#define SOFTPIXEL_VEC4I __m128i
-#define SOFTPIXEL_TO_VEC4I(x) (x).ivec
-#else
-#define SOFTPIXEL_CALL
-#define SOFTPIXEL_VEC4I const Math3D::Vec4 &
-#define SOFTPIXEL_TO_VEC4I(x) (x)
-#endif
-
-typedef void (SOFTPIXEL_CALL *SingleFunc)(int x, int y, int z, int fog, SOFTPIXEL_VEC4I color_in, const PixelFuncID &pixelID);
+typedef void (SOFTRAST_CALL *SingleFunc)(int x, int y, int z, int fog, Vec4IntArg color_in, const PixelFuncID &pixelID);
SingleFunc GetSingleFunc(const PixelFuncID &id);
void Init();
@@ -60,62 +36,6 @@ void Shutdown();
bool DescribeCodePtr(const u8 *ptr, std::string &name);
-struct PixelRegCache {
- enum Purpose {
- INVALID,
- ZERO,
- SRC_ALPHA,
- GSTATE,
- CONST_BASE,
- STENCIL,
- COLOR_OFF,
- DEPTH_OFF,
-
- // Above this can only be temps.
- TEMP0,
- TEMP1,
- TEMP2,
- TEMP3,
- TEMP4,
- TEMP5,
- TEMP_HELPER,
- };
- enum Type {
- T_GEN,
- T_VEC,
- };
-
-#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
- typedef Gen::X64Reg Reg;
-#else
- typedef int Reg;
-#endif
-
- struct RegStatus {
- Reg reg;
- Purpose purpose;
- Type type;
- uint8_t locked = 0;
- bool forceLocked = false;
- };
-
- void Reset();
- void Release(Reg r, Type t, Purpose p = INVALID);
- void Unlock(Reg r, Type t);
- bool Has(Purpose p, Type t);
- Reg Find(Purpose p, Type t);
- Reg Alloc(Purpose p, Type t);
- void ForceLock(Purpose p, Type t, bool state = true);
-
- // For getting a specific reg. WARNING: May return a locked reg, so you have to check.
- void GrabReg(Reg r, Purpose p, Type t, bool &needsSwap, Reg swapReg);
-
-private:
- RegStatus *FindReg(Reg r, Type t);
-
- std::vector regs;
-};
-
struct PixelBlendState {
bool usesFactors = false;
bool usesDstAlpha = false;
@@ -123,17 +43,7 @@ struct PixelBlendState {
};
void ComputePixelBlendState(PixelBlendState &state, const PixelFuncID &id);
-#if PPSSPP_ARCH(ARM)
-class PixelJitCache : public ArmGen::ARMXCodeBlock {
-#elif PPSSPP_ARCH(ARM64)
-class PixelJitCache : public Arm64Gen::ARM64CodeBlock {
-#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
-class PixelJitCache : public Gen::XCodeBlock {
-#elif PPSSPP_ARCH(MIPS)
-class PixelJitCache : public MIPSGen::MIPSCodeBlock {
-#else
-class PixelJitCache : public FakeGen::FakeXCodeBlock {
-#endif
+class PixelJitCache : public Rasterizer::CodeBlock {
public:
PixelJitCache();
@@ -151,41 +61,41 @@ private:
Arm64Gen::ARM64FloatEmitter fp;
#endif
- PixelRegCache::Reg GetGState();
- PixelRegCache::Reg GetConstBase();
- PixelRegCache::Reg GetZeroVec();
+ RegCache::Reg GetGState();
+ RegCache::Reg GetConstBase();
+ RegCache::Reg GetZeroVec();
// Note: these may require a temporary reg.
- PixelRegCache::Reg GetColorOff(const PixelFuncID &id);
- PixelRegCache::Reg GetDepthOff(const PixelFuncID &id);
- PixelRegCache::Reg GetDestStencil(const PixelFuncID &id);
+ RegCache::Reg GetColorOff(const PixelFuncID &id);
+ RegCache::Reg GetDepthOff(const PixelFuncID &id);
+ RegCache::Reg GetDestStencil(const PixelFuncID &id);
bool Jit_ApplyDepthRange(const PixelFuncID &id);
bool Jit_AlphaTest(const PixelFuncID &id);
bool Jit_ApplyFog(const PixelFuncID &id);
bool Jit_ColorTest(const PixelFuncID &id);
bool Jit_StencilAndDepthTest(const PixelFuncID &id);
- bool Jit_StencilTest(const PixelFuncID &id, PixelRegCache::Reg stencilReg, PixelRegCache::Reg maskedReg);
- bool Jit_DepthTestForStencil(const PixelFuncID &id, PixelRegCache::Reg stencilReg);
- bool Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, PixelRegCache::Reg stencilReg);
- bool Jit_WriteStencilOnly(const PixelFuncID &id, PixelRegCache::Reg stencilReg);
+ bool Jit_StencilTest(const PixelFuncID &id, RegCache::Reg stencilReg, RegCache::Reg maskedReg);
+ bool Jit_DepthTestForStencil(const PixelFuncID &id, RegCache::Reg stencilReg);
+ bool Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, RegCache::Reg stencilReg);
+ bool Jit_WriteStencilOnly(const PixelFuncID &id, RegCache::Reg stencilReg);
bool Jit_DepthTest(const PixelFuncID &id);
bool Jit_WriteDepth(const PixelFuncID &id);
bool Jit_AlphaBlend(const PixelFuncID &id);
- bool Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg factorReg, PixelRegCache::Reg dstReg, GEBlendSrcFactor factor);
- bool Jit_DstBlendFactor(const PixelFuncID &id, PixelRegCache::Reg srcFactorReg, PixelRegCache::Reg dstFactorReg, PixelRegCache::Reg dstReg);
+ bool Jit_BlendFactor(const PixelFuncID &id, RegCache::Reg factorReg, RegCache::Reg dstReg, GEBlendSrcFactor factor);
+ bool Jit_DstBlendFactor(const PixelFuncID &id, RegCache::Reg srcFactorReg, RegCache::Reg dstFactorReg, RegCache::Reg dstReg);
bool Jit_Dither(const PixelFuncID &id);
bool Jit_WriteColor(const PixelFuncID &id);
- bool Jit_ApplyLogicOp(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg maskReg);
- bool Jit_ConvertTo565(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg);
- bool Jit_ConvertTo5551(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha);
- bool Jit_ConvertTo4444(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha);
- bool Jit_ConvertFrom565(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg);
- bool Jit_ConvertFrom5551(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha);
- bool Jit_ConvertFrom4444(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha);
+ bool Jit_ApplyLogicOp(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg maskReg);
+ bool Jit_ConvertTo565(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg);
+ bool Jit_ConvertTo5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha);
+ bool Jit_ConvertTo4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha);
+ bool Jit_ConvertFrom565(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg);
+ bool Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha);
+ bool Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha);
std::unordered_map cache_;
std::unordered_map addresses_;
- PixelRegCache regCache_;
+ RegCache regCache_;
#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
void Discard();
@@ -195,6 +105,7 @@ private:
std::vector discards_;
// Used in Jit_ApplyLogicOp() to skip the standard MOV/OR write.
std::vector skipStandardWrites_;
+ int stackIDOffset_ = 0;
bool colorIs16Bit_ = false;
#endif
};
diff --git a/GPU/Software/DrawPixelX86.cpp b/GPU/Software/DrawPixelX86.cpp
index ad1ad8b25c..a4dd882a88 100644
--- a/GPU/Software/DrawPixelX86.cpp
+++ b/GPU/Software/DrawPixelX86.cpp
@@ -31,30 +31,6 @@ using namespace Gen;
namespace Rasterizer {
-#if PPSSPP_PLATFORM(WINDOWS)
-static const X64Reg argXReg = RCX;
-static const X64Reg argYReg = RDX;
-static const X64Reg argZReg = R8;
-static const X64Reg argFogReg = R9;
-static const X64Reg argColorReg = XMM4;
-
-// Windows reserves space to save args, 1 xmm + 4 ints before the id.
-static const OpArg mArgID = MDisp(RSP, 1 * 16 + 4 * PTRBITS / 8);
-
-// Must save: RBX, RSP, RBP, RDI, RSI, R12-R15, XMM6-15
-#else
-static const X64Reg argXReg = RDI;
-static const X64Reg argYReg = RSI;
-static const X64Reg argZReg = RDX;
-static const X64Reg argFogReg = RCX;
-static const X64Reg argColorReg = XMM0;
-
-// Here we just have the return and padding to align RPB.
-static const OpArg mArgID = MDisp(RSP, 16);
-
-// Must save: RBX, RSP, RBP, R12-R15
-#endif
-
// This one is the const base. Also a set of 255s.
alignas(16) static const uint16_t const255_16s[8] = { 255, 255, 255, 255, 255, 255, 255, 255 };
// This is used for a multiply that divides by 255 with shifting.
@@ -89,23 +65,52 @@ static OpArg MConstDisp(X64Reg r, const T *t) {
SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) {
// Setup the reg cache.
- regCache_.Reset();
- regCache_.Release(RAX, PixelRegCache::T_GEN);
- regCache_.Release(R10, PixelRegCache::T_GEN);
- regCache_.Release(R11, PixelRegCache::T_GEN);
- regCache_.Release(XMM1, PixelRegCache::T_VEC);
- regCache_.Release(XMM2, PixelRegCache::T_VEC);
- regCache_.Release(XMM3, PixelRegCache::T_VEC);
- regCache_.Release(XMM5, PixelRegCache::T_VEC);
+ regCache_.Add(RAX, RegCache::GEN_INVALID);
+ regCache_.Add(R10, RegCache::GEN_INVALID);
+ regCache_.Add(R11, RegCache::GEN_INVALID);
+ regCache_.Add(XMM1, RegCache::VEC_INVALID);
+ regCache_.Add(XMM2, RegCache::VEC_INVALID);
+ regCache_.Add(XMM3, RegCache::VEC_INVALID);
+ regCache_.Add(XMM5, RegCache::VEC_INVALID);
-#if !PPSSPP_PLATFORM(WINDOWS)
- regCache_.Release(R8, PixelRegCache::T_GEN);
- regCache_.Release(R9, PixelRegCache::T_GEN);
- regCache_.Release(XMM4, PixelRegCache::T_VEC);
+#if PPSSPP_PLATFORM(WINDOWS)
+ // Must save: RBX, RSP, RBP, RDI, RSI, R12-R15, XMM6-15
+
+ regCache_.Add(XMM0, RegCache::VEC_INVALID);
+
+ regCache_.Add(RCX, RegCache::GEN_ARG_X);
+ regCache_.Add(RDX, RegCache::GEN_ARG_Y);
+ regCache_.Add(R8, RegCache::GEN_ARG_Z);
+ regCache_.Add(R9, RegCache::GEN_ARG_FOG);
+ regCache_.Add(XMM4, RegCache::VEC_ARG_COLOR);
+
+ // Windows reserves space to save args, 1 xmm + 4 ints before the id.
+ stackIDOffset_ = 1 * 16 + 4 * PTRBITS / 8;
#else
- regCache_.Release(XMM0, PixelRegCache::T_VEC);
+ // Must save: RBX, RSP, RBP, R12-R15
+
+ regCache_.Add(R9, RegCache::GEN_INVALID);
+ regCache_.Add(XMM4, RegCache::VEC_INVALID);
+
+ regCache_.Add(RDI, RegCache::GEN_ARG_X);
+ regCache_.Add(RSI, RegCache::GEN_ARG_Y);
+ regCache_.Add(RDX, RegCache::GEN_ARG_Z);
+ regCache_.Add(RCX, RegCache::GEN_ARG_FOG);
+ regCache_.Add(XMM0, RegCache::VEC_ARG_COLOR);
+ regCache_.Add(R8, RegCache::GEN_ARG_ID);
+
+ stackIDOffset_ = -1;
#endif
+ // Initially, disallow spill for args (they get unlocked when no longer needed.)
+ regCache_.ForceRetain(RegCache::GEN_ARG_X);
+ regCache_.ForceRetain(RegCache::GEN_ARG_Y);
+ regCache_.ForceRetain(RegCache::GEN_ARG_Z);
+ regCache_.ForceRetain(RegCache::GEN_ARG_FOG);
+ regCache_.ForceRetain(RegCache::VEC_ARG_COLOR);
+ if (regCache_.Has(RegCache::GEN_ARG_ID))
+ regCache_.ForceRetain(RegCache::GEN_ARG_ID);
+
BeginWrite();
const u8 *start = AlignCode16();
bool success = true;
@@ -115,8 +120,10 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) {
// Next, let's clamp the color (might affect alpha test, and everything expects it clamped.)
// We simply convert to 4x8-bit to clamp. Everything else expects color in this format.
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
PACKSSDW(argColorReg, R(argColorReg));
PACKUSWB(argColorReg, R(argColorReg));
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
colorIs16Bit_ = false;
success = success && Jit_AlphaTest(id);
@@ -139,6 +146,10 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) {
}
discards_.clear();
+ if (regCache_.Has(RegCache::GEN_ARG_ID))
+ regCache_.ForceRelease(RegCache::GEN_ARG_ID);
+ regCache_.Reset(success);
+
if (!success) {
ERROR_LOG_REPORT(G3D, "Could not compile pixel func: %s", DescribePixelFuncID(id).c_str());
@@ -153,38 +164,40 @@ SingleFunc PixelJitCache::CompileSingle(const PixelFuncID &id) {
return (SingleFunc)start;
}
-PixelRegCache::Reg PixelJitCache::GetGState() {
- if (!regCache_.Has(PixelRegCache::GSTATE, PixelRegCache::T_GEN)) {
- X64Reg r = regCache_.Alloc(PixelRegCache::GSTATE, PixelRegCache::T_GEN);
+RegCache::Reg PixelJitCache::GetGState() {
+ if (!regCache_.Has(RegCache::GEN_GSTATE)) {
+ X64Reg r = regCache_.Alloc(RegCache::GEN_GSTATE);
MOV(PTRBITS, R(r), ImmPtr(&gstate.nop));
return r;
}
- return regCache_.Find(PixelRegCache::GSTATE, PixelRegCache::T_GEN);
+ return regCache_.Find(RegCache::GEN_GSTATE);
}
-PixelRegCache::Reg PixelJitCache::GetConstBase() {
- if (!regCache_.Has(PixelRegCache::CONST_BASE, PixelRegCache::T_GEN)) {
- X64Reg r = regCache_.Alloc(PixelRegCache::CONST_BASE, PixelRegCache::T_GEN);
+RegCache::Reg PixelJitCache::GetConstBase() {
+ if (!regCache_.Has(RegCache::GEN_CONST_BASE)) {
+ X64Reg r = regCache_.Alloc(RegCache::GEN_CONST_BASE);
MOV(PTRBITS, R(r), ImmPtr(&const255_16s[0]));
return r;
}
- return regCache_.Find(PixelRegCache::CONST_BASE, PixelRegCache::T_GEN);
+ return regCache_.Find(RegCache::GEN_CONST_BASE);
}
-PixelRegCache::Reg PixelJitCache::GetZeroVec() {
- if (!regCache_.Has(PixelRegCache::ZERO, PixelRegCache::T_VEC)) {
- X64Reg r = regCache_.Alloc(PixelRegCache::ZERO, PixelRegCache::T_VEC);
+RegCache::Reg PixelJitCache::GetZeroVec() {
+ if (!regCache_.Has(RegCache::VEC_ZERO)) {
+ X64Reg r = regCache_.Alloc(RegCache::VEC_ZERO);
PXOR(r, R(r));
return r;
}
- return regCache_.Find(PixelRegCache::ZERO, PixelRegCache::T_VEC);
+ return regCache_.Find(RegCache::VEC_ZERO);
}
-PixelRegCache::Reg PixelJitCache::GetColorOff(const PixelFuncID &id) {
- if (!regCache_.Has(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN)) {
+RegCache::Reg PixelJitCache::GetColorOff(const PixelFuncID &id) {
+ if (!regCache_.Has(RegCache::GEN_COLOR_OFF)) {
if (id.useStandardStride && !id.dithering) {
bool loadDepthOff = id.depthWrite || id.DepthTestFunc() != GE_COMP_ALWAYS;
X64Reg depthTemp = INVALID_REG;
+ X64Reg argYReg = regCache_.Find(RegCache::GEN_ARG_Y);
+ X64Reg argXReg = regCache_.Find(RegCache::GEN_ARG_X);
// In this mode, we force argXReg to the off, and throw away argYReg.
SHL(32, R(argYReg), Imm8(9));
@@ -193,7 +206,7 @@ PixelRegCache::Reg PixelJitCache::GetColorOff(const PixelFuncID &id) {
// Now add the pointer for the color buffer.
if (loadDepthOff) {
_assert_(Accessible(&fb.data, &depthbuf.data));
- depthTemp = regCache_.Alloc(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ depthTemp = regCache_.Alloc(RegCache::GEN_DEPTH_OFF);
MOV(PTRBITS, R(depthTemp), ImmPtr(&fb.data));
MOV(PTRBITS, R(argYReg), MatR(depthTemp));
} else {
@@ -201,100 +214,112 @@ PixelRegCache::Reg PixelJitCache::GetColorOff(const PixelFuncID &id) {
MOV(PTRBITS, R(argYReg), MatR(argYReg));
}
LEA(PTRBITS, argYReg, MComplex(argYReg, argXReg, id.FBFormat() == GE_FORMAT_8888 ? 4 : 2, 0));
- // With that, argYOff is now COLOR_OFF.
- regCache_.Release(argYReg, PixelRegCache::T_GEN, PixelRegCache::COLOR_OFF);
- // Lock it, because we can't recalculate this.
- regCache_.ForceLock(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ // With that, argYOff is now GEN_COLOR_OFF.
+ regCache_.Unlock(argYReg, RegCache::GEN_ARG_Y);
+ regCache_.Change(RegCache::GEN_ARG_Y, RegCache::GEN_COLOR_OFF);
+ // Retain it, because we can't recalculate this.
+ regCache_.ForceRetain(RegCache::GEN_COLOR_OFF);
// Next, also calculate the depth offset, unless we won't need it at all.
if (loadDepthOff) {
MOV(PTRBITS, R(depthTemp), MAccessibleDisp(depthTemp, &fb.data, &depthbuf.data));
LEA(PTRBITS, argXReg, MComplex(depthTemp, argXReg, 2, 0));
- regCache_.Release(depthTemp, PixelRegCache::T_GEN);
+ regCache_.Release(depthTemp, RegCache::GEN_DEPTH_OFF);
- // Okay, same deal - release as DEPTH_OFF and force lock.
- regCache_.Release(argXReg, PixelRegCache::T_GEN, PixelRegCache::DEPTH_OFF);
- regCache_.ForceLock(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ // Okay, same deal - release as GEN_DEPTH_OFF and force retain it.
+ regCache_.Unlock(argXReg, RegCache::GEN_ARG_X);
+ regCache_.Change(RegCache::GEN_ARG_X, RegCache::GEN_DEPTH_OFF);
+ regCache_.ForceRetain(RegCache::GEN_DEPTH_OFF);
} else {
- regCache_.Release(argXReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(argXReg, RegCache::GEN_ARG_X);
+ regCache_.ForceRelease(RegCache::GEN_ARG_X);
}
- return regCache_.Find(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ return regCache_.Find(RegCache::GEN_COLOR_OFF);
}
+ X64Reg argYReg = regCache_.Find(RegCache::GEN_ARG_Y);
X64Reg r;
if (id.useStandardStride) {
- r = regCache_.Alloc(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ r = regCache_.Alloc(RegCache::GEN_COLOR_OFF);
MOV(32, R(r), R(argYReg));
SHL(32, R(r), Imm8(9));
} else {
X64Reg gstateReg = GetGState();
- r = regCache_.Alloc(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ r = regCache_.Alloc(RegCache::GEN_COLOR_OFF);
MOVZX(32, 16, r, MDisp(gstateReg, offsetof(GPUgstate, fbwidth)));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
AND(16, R(r), Imm16(0x07FC));
IMUL(32, r, R(argYReg));
}
+ regCache_.Unlock(argYReg, RegCache::GEN_ARG_Y);
+ X64Reg argXReg = regCache_.Find(RegCache::GEN_ARG_X);
ADD(32, R(r), R(argXReg));
+ regCache_.Unlock(argXReg, RegCache::GEN_ARG_X);
- X64Reg temp = regCache_.Alloc(PixelRegCache::TEMP_HELPER, PixelRegCache::T_GEN);
+ X64Reg temp = regCache_.Alloc(RegCache::GEN_TEMP_HELPER);
MOV(PTRBITS, R(temp), ImmPtr(&fb.data));
MOV(PTRBITS, R(temp), MatR(temp));
LEA(PTRBITS, r, MComplex(temp, r, id.FBFormat() == GE_FORMAT_8888 ? 4 : 2, 0));
- regCache_.Release(temp, PixelRegCache::T_GEN);
+ regCache_.Release(temp, RegCache::GEN_TEMP_HELPER);
return r;
}
- return regCache_.Find(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ return regCache_.Find(RegCache::GEN_COLOR_OFF);
}
-PixelRegCache::Reg PixelJitCache::GetDepthOff(const PixelFuncID &id) {
- if (!regCache_.Has(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN)) {
+RegCache::Reg PixelJitCache::GetDepthOff(const PixelFuncID &id) {
+ if (!regCache_.Has(RegCache::GEN_DEPTH_OFF)) {
// If both color and depth use 512, the offsets are the same.
if (id.useStandardStride && !id.dithering) {
// Calculate once inside GetColorOff().
- regCache_.Unlock(GetColorOff(id), PixelRegCache::T_GEN);
- return regCache_.Find(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ X64Reg colorOffReg = GetColorOff(id);
+ regCache_.Unlock(colorOffReg, RegCache::GEN_COLOR_OFF);
+ return regCache_.Find(RegCache::GEN_DEPTH_OFF);
}
+ X64Reg argYReg = regCache_.Find(RegCache::GEN_ARG_Y);
X64Reg r;
if (id.useStandardStride) {
- r = regCache_.Alloc(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ r = regCache_.Alloc(RegCache::GEN_DEPTH_OFF);
MOV(32, R(r), R(argYReg));
SHL(32, R(r), Imm8(9));
} else {
X64Reg gstateReg = GetGState();
- r = regCache_.Alloc(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ r = regCache_.Alloc(RegCache::GEN_DEPTH_OFF);
MOVZX(32, 16, r, MDisp(gstateReg, offsetof(GPUgstate, zbwidth)));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
AND(16, R(r), Imm16(0x07FC));
IMUL(32, r, R(argYReg));
}
+ regCache_.Unlock(argYReg, RegCache::GEN_ARG_Y);
+ X64Reg argXReg = regCache_.Find(RegCache::GEN_ARG_X);
ADD(32, R(r), R(argXReg));
+ regCache_.Unlock(argXReg, RegCache::GEN_ARG_X);
- X64Reg temp = regCache_.Alloc(PixelRegCache::TEMP_HELPER, PixelRegCache::T_GEN);
+ X64Reg temp = regCache_.Alloc(RegCache::GEN_TEMP_HELPER);
MOV(PTRBITS, R(temp), ImmPtr(&depthbuf.data));
MOV(PTRBITS, R(temp), MatR(temp));
LEA(PTRBITS, r, MComplex(temp, r, 2, 0));
- regCache_.Release(temp, PixelRegCache::T_GEN);
+ regCache_.Release(temp, RegCache::GEN_TEMP_HELPER);
return r;
}
- return regCache_.Find(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN);
+ return regCache_.Find(RegCache::GEN_DEPTH_OFF);
}
-PixelRegCache::Reg PixelJitCache::GetDestStencil(const PixelFuncID &id) {
+RegCache::Reg PixelJitCache::GetDestStencil(const PixelFuncID &id) {
// Skip if 565, since stencil is fixed zero.
if (id.FBFormat() == GE_FORMAT_565)
return INVALID_REG;
X64Reg colorOffReg = GetColorOff(id);
- X64Reg stencilReg = regCache_.Alloc(PixelRegCache::STENCIL, PixelRegCache::T_GEN);
+ X64Reg stencilReg = regCache_.Alloc(RegCache::GEN_STENCIL);
if (id.FBFormat() == GE_FORMAT_8888) {
MOVZX(32, 8, stencilReg, MDisp(colorOffReg, 3));
} else if (id.FBFormat() == GE_FORMAT_5551) {
@@ -303,13 +328,13 @@ PixelRegCache::Reg PixelJitCache::GetDestStencil(const PixelFuncID &id) {
} else if (id.FBFormat() == GE_FORMAT_4444) {
MOVZX(32, 8, stencilReg, MDisp(colorOffReg, 1));
SHR(32, R(stencilReg), Imm8(4));
- X64Reg temp = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ X64Reg temp = regCache_.Alloc(RegCache::GEN_TEMP_HELPER);
MOV(32, R(temp), R(stencilReg));
SHL(32, R(temp), Imm8(4));
OR(32, R(stencilReg), R(temp));
- regCache_.Release(temp, PixelRegCache::T_GEN);
+ regCache_.Release(temp, RegCache::GEN_TEMP_HELPER);
}
- regCache_.Unlock(colorOffReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOffReg, RegCache::GEN_COLOR_OFF);
return stencilReg;
}
@@ -325,28 +350,30 @@ void PixelJitCache::Discard(Gen::CCFlags cc) {
bool PixelJitCache::Jit_ApplyDepthRange(const PixelFuncID &id) {
if (id.applyDepthRange) {
X64Reg gstateReg = GetGState();
- X64Reg minReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
- X64Reg maxReg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_GEN);
+ X64Reg minReg = regCache_.Alloc(RegCache::GEN_TEMP0);
+ X64Reg maxReg = regCache_.Alloc(RegCache::GEN_TEMP1);
// Only load the lowest 16 bits of each, but compare all 32 of z.
MOVZX(32, 16, minReg, MDisp(gstateReg, offsetof(GPUgstate, minz)));
MOVZX(32, 16, maxReg, MDisp(gstateReg, offsetof(GPUgstate, maxz)));
+ X64Reg argZReg = regCache_.Find(RegCache::GEN_ARG_Z);
CMP(32, R(argZReg), R(minReg));
Discard(CC_L);
CMP(32, R(argZReg), R(maxReg));
Discard(CC_G);
+ regCache_.Unlock(argZReg, RegCache::GEN_ARG_Z);
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
- regCache_.Release(minReg, PixelRegCache::T_GEN);
- regCache_.Release(maxReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
+ regCache_.Release(minReg, RegCache::GEN_TEMP0);
+ regCache_.Release(maxReg, RegCache::GEN_TEMP1);
}
// Since this is early on, try to free up the z reg if we don't need it anymore.
if (id.clearMode && !id.DepthClear())
- regCache_.Release(argZReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Z);
else if (!id.clearMode && !id.depthWrite && id.DepthTestFunc() == GE_COMP_ALWAYS)
- regCache_.Release(argZReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Z);
return true;
}
@@ -367,12 +394,14 @@ bool PixelJitCache::Jit_AlphaTest(const PixelFuncID &id) {
// Load alpha into its own general reg.
X64Reg alphaReg;
- if (regCache_.Has(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN)) {
- alphaReg = regCache_.Find(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_SRC_ALPHA)) {
+ alphaReg = regCache_.Find(RegCache::GEN_SRC_ALPHA);
} else {
- alphaReg = regCache_.Alloc(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN);
+ alphaReg = regCache_.Alloc(RegCache::GEN_SRC_ALPHA);
_assert_(!colorIs16Bit_);
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
MOVD_xmm(R(alphaReg), argColorReg);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
SHR(32, R(alphaReg), Imm8(24));
}
@@ -380,24 +409,24 @@ bool PixelJitCache::Jit_AlphaTest(const PixelFuncID &id) {
// Unfortunate, we'll need gstate to load the mask.
// Note: we leave the ALPHA purpose untouched and free it, because later code may reuse.
X64Reg gstateReg = GetGState();
- X64Reg maskedReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ X64Reg maskedReg = regCache_.Alloc(RegCache::GEN_TEMP0);
// The mask is >> 16, so we load + 2.
MOVZX(32, 8, maskedReg, MDisp(gstateReg, offsetof(GPUgstate, alphatest) + 2));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
AND(32, R(maskedReg), R(alphaReg));
- regCache_.Unlock(alphaReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(alphaReg, RegCache::GEN_SRC_ALPHA);
// Okay now do the rest using the masked reg, which we modified.
alphaReg = maskedReg;
- // Pre-emptively release, we don't need any other regs.
- regCache_.Release(maskedReg, PixelRegCache::T_GEN);
- } else {
- regCache_.Unlock(alphaReg, PixelRegCache::T_GEN);
}
// We hardcode the ref into this jit func.
CMP(8, R(alphaReg), Imm8(id.alphaTestRef));
+ if (id.hasAlphaTestMask)
+ regCache_.Release(alphaReg, RegCache::GEN_TEMP0);
+ else
+ regCache_.Unlock(alphaReg, RegCache::GEN_SRC_ALPHA);
switch (id.AlphaTestFunc()) {
case GE_COMP_NEVER:
@@ -438,9 +467,9 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
// We'll have 4 with fog released, so we're using them all...
X64Reg gstateReg = GetGState();
- X64Reg funcReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
- X64Reg maskReg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_GEN);
- X64Reg refReg = regCache_.Alloc(PixelRegCache::TEMP2, PixelRegCache::T_GEN);
+ X64Reg funcReg = regCache_.Alloc(RegCache::GEN_TEMP0);
+ X64Reg maskReg = regCache_.Alloc(RegCache::GEN_TEMP1);
+ X64Reg refReg = regCache_.Alloc(RegCache::GEN_TEMP2);
// First, load the registers: mask and ref.
MOV(32, R(maskReg), MDisp(gstateReg, offsetof(GPUgstate, colortestmask)));
@@ -448,6 +477,7 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
MOV(32, R(refReg), MDisp(gstateReg, offsetof(GPUgstate, colorref)));
AND(32, R(refReg), R(maskReg));
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
if (colorIs16Bit_) {
// If it's expanded, we need to clamp anyway if it was fogged.
PACKUSWB(argColorReg, R(argColorReg));
@@ -457,11 +487,12 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
// Temporarily abuse funcReg to grab the color into maskReg.
MOVD_xmm(R(funcReg), argColorReg);
AND(32, R(maskReg), R(funcReg));
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
// Now that we're setup, get the func and follow it.
MOVZX(32, 8, funcReg, MDisp(gstateReg, offsetof(GPUgstate, colortest)));
AND(8, R(funcReg), Imm8(3));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
CMP(8, R(funcReg), Imm8(GE_COMP_ALWAYS));
// Discard for GE_COMP_NEVER...
@@ -470,7 +501,7 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
CMP(8, R(funcReg), Imm8(GE_COMP_EQUAL));
FixupBranch doEqual = J_CC(CC_E);
- regCache_.Release(funcReg, PixelRegCache::T_GEN);
+ regCache_.Release(funcReg, RegCache::GEN_TEMP0);
// The not equal path here... if they are equal, we discard.
CMP(32, R(refReg), R(maskReg));
@@ -481,8 +512,8 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
CMP(32, R(refReg), R(maskReg));
Discard(CC_NE);
- regCache_.Release(maskReg, PixelRegCache::T_GEN);
- regCache_.Release(refReg, PixelRegCache::T_GEN);
+ regCache_.Release(maskReg, RegCache::GEN_TEMP1);
+ regCache_.Release(refReg, RegCache::GEN_TEMP2);
SetJumpTarget(skip);
SetJumpTarget(skip2);
@@ -493,58 +524,60 @@ bool PixelJitCache::Jit_ColorTest(const PixelFuncID &id) {
bool PixelJitCache::Jit_ApplyFog(const PixelFuncID &id) {
if (!id.applyFog) {
// Okay, anyone can use the fog register then.
- regCache_.Release(argFogReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_FOG);
return true;
}
// Load fog and expand to 16 bit. Ignore the high 8 bits, which'll match up with A.
- X64Reg fogColorReg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_VEC);
+ X64Reg fogColorReg = regCache_.Alloc(RegCache::VEC_TEMP1);
X64Reg gstateReg = GetGState();
if (cpu_info.bSSE4_1) {
- X64Reg gstateReg = GetGState();
// This actually loads the texlodslope too, but that's okay.
PMOVZXBW(fogColorReg, MDisp(gstateReg, offsetof(GPUgstate, fogcolor)));
} else {
X64Reg zeroReg = GetZeroVec();
MOVD_xmm(fogColorReg, MDisp(gstateReg, offsetof(GPUgstate, fogcolor)));
PUNPCKLBW(fogColorReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
// Load a set of 255s at 16 bit into a reg for later...
- X64Reg invertReg = regCache_.Alloc(PixelRegCache::TEMP2, PixelRegCache::T_VEC);
+ X64Reg invertReg = regCache_.Alloc(RegCache::VEC_TEMP2);
X64Reg constReg = GetConstBase();
MOVDQA(invertReg, MConstDisp(constReg, &const255_16s[0]));
- regCache_.Unlock(constReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(constReg, RegCache::GEN_CONST_BASE);
// Expand (we clamped) color to 16 bit as well, so we can multiply with fog.
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
if (!colorIs16Bit_) {
if (cpu_info.bSSE4_1) {
PMOVZXBW(argColorReg, R(argColorReg));
} else {
X64Reg zeroReg = GetZeroVec();
PUNPCKLBW(argColorReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
colorIs16Bit_ = true;
}
// Save A so we can put it back, we don't "fog" A.
X64Reg alphaReg;
- if (regCache_.Has(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN)) {
- alphaReg = regCache_.Find(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_SRC_ALPHA)) {
+ alphaReg = regCache_.Find(RegCache::GEN_SRC_ALPHA);
} else {
- alphaReg = regCache_.Alloc(PixelRegCache::SRC_ALPHA, PixelRegCache::T_GEN);
+ alphaReg = regCache_.Alloc(RegCache::GEN_SRC_ALPHA);
PEXTRW(alphaReg, argColorReg, 3);
}
// Okay, let's broadcast fog to an XMM.
- X64Reg fogMultReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ X64Reg fogMultReg = regCache_.Alloc(RegCache::VEC_TEMP3);
+ X64Reg argFogReg = regCache_.Find(RegCache::GEN_ARG_FOG);
MOVD_xmm(fogMultReg, R(argFogReg));
PSHUFLW(fogMultReg, R(fogMultReg), _MM_SHUFFLE(0, 0, 0, 0));
+ regCache_.Unlock(argFogReg, RegCache::GEN_ARG_FOG);
// We can free up the actual fog reg now.
- regCache_.Release(argFogReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_FOG);
// Now we multiply the existing color by fog...
PMULLW(argColorReg, R(fogMultReg));
@@ -553,22 +586,23 @@ bool PixelJitCache::Jit_ApplyFog(const PixelFuncID &id) {
PMULLW(fogColorReg, R(invertReg));
// At this point, argColorReg and fogColorReg are multiplied at 16-bit, so we need to sum.
PADDUSW(argColorReg, R(fogColorReg));
- regCache_.Release(fogColorReg, PixelRegCache::T_VEC);
- regCache_.Release(fogMultReg, PixelRegCache::T_VEC);
- regCache_.Release(invertReg, PixelRegCache::T_VEC);
+ regCache_.Release(fogColorReg, RegCache::VEC_TEMP1);
+ regCache_.Release(invertReg, RegCache::VEC_TEMP2);
+ regCache_.Release(fogMultReg, RegCache::VEC_TEMP3);
// Now to divide by 255, we use bit tricks: multiply by 0x8081, and shift right by 16+7.
constReg = GetConstBase();
PMULHUW(argColorReg, MConstDisp(constReg, &by255i));
- regCache_.Unlock(constReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(constReg, RegCache::GEN_CONST_BASE);
// Now shift right by 7 (PMULHUW already did 16 of the shift.)
PSRLW(argColorReg, 7);
// Okay, put A back in, we'll shrink it to 8888 when needed.
PINSRW(argColorReg, R(alphaReg), 3);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
- // We won't use alphaReg again, so toss it.
- regCache_.Release(alphaReg, PixelRegCache::T_GEN);
+ // We most likely won't use alphaReg again.
+ regCache_.Unlock(alphaReg, RegCache::GEN_SRC_ALPHA);
return true;
}
@@ -580,16 +614,16 @@ bool PixelJitCache::Jit_StencilAndDepthTest(const PixelFuncID &id) {
X64Reg maskedReg = stencilReg;
if (id.hasStencilTestMask) {
X64Reg gstateReg = GetGState();
- maskedReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ maskedReg = regCache_.Alloc(RegCache::GEN_TEMP0);
MOV(32, R(maskedReg), R(stencilReg));
AND(8, R(maskedReg), MDisp(gstateReg, offsetof(GPUgstate, stenciltest) + 2));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
}
bool success = true;
success = success && Jit_StencilTest(id, stencilReg, maskedReg);
if (maskedReg != stencilReg)
- regCache_.Unlock(maskedReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(maskedReg, RegCache::GEN_TEMP0);
// Next up, the depth test.
if (stencilReg == INVALID_REG) {
@@ -602,12 +636,12 @@ bool PixelJitCache::Jit_StencilAndDepthTest(const PixelFuncID &id) {
success = success && Jit_ApplyStencilOp(id, id.ZPass(), stencilReg);
// At this point, stencilReg can't be spilled. It contains the updated value.
- regCache_.ForceLock(PixelRegCache::STENCIL, PixelRegCache::T_GEN);
+ regCache_.ForceRetain(RegCache::GEN_STENCIL);
return success;
}
-bool PixelJitCache::Jit_StencilTest(const PixelFuncID &id, PixelRegCache::Reg stencilReg, PixelRegCache::Reg maskedReg) {
+bool PixelJitCache::Jit_StencilTest(const PixelFuncID &id, RegCache::Reg stencilReg, RegCache::Reg maskedReg) {
bool hasFixedResult = false;
bool fixedResult = false;
FixupBranch toPass;
@@ -683,13 +717,15 @@ bool PixelJitCache::Jit_StencilTest(const PixelFuncID &id, PixelRegCache::Reg st
return success;
}
-bool PixelJitCache::Jit_DepthTestForStencil(const PixelFuncID &id, PixelRegCache::Reg stencilReg) {
+bool PixelJitCache::Jit_DepthTestForStencil(const PixelFuncID &id, RegCache::Reg stencilReg) {
if (id.DepthTestFunc() == GE_COMP_ALWAYS)
return true;
X64Reg depthOffReg = GetDepthOff(id);
+ X64Reg argZReg = regCache_.Find(RegCache::GEN_ARG_Z);
CMP(16, R(argZReg), MatR(depthOffReg));
- regCache_.Unlock(depthOffReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(depthOffReg, RegCache::GEN_DEPTH_OFF);
+ regCache_.Unlock(argZReg, RegCache::GEN_ARG_Z);
// We discard the opposite of the passing test.
FixupBranch skip;
@@ -741,12 +777,12 @@ bool PixelJitCache::Jit_DepthTestForStencil(const PixelFuncID &id, PixelRegCache
// Like in Jit_DepthTest(), at this point we may not need this reg anymore.
if (!id.depthWrite)
- regCache_.Release(argZReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Z);
return success;
}
-bool PixelJitCache::Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, PixelRegCache::Reg stencilReg) {
+bool PixelJitCache::Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, RegCache::Reg stencilReg) {
_assert_(stencilReg != INVALID_REG);
FixupBranch skip;
@@ -764,7 +800,7 @@ bool PixelJitCache::Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, Pi
// Load the unmasked value.
X64Reg gstateReg = GetGState();
MOVZX(32, 8, stencilReg, MDisp(gstateReg, offsetof(GPUgstate, stenciltest) + 1));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
} else {
MOV(8, R(stencilReg), Imm8(id.stencilTestRef));
}
@@ -828,14 +864,14 @@ bool PixelJitCache::Jit_ApplyStencilOp(const PixelFuncID &id, GEStencilOp op, Pi
return true;
}
-bool PixelJitCache::Jit_WriteStencilOnly(const PixelFuncID &id, PixelRegCache::Reg stencilReg) {
+bool PixelJitCache::Jit_WriteStencilOnly(const PixelFuncID &id, RegCache::Reg stencilReg) {
_assert_(stencilReg != INVALID_REG);
// It's okay to destory stencilReg here, we know we're the last writing it.
X64Reg colorOffReg = GetColorOff(id);
if (id.applyColorWriteMask) {
X64Reg gstateReg = GetGState();
- X64Reg maskReg = regCache_.Alloc(PixelRegCache::TEMP5, PixelRegCache::T_GEN);
+ X64Reg maskReg = regCache_.Alloc(RegCache::GEN_TEMP5);
switch (id.fbFormat) {
case GE_FORMAT_565:
@@ -880,8 +916,8 @@ bool PixelJitCache::Jit_WriteStencilOnly(const PixelFuncID &id, PixelRegCache::R
break;
}
- regCache_.Release(maskReg, PixelRegCache::T_GEN);
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Release(maskReg, RegCache::GEN_TEMP5);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
} else {
switch (id.fbFormat) {
case GE_FORMAT_565:
@@ -905,7 +941,7 @@ bool PixelJitCache::Jit_WriteStencilOnly(const PixelFuncID &id, PixelRegCache::R
}
}
- regCache_.Unlock(colorOffReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOffReg, RegCache::GEN_COLOR_OFF);
return true;
}
@@ -919,8 +955,10 @@ bool PixelJitCache::Jit_DepthTest(const PixelFuncID &id) {
}
X64Reg depthOffReg = GetDepthOff(id);
+ X64Reg argZReg = regCache_.Find(RegCache::GEN_ARG_Z);
CMP(16, R(argZReg), MatR(depthOffReg));
- regCache_.Unlock(depthOffReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(depthOffReg, RegCache::GEN_DEPTH_OFF);
+ regCache_.Unlock(argZReg, RegCache::GEN_ARG_Z);
// We discard the opposite of the passing test.
switch (id.DepthTestFunc()) {
@@ -953,9 +991,9 @@ bool PixelJitCache::Jit_DepthTest(const PixelFuncID &id) {
break;
}
- // If we're not writing, we don't need Z anymore. We'll free DEPTH_OFF in Jit_WriteDepth().
+ // If we're not writing, we don't need Z anymore. We'll free GEN_DEPTH_OFF in Jit_WriteDepth().
if (!id.depthWrite)
- regCache_.Release(argZReg, PixelRegCache::T_GEN);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Z);
return true;
}
@@ -964,14 +1002,16 @@ bool PixelJitCache::Jit_WriteDepth(const PixelFuncID &id) {
// Clear mode shares depthWrite for DepthClear().
if (id.depthWrite) {
X64Reg depthOffReg = GetDepthOff(id);
+ X64Reg argZReg = regCache_.Find(RegCache::GEN_ARG_Z);
MOV(16, MatR(depthOffReg), R(argZReg));
- regCache_.Unlock(depthOffReg, PixelRegCache::T_GEN);
- regCache_.Release(argZReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(depthOffReg, RegCache::GEN_DEPTH_OFF);
+ regCache_.Unlock(argZReg, RegCache::GEN_ARG_Z);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Z);
}
// We can free up this reg if we force locked it.
- if (regCache_.Has(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN)) {
- regCache_.ForceLock(PixelRegCache::DEPTH_OFF, PixelRegCache::T_GEN, false);
+ if (regCache_.Has(RegCache::GEN_DEPTH_OFF)) {
+ regCache_.ForceRelease(RegCache::GEN_DEPTH_OFF);
}
return true;
@@ -988,18 +1028,19 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
bool success = true;
// Step 1: Load and expand dest color.
- X64Reg dstReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_VEC);
- X64Reg colorOff = GetColorOff(id);
+ X64Reg dstReg = regCache_.Alloc(RegCache::VEC_TEMP0);
if (id.FBFormat() == GE_FORMAT_8888) {
+ X64Reg colorOff = GetColorOff(id);
MOVD_xmm(dstReg, MatR(colorOff));
- regCache_.Unlock(colorOff, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOff, RegCache::GEN_COLOR_OFF);
} else {
- X64Reg dstGenReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ X64Reg colorOff = GetColorOff(id);
+ X64Reg dstGenReg = regCache_.Alloc(RegCache::GEN_TEMP0);
MOVZX(32, 16, dstGenReg, MatR(colorOff));
- regCache_.Unlock(colorOff, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOff, RegCache::GEN_COLOR_OFF);
- X64Reg temp1Reg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_GEN);
- X64Reg temp2Reg = regCache_.Alloc(PixelRegCache::TEMP2, PixelRegCache::T_GEN);
+ X64Reg temp1Reg = regCache_.Alloc(RegCache::GEN_TEMP1);
+ X64Reg temp2Reg = regCache_.Alloc(RegCache::GEN_TEMP2);
switch (id.fbFormat) {
case GE_FORMAT_565:
@@ -1021,15 +1062,16 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
MOVD_xmm(dstReg, R(dstGenReg));
- regCache_.Release(temp1Reg, PixelRegCache::T_GEN);
- regCache_.Release(temp2Reg, PixelRegCache::T_GEN);
- regCache_.Release(dstGenReg, PixelRegCache::T_GEN);
+ regCache_.Release(dstGenReg, RegCache::GEN_TEMP0);
+ regCache_.Release(temp1Reg, RegCache::GEN_TEMP1);
+ regCache_.Release(temp2Reg, RegCache::GEN_TEMP2);
}
// Step 2: Load and apply factors.
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
if (blendState.usesFactors) {
- X64Reg srcFactorReg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_VEC);
- X64Reg dstFactorReg = regCache_.Alloc(PixelRegCache::TEMP2, PixelRegCache::T_VEC);
+ X64Reg srcFactorReg = regCache_.Alloc(RegCache::VEC_TEMP1);
+ X64Reg dstFactorReg = regCache_.Alloc(RegCache::VEC_TEMP2);
// We apply these at 16-bit, because they can be doubled and have a half offset.
if (cpu_info.bSSE4_1) {
@@ -1041,7 +1083,7 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
if (!colorIs16Bit_)
PUNPCKLBW(argColorReg, R(zeroReg));
PUNPCKLBW(dstReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
colorIs16Bit_ = true;
@@ -1055,10 +1097,10 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
success = success && Jit_DstBlendFactor(id, srcFactorReg, dstFactorReg, dstReg);
X64Reg constReg = GetConstBase();
- X64Reg halfReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ X64Reg halfReg = regCache_.Alloc(RegCache::VEC_TEMP3);
// We'll use this several times, so load into a reg.
MOVDQA(halfReg, MConstDisp(constReg, &blendHalf_11_4s[0]));
- regCache_.Unlock(constReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(constReg, RegCache::GEN_CONST_BASE);
// Add in the half bit to the factors and color values, then multiply.
// We take the high 16 bits to get a free right shift by 16.
@@ -1070,9 +1112,9 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
POR(dstReg, R(halfReg));
PMULHUW(dstReg, R(dstFactorReg));
- regCache_.Release(halfReg, PixelRegCache::T_VEC);
- regCache_.Release(srcFactorReg, PixelRegCache::T_VEC);
- regCache_.Release(dstFactorReg, PixelRegCache::T_VEC);
+ regCache_.Release(srcFactorReg, RegCache::VEC_TEMP1);
+ regCache_.Release(dstFactorReg, RegCache::VEC_TEMP2);
+ regCache_.Release(halfReg, RegCache::VEC_TEMP3);
} else if (colorIs16Bit_) {
// If it's expanded, shrink and clamp for our min/max/absdiff handling.
PACKUSWB(argColorReg, R(argColorReg));
@@ -1082,7 +1124,7 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
// Step 3: Apply equation.
// Note: below, we completely ignore what happens to the alpha bits.
// It won't matter, since we'll replace those with stencil anyway.
- X64Reg tempReg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_VEC);
+ X64Reg tempReg = regCache_.Alloc(RegCache::VEC_TEMP1);
switch (id.AlphaBlendEq()) {
case GE_BLENDMODE_MUL_AND_ADD:
PADDUSW(argColorReg, R(dstReg));
@@ -1117,17 +1159,19 @@ bool PixelJitCache::Jit_AlphaBlend(const PixelFuncID &id) {
break;
}
- regCache_.Release(tempReg, PixelRegCache::T_VEC);
- regCache_.Release(dstReg, PixelRegCache::T_VEC);
+ regCache_.Release(dstReg, RegCache::VEC_TEMP0);
+ regCache_.Release(tempReg, RegCache::VEC_TEMP1);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
return success;
}
-bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg factorReg, PixelRegCache::Reg dstReg, GEBlendSrcFactor factor) {
+bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, RegCache::Reg factorReg, RegCache::Reg dstReg, GEBlendSrcFactor factor) {
X64Reg constReg = INVALID_REG;
X64Reg gstateReg = INVALID_REG;
X64Reg tempReg = INVALID_REG;
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
// Everything below expects an expanded 16-bit color
_assert_(colorIs16Bit_);
@@ -1152,7 +1196,7 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
case GE_SRCBLEND_INVSRCALPHA:
constReg = GetConstBase();
- tempReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ tempReg = regCache_.Alloc(RegCache::VEC_TEMP3);
MOVDQA(factorReg, MConstDisp(constReg, &blendInvert_11_4s[0]));
PSHUFLW(tempReg, R(argColorReg), _MM_SHUFFLE(3, 3, 3, 3));
@@ -1165,7 +1209,7 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
case GE_SRCBLEND_INVDSTALPHA:
constReg = GetConstBase();
- tempReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ tempReg = regCache_.Alloc(RegCache::VEC_TEMP3);
MOVDQA(factorReg, MConstDisp(constReg, &blendInvert_11_4s[0]));
PSHUFLW(tempReg, R(dstReg), _MM_SHUFFLE(3, 3, 3, 3));
@@ -1179,7 +1223,7 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
case GE_SRCBLEND_DOUBLEINVSRCALPHA:
constReg = GetConstBase();
- tempReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ tempReg = regCache_.Alloc(RegCache::VEC_TEMP3);
MOVDQA(factorReg, MConstDisp(constReg, &blendInvert_11_4s[0]));
PSHUFLW(tempReg, R(argColorReg), _MM_SHUFFLE(3, 3, 3, 3));
@@ -1194,7 +1238,7 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
case GE_SRCBLEND_DOUBLEINVDSTALPHA:
constReg = GetConstBase();
- tempReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_VEC);
+ tempReg = regCache_.Alloc(RegCache::VEC_TEMP3);
MOVDQA(factorReg, MConstDisp(constReg, &blendInvert_11_4s[0]));
PSHUFLW(tempReg, R(dstReg), _MM_SHUFFLE(3, 3, 3, 3));
@@ -1211,7 +1255,7 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
} else {
X64Reg zeroReg = GetZeroVec();
PUNPCKLBW(factorReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
// Round it out by shifting into place.
PSLLW(factorReg, 4);
@@ -1219,19 +1263,21 @@ bool PixelJitCache::Jit_BlendFactor(const PixelFuncID &id, PixelRegCache::Reg fa
}
if (constReg != INVALID_REG)
- regCache_.Unlock(constReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(constReg, RegCache::GEN_CONST_BASE);
if (gstateReg != INVALID_REG)
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
if (tempReg != INVALID_REG)
- regCache_.Release(tempReg, PixelRegCache::T_VEC);
+ regCache_.Release(tempReg, RegCache::VEC_TEMP3);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
return true;
}
-bool PixelJitCache::Jit_DstBlendFactor(const PixelFuncID &id, PixelRegCache::Reg srcFactorReg, PixelRegCache::Reg dstFactorReg, PixelRegCache::Reg dstReg) {
+bool PixelJitCache::Jit_DstBlendFactor(const PixelFuncID &id, RegCache::Reg srcFactorReg, RegCache::Reg dstFactorReg, RegCache::Reg dstReg) {
bool success = true;
X64Reg constReg = INVALID_REG;
X64Reg gstateReg = INVALID_REG;
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
// Everything below expects an expanded 16-bit color
_assert_(colorIs16Bit_);
@@ -1280,7 +1326,7 @@ bool PixelJitCache::Jit_DstBlendFactor(const PixelFuncID &id, PixelRegCache::Reg
} else {
X64Reg zeroReg = GetZeroVec();
PUNPCKLBW(dstFactorReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
// Round it out by shifting into place.
PSLLW(dstFactorReg, 4);
@@ -1288,9 +1334,10 @@ bool PixelJitCache::Jit_DstBlendFactor(const PixelFuncID &id, PixelRegCache::Reg
}
if (constReg != INVALID_REG)
- regCache_.Unlock(constReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(constReg, RegCache::GEN_CONST_BASE);
if (gstateReg != INVALID_REG)
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
return success;
}
@@ -1302,39 +1349,50 @@ bool PixelJitCache::Jit_Dither(const PixelFuncID &id) {
#ifndef SOFTPIXEL_USE_CACHE
X64Reg gstateReg = GetGState();
#endif
- X64Reg valueReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ X64Reg valueReg = regCache_.Alloc(RegCache::GEN_TEMP0);
// Load the row dither matrix entry (will still need to get the X.)
+ X64Reg argYReg = regCache_.Find(RegCache::GEN_ARG_Y);
MOV(32, R(valueReg), R(argYReg));
AND(32, R(valueReg), Imm8(3));
#ifndef SOFTPIXEL_USE_CACHE
MOVZX(32, 16, valueReg, MComplex(gstateReg, valueReg, 4, offsetof(GPUgstate, dithmtx)));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
#endif
- // At this point, we're done with depth and y, so let's grab COLOR_OFF and lock it.
+ // At this point, we're done with depth and y, so let's grab GEN_COLOR_OFF and retain it.
// Then we can modify x and throw it away too, which is our actual goal.
- regCache_.Unlock(GetColorOff(id), PixelRegCache::T_GEN);
- regCache_.ForceLock(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
- regCache_.Release(argYReg, PixelRegCache::T_GEN);
+ X64Reg colorOffReg = GetColorOff(id);
+ regCache_.Unlock(colorOffReg, RegCache::GEN_COLOR_OFF);
+ regCache_.ForceRetain(RegCache::GEN_COLOR_OFF);
+ // And get rid of y, we can use for other regs.
+ regCache_.Unlock(argYReg, RegCache::GEN_ARG_Y);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Y);
+ X64Reg argXReg = regCache_.Find(RegCache::GEN_ARG_X);
AND(32, R(argXReg), Imm32(3));
#ifndef SOFTPIXEL_USE_CACHE
SHL(32, R(argXReg), Imm8(2));
// Conveniently, this is ECX on Windows, but otherwise we need to swap it.
+ X64Reg shiftReg = INVALID_REG;
if (argXReg != RCX) {
bool needsSwap = false;
- regCache_.GrabReg(RCX, PixelRegCache::TEMP1, PixelRegCache::T_GEN, needsSwap, argXReg);
+ // This will force release argXReg if swapped.
+ regCache_.GrabReg(RCX, RegCache::GEN_TEMP1, needsSwap, argXReg, RegCache::GEN_ARG_X);
+ shiftReg = RCX;
if (needsSwap) {
XCHG(PTRBITS, R(argXReg), R(RCX));
if (valueReg == RCX)
valueReg = argXReg;
+
+ // At this point, argXReg is some other unknown reg... basically, it's released.
+ argXReg = INVALID_REG;
} else {
+ // We'll unlock and force release argXReg later, but copy for now.
MOV(32, R(RCX), R(argXReg));
- regCache_.Release(argXReg, PixelRegCache::T_GEN);
}
}
@@ -1342,8 +1400,9 @@ bool PixelJitCache::Jit_Dither(const PixelFuncID &id) {
SHR(32, R(valueReg), R(CL));
AND(16, R(valueReg), Imm16(0x000F));
- // This will either be argXReg on Windows, or RCX we explicitly grabbed.
- regCache_.Release(RCX, PixelRegCache::T_GEN);
+ // Release RCX if we explicitly grabbed.
+ if (shiftReg != INVALID_REG)
+ regCache_.Release(shiftReg, RegCache::GEN_TEMP1);
// Now we need to make 0-7 positive, 8-F negative.. so sign extend.
SHL(32, R(valueReg), Imm8(4));
@@ -1355,48 +1414,65 @@ bool PixelJitCache::Jit_Dither(const PixelFuncID &id) {
LEA(32, valueReg, MComplex(argXReg, valueReg, 8, offsetof(PixelFuncID, cached.ditherMatrix)));
// Okay, now abuse argXReg to read the PixelFuncID pointer on the stack.
- MOV(PTRBITS, R(argXReg), mArgID);
- MOVSX(32, 16, valueReg, MRegSum(argXReg, valueReg));
- regCache_.Release(argXReg, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_ARG_ID)) {
+ X64Reg idReg = regCache_.Find(RegCache::GEN_ARG_ID);
+ MOVSX(32, 16, valueReg, MRegSum(idReg, valueReg));
+ regCache_.Unlock(idReg, RegCache::GEN_ARG_ID);
+ } else {
+ _assert_(stackIDOffset_ != -1);
+ MOV(PTRBITS, R(argXReg), MDisp(RSP, stackIDOffset_));
+ MOVSX(32, 16, valueReg, MRegSum(argXReg, valueReg));
+ }
#endif
+ if (argXReg != INVALID_REG) {
+ regCache_.Unlock(argXReg, RegCache::GEN_ARG_X);
+ regCache_.ForceRelease(RegCache::GEN_ARG_X);
+ }
// Copy that value into a vec to add to the color.
- X64Reg vecValueReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_VEC);
+ X64Reg vecValueReg = regCache_.Alloc(RegCache::VEC_TEMP0);
MOVD_xmm(vecValueReg, R(valueReg));
- regCache_.Release(valueReg, PixelRegCache::T_GEN);
+ regCache_.Release(valueReg, RegCache::GEN_TEMP0);
// Now we want to broadcast RGB in 16-bit, but keep A as 0.
// Luckily, we know that second lane (in 16-bit) is zero from valueReg's high 16 bits.
// We use 16-bit because we need a signed add, but we also want to saturate.
PSHUFLW(vecValueReg, R(vecValueReg), _MM_SHUFFLE(1, 0, 0, 0));
+
// With that, now let's convert the color to 16 bit...
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
if (!colorIs16Bit_) {
if (cpu_info.bSSE4_1) {
PMOVZXBW(argColorReg, R(argColorReg));
} else {
X64Reg zeroReg = GetZeroVec();
PUNPCKLBW(argColorReg, R(zeroReg));
- regCache_.Unlock(zeroReg, PixelRegCache::T_VEC);
+ regCache_.Unlock(zeroReg, RegCache::VEC_ZERO);
}
colorIs16Bit_ = true;
}
// And simply add the dither values.
PADDSW(argColorReg, R(vecValueReg));
- regCache_.Release(vecValueReg, PixelRegCache::T_VEC);
+ regCache_.Release(vecValueReg, RegCache::VEC_TEMP0);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
return true;
}
bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
X64Reg colorOff = GetColorOff(id);
- if (!id.useStandardStride && !id.dithering) {
- // We won't need X or Y anymore, so toss them for reg space.
- regCache_.Release(argXReg, PixelRegCache::T_GEN);
- regCache_.Release(argYReg, PixelRegCache::T_GEN);
- regCache_.ForceLock(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_ARG_X)) {
+ // We normally toss x and y during dithering or useStandardStride with no dithering.
+ // Free up the regs now to get more reg space.
+ regCache_.ForceRelease(RegCache::GEN_ARG_X);
+ regCache_.ForceRelease(RegCache::GEN_ARG_Y);
+
+ // But make sure we don't lose GEN_COLOR_OFF, we'll be lost without that now.
+ regCache_.ForceRetain(RegCache::GEN_COLOR_OFF);
}
// Convert back to 8888 and clamp.
+ X64Reg argColorReg = regCache_.Find(RegCache::VEC_ARG_COLOR);
if (colorIs16Bit_) {
PACKUSWB(argColorReg, R(argColorReg));
colorIs16Bit_ = false;
@@ -1410,27 +1486,35 @@ bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
if (!id.ColorClear()) {
// Let's reuse Jit_WriteStencilOnly for this path.
- X64Reg alphaReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
- MOVD_xmm(R(alphaReg), argColorReg);
- SHR(32, R(alphaReg), Imm8(24));
+ X64Reg alphaReg;
+ if (regCache_.Has(RegCache::GEN_SRC_ALPHA)) {
+ alphaReg = regCache_.Find(RegCache::GEN_SRC_ALPHA);
+ } else {
+ alphaReg = regCache_.Alloc(RegCache::GEN_SRC_ALPHA);
+ MOVD_xmm(R(alphaReg), argColorReg);
+ SHR(32, R(alphaReg), Imm8(24));
+ }
bool success = Jit_WriteStencilOnly(id, alphaReg);
- regCache_.Release(alphaReg, PixelRegCache::T_GEN);
+ regCache_.Release(alphaReg, RegCache::GEN_SRC_ALPHA);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
return success;
}
// In this case, we're clearing only color or only color and stencil. Proceed.
}
- X64Reg colorReg = regCache_.Alloc(PixelRegCache::TEMP0, PixelRegCache::T_GEN);
+ X64Reg colorReg = regCache_.Alloc(RegCache::GEN_TEMP0);
MOVD_xmm(R(colorReg), argColorReg);
+ regCache_.Unlock(argColorReg, RegCache::VEC_ARG_COLOR);
+ regCache_.ForceRelease(RegCache::VEC_ARG_COLOR);
X64Reg stencilReg = INVALID_REG;
- if (regCache_.Has(PixelRegCache::STENCIL, PixelRegCache::T_GEN))
- stencilReg = regCache_.Find(PixelRegCache::STENCIL, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_STENCIL))
+ stencilReg = regCache_.Find(RegCache::GEN_STENCIL);
- X64Reg temp1Reg = regCache_.Alloc(PixelRegCache::TEMP1, PixelRegCache::T_GEN);
- X64Reg temp2Reg = regCache_.Alloc(PixelRegCache::TEMP2, PixelRegCache::T_GEN);
+ X64Reg temp1Reg = regCache_.Alloc(RegCache::GEN_TEMP1);
+ X64Reg temp2Reg = regCache_.Alloc(RegCache::GEN_TEMP2);
bool convertAlpha = id.clearMode && id.StencilClear();
bool writeAlpha = convertAlpha || stencilReg != INVALID_REG;
uint32_t fixedKeepMask = 0x00000000;
@@ -1485,7 +1569,7 @@ bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
if (id.applyColorWriteMask) {
#ifndef SOFTPIXEL_USE_CACHE
X64Reg gstateReg = GetGState();
- maskReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_GEN);
+ maskReg = regCache_.Alloc(RegCache::GEN_TEMP3);
// Load the write mask, combine in the stencil/alpha mask bits.
MOV(32, R(maskReg), MDisp(gstateReg, offsetof(GPUgstate, pmskc)));
@@ -1494,7 +1578,7 @@ bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
SHL(32, R(temp2Reg), Imm8(24));
OR(32, R(maskReg), R(temp2Reg));
}
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
// Switch the mask into the specified bit depth. This is easier.
switch (id.fbFormat) {
@@ -1520,16 +1604,22 @@ bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
break;
}
#else
- maskReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_GEN);
+ maskReg = regCache_.Alloc(RegCache::GEN_TEMP3);
// Load the pre-converted and combined write mask.
- MOV(PTRBITS, R(maskReg), mArgID);
- MOV(32, R(maskReg), MDisp(maskReg, offsetof(PixelFuncID, cached.colorWriteMask)));
+ if (regCache_.Has(RegCache::GEN_ARG_ID)) {
+ X64Reg idReg = regCache_.Find(RegCache::GEN_ARG_ID);
+ MOV(32, R(maskReg), MDisp(idReg, offsetof(PixelFuncID, cached.colorWriteMask)));
+ regCache_.Unlock(idReg, RegCache::GEN_ARG_ID);
+ } else {
+ _assert_(stackIDOffset_ != -1);
+ MOV(PTRBITS, R(maskReg), MDisp(RSP, stackIDOffset_));
+ MOV(32, R(maskReg), MDisp(maskReg, offsetof(PixelFuncID, cached.colorWriteMask)));
+ }
#endif
}
// We've run out of regs, let's live without temp2 from here on.
- regCache_.Release(temp2Reg, PixelRegCache::T_GEN);
- temp2Reg = INVALID_REG;
+ regCache_.Release(temp2Reg, RegCache::GEN_TEMP2);
// Step 3: Apply logic op, combine stencil.
skipStandardWrites_.clear();
@@ -1586,36 +1676,34 @@ bool PixelJitCache::Jit_WriteColor(const PixelFuncID &id) {
SetJumpTarget(fixup);
skipStandardWrites_.clear();
- regCache_.Unlock(colorOff, PixelRegCache::T_GEN);
- regCache_.Release(colorReg, PixelRegCache::T_GEN);
- regCache_.Release(temp1Reg, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOff, RegCache::GEN_COLOR_OFF);
+ regCache_.ForceRelease(RegCache::GEN_COLOR_OFF);
+ regCache_.Release(colorReg, RegCache::GEN_TEMP0);
+ regCache_.Release(temp1Reg, RegCache::GEN_TEMP1);
if (maskReg != INVALID_REG)
- regCache_.Release(maskReg, PixelRegCache::T_GEN);
+ regCache_.Release(maskReg, RegCache::GEN_TEMP3);
if (stencilReg != INVALID_REG) {
- regCache_.ForceLock(PixelRegCache::STENCIL, PixelRegCache::T_GEN, false);
- regCache_.Release(stencilReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(stencilReg, RegCache::GEN_STENCIL);
+ regCache_.ForceRelease(RegCache::GEN_STENCIL);
}
return success;
}
-bool PixelJitCache::Jit_ApplyLogicOp(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg maskReg) {
- X64Reg logicOpReg = INVALID_REG;
- if (id.applyLogicOp) {
- X64Reg gstateReg = GetGState();
- logicOpReg = regCache_.Alloc(PixelRegCache::TEMP3, PixelRegCache::T_GEN);
- MOVZX(32, 8, logicOpReg, MDisp(gstateReg, offsetof(GPUgstate, lop)));
- AND(8, R(logicOpReg), Imm8(0x0F));
- regCache_.Unlock(gstateReg, PixelRegCache::T_GEN);
- }
+bool PixelJitCache::Jit_ApplyLogicOp(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg maskReg) {
+ X64Reg gstateReg = GetGState();
+ X64Reg logicOpReg = regCache_.Alloc(RegCache::GEN_TEMP3);
+ MOVZX(32, 8, logicOpReg, MDisp(gstateReg, offsetof(GPUgstate, lop)));
+ AND(8, R(logicOpReg), Imm8(0x0F));
+ regCache_.Unlock(gstateReg, RegCache::GEN_GSTATE);
X64Reg stencilReg = INVALID_REG;
- if (regCache_.Has(PixelRegCache::STENCIL, PixelRegCache::T_GEN))
- stencilReg = regCache_.Find(PixelRegCache::STENCIL, PixelRegCache::T_GEN);
+ if (regCache_.Has(RegCache::GEN_STENCIL))
+ stencilReg = regCache_.Find(RegCache::GEN_STENCIL);
// Should already be allocated.
- X64Reg colorOff = regCache_.Find(PixelRegCache::COLOR_OFF, PixelRegCache::T_GEN);
- X64Reg temp1Reg = regCache_.Find(PixelRegCache::TEMP1, PixelRegCache::T_GEN);
+ X64Reg colorOff = regCache_.Find(RegCache::GEN_COLOR_OFF);
+ X64Reg temp1Reg = regCache_.Find(RegCache::GEN_TEMP1);
// We'll use these in several cases, so prepare.
int bits = id.fbFormat == GE_FORMAT_8888 ? 32 : 16;
@@ -1934,15 +2022,16 @@ bool PixelJitCache::Jit_ApplyLogicOp(const PixelFuncID &id, PixelRegCache::Reg c
for (FixupBranch &fixup : finishes)
SetJumpTarget(fixup);
- regCache_.Unlock(colorOff, PixelRegCache::T_GEN);
- regCache_.Unlock(temp1Reg, PixelRegCache::T_GEN);
+ regCache_.Unlock(colorOff, RegCache::GEN_COLOR_OFF);
+ regCache_.Unlock(temp1Reg, RegCache::GEN_TEMP1);
+ regCache_.Unlock(logicOpReg, RegCache::GEN_TEMP3);
if (stencilReg != INVALID_REG)
- regCache_.Unlock(stencilReg, PixelRegCache::T_GEN);
+ regCache_.Unlock(stencilReg, RegCache::GEN_STENCIL);
return true;
}
-bool PixelJitCache::Jit_ConvertTo565(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg) {
+bool PixelJitCache::Jit_ConvertTo565(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg) {
// Assemble the 565 color, starting with R...
MOV(32, R(temp1Reg), R(colorReg));
SHR(32, R(temp1Reg), Imm8(3));
@@ -1962,7 +2051,7 @@ bool PixelJitCache::Jit_ConvertTo565(const PixelFuncID &id, PixelRegCache::Reg c
return true;
}
-bool PixelJitCache::Jit_ConvertTo5551(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha) {
+bool PixelJitCache::Jit_ConvertTo5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha) {
// This is R, pretty simple.
MOV(32, R(temp1Reg), R(colorReg));
SHR(32, R(temp1Reg), Imm8(3));
@@ -1992,7 +2081,7 @@ bool PixelJitCache::Jit_ConvertTo5551(const PixelFuncID &id, PixelRegCache::Reg
return true;
}
-bool PixelJitCache::Jit_ConvertTo4444(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha) {
+bool PixelJitCache::Jit_ConvertTo4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha) {
// Shift and mask out R.
MOV(32, R(temp1Reg), R(colorReg));
SHR(32, R(temp1Reg), Imm8(4));
@@ -2022,7 +2111,7 @@ bool PixelJitCache::Jit_ConvertTo4444(const PixelFuncID &id, PixelRegCache::Reg
return true;
}
-bool PixelJitCache::Jit_ConvertFrom565(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg) {
+bool PixelJitCache::Jit_ConvertFrom565(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg) {
// Filter out red only into temp1.
MOV(32, R(temp1Reg), R(colorReg));
AND(16, R(temp1Reg), Imm16(0x1F << 0));
@@ -2056,7 +2145,7 @@ bool PixelJitCache::Jit_ConvertFrom565(const PixelFuncID &id, PixelRegCache::Reg
return true;
}
-bool PixelJitCache::Jit_ConvertFrom5551(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha) {
+bool PixelJitCache::Jit_ConvertFrom5551(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha) {
// Filter out red only into temp1.
MOV(32, R(temp1Reg), R(colorReg));
AND(16, R(temp1Reg), Imm16(0x1F << 0));
@@ -2092,7 +2181,7 @@ bool PixelJitCache::Jit_ConvertFrom5551(const PixelFuncID &id, PixelRegCache::Re
return true;
}
-bool PixelJitCache::Jit_ConvertFrom4444(const PixelFuncID &id, PixelRegCache::Reg colorReg, PixelRegCache::Reg temp1Reg, PixelRegCache::Reg temp2Reg, bool keepAlpha) {
+bool PixelJitCache::Jit_ConvertFrom4444(const PixelFuncID &id, RegCache::Reg colorReg, RegCache::Reg temp1Reg, RegCache::Reg temp2Reg, bool keepAlpha) {
// Move red into position within temp1.
MOV(32, R(temp1Reg), R(colorReg));
AND(16, R(temp1Reg), Imm16(0xF << 0));
diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp
index d298c1d0c0..ebb9709fd8 100644
--- a/GPU/Software/Rasterizer.cpp
+++ b/GPU/Software/Rasterizer.cpp
@@ -906,7 +906,7 @@ void DrawTriangleSlice(
subp.x = p.x + (i & 1);
subp.y = p.y + (i / 2);
- drawPixel(subp.x, subp.y, z[i], fog[i], SOFTPIXEL_TO_VEC4I(prim_color[i]), pixelID);
+ drawPixel(subp.x, subp.y, z[i], fog[i], ToVec4IntArg(prim_color[i]), pixelID);
}
}
}
@@ -1054,7 +1054,7 @@ void DrawPoint(const VertexData &v0)
fog = ClampFogDepth(v0.fogdepth);
}
- drawPixel(p.x, p.y, z, fog, SOFTPIXEL_TO_VEC4I(prim_color), pixelID);
+ drawPixel(p.x, p.y, z, fog, ToVec4IntArg(prim_color), pixelID);
}
void ClearRectangle(const VertexData &v0, const VertexData &v1)
@@ -1344,7 +1344,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1)
ScreenCoords pprime = ScreenCoords((int)x, (int)y, (int)z);
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
- drawPixel(p.x, p.y, z, fog, SOFTPIXEL_TO_VEC4I(prim_color), pixelID);
+ drawPixel(p.x, p.y, z, fog, ToVec4IntArg(prim_color), pixelID);
}
x += xinc;
diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp
index d2089f64bc..657ff93aab 100644
--- a/GPU/Software/RasterizerRectangle.cpp
+++ b/GPU/Software/RasterizerRectangle.cpp
@@ -193,7 +193,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) {
Vec4 prim_color = v1.color0;
Vec4 tex_color = Vec4::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0));
prim_color = GetTextureFunctionOutput(prim_color, tex_color);
- drawPixel(x, y, z, 255, SOFTPIXEL_TO_VEC4I(prim_color), pixelID);
+ drawPixel(x, y, z, 255, ToVec4IntArg(prim_color), pixelID);
s += ds;
}
t += dt;
@@ -237,7 +237,7 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) {
for (int y = y1; y < y2; y++) {
for (int x = pos0.x; x < pos1.x; x++) {
Vec4 prim_color = v1.color0;
- drawPixel(x, y, z, fog, SOFTPIXEL_TO_VEC4I(prim_color), pixelID);
+ drawPixel(x, y, z, fog, ToVec4IntArg(prim_color), pixelID);
}
}
}, pos0.y, pos1.y, MIN_LINES_PER_THREAD);
diff --git a/GPU/Software/RasterizerRegCache.cpp b/GPU/Software/RasterizerRegCache.cpp
new file mode 100644
index 0000000000..21646a667f
--- /dev/null
+++ b/GPU/Software/RasterizerRegCache.cpp
@@ -0,0 +1,214 @@
+// Copyright (c) 2021- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#include "GPU/Software/RasterizerRegCache.h"
+
+namespace Rasterizer {
+
+void RegCache::Reset(bool validate) {
+ if (validate) {
+ for (auto ® : regs) {
+ _assert_msg_(reg.locked == 0, "softjit: Reset() with reg still locked (%04X)", reg.purpose);
+ _assert_msg_(!reg.forceRetained, "softjit: Reset() with reg force retained (%04X)", reg.purpose);
+ }
+ }
+ regs.clear();
+}
+
+void RegCache::Add(Reg r, Purpose p) {
+ for (auto ® : regs) {
+ if (reg.reg == r && (reg.purpose & FLAG_GEN) == (p & FLAG_GEN)) {
+ _assert_msg_(false, "softjit Add() reg duplicate (%04X)", p);
+ }
+ }
+ _assert_msg_(r != REG_INVALID_VALUE, "softjit Add() invalid reg (%04X)", p);
+
+ RegStatus newStatus;
+ newStatus.reg = r;
+ newStatus.purpose = p;
+ regs.push_back(newStatus);
+}
+
+void RegCache::Change(Purpose history, Purpose destiny) {
+ for (auto ® : regs) {
+ if (reg.purpose == history) {
+ reg.purpose = destiny;
+ return;
+ }
+ }
+
+ _assert_msg_(false, "softjit Change() reg that isn't there (%04X)", history);
+}
+
+void RegCache::Release(Reg &r, Purpose p) {
+ RegStatus *status = FindReg(r, p);
+ _assert_msg_(status != nullptr, "softjit Release() reg that isn't there (%04X)", p);
+ _assert_msg_(status->locked > 0, "softjit Release() reg that isn't locked (%04X)", p);
+ _assert_msg_(!status->forceRetained, "softjit Release() reg that is force retained (%04X)", p);
+
+ status->locked--;
+ if (status->locked == 0) {
+ if ((status->purpose & FLAG_GEN) != 0)
+ status->purpose = GEN_INVALID;
+ else
+ status->purpose = VEC_INVALID;
+ }
+
+ r = REG_INVALID_VALUE;
+}
+
+void RegCache::Unlock(Reg &r, Purpose p) {
+ RegStatus *status = FindReg(r, p);
+ if (status) {
+ _assert_msg_(status->locked > 0, "softjit Unlock() reg that isn't locked (%04X)", p);
+ status->locked--;
+ r = REG_INVALID_VALUE;
+ return;
+ }
+
+ _assert_msg_(false, "softjit Unlock() reg that isn't there (%04X)", p);
+}
+
+bool RegCache::Has(Purpose p) {
+ for (auto ® : regs) {
+ if (reg.purpose == p) {
+ return true;
+ }
+ }
+ return false;
+}
+
+RegCache::Reg RegCache::Find(Purpose p) {
+ for (auto ® : regs) {
+ if (reg.purpose == p) {
+ _assert_msg_(reg.locked <= 255, "softjit Find() reg has lots of locks (%04X)", p);
+ reg.locked++;
+ return reg.reg;
+ }
+ }
+ _assert_msg_(false, "softjit Find() reg that isn't there (%04X)", p);
+ return REG_INVALID_VALUE;
+}
+
+RegCache::Reg RegCache::Alloc(Purpose p) {
+ _assert_msg_(!Has(p), "softjit Alloc() reg duplicate (%04X)", p);
+ RegStatus *best = nullptr;
+ for (auto ® : regs) {
+ if (reg.locked != 0 || reg.forceRetained)
+ continue;
+ // Needs to be the same type.
+ if ((reg.purpose & FLAG_GEN) != (p & FLAG_GEN))
+ continue;
+
+ if (best == nullptr)
+ best = ®
+ // Prefer a free/purposeless reg (includes INVALID.)
+ if ((reg.purpose & FLAG_TEMP) != 0) {
+ best = ®
+ break;
+ }
+ // But also prefer a lower priority reg.
+ if (reg.purpose < best->purpose)
+ best = ®
+ }
+
+ if (best) {
+ best->locked = 1;
+ best->purpose = p;
+ return best->reg;
+ }
+
+ _assert_msg_(false, "softjit Alloc() reg with none free (%04X)", p);
+ return REG_INVALID_VALUE;
+}
+
+void RegCache::ForceRetain(Purpose p) {
+ for (auto ® : regs) {
+ if (reg.purpose == p) {
+ reg.forceRetained = true;
+ return;
+ }
+ }
+
+ _assert_msg_(false, "softjit ForceRetain() reg that isn't there (%04X)", p);
+}
+
+void RegCache::ForceRelease(Purpose p) {
+ for (auto ® : regs) {
+ if (reg.purpose == p) {
+ _assert_msg_(reg.locked == 0, "softjit ForceRelease() while locked (%04X)", p);
+ reg.forceRetained = false;
+ if ((reg.purpose & FLAG_GEN) != 0)
+ reg.purpose = GEN_INVALID;
+ else
+ reg.purpose = VEC_INVALID;
+ return;
+ }
+ }
+
+ _assert_msg_(false, "softjit ForceRelease() reg that isn't there (%04X)", p);
+}
+
+void RegCache::GrabReg(Reg r, Purpose p, bool &needsSwap, Reg swapReg, Purpose swapPurpose) {
+ for (auto ® : regs) {
+ if (reg.reg != r)
+ continue;
+ if ((reg.purpose & FLAG_GEN) != (p & FLAG_GEN))
+ continue;
+
+ // Easy version, it's free.
+ if (reg.locked == 0 && !reg.forceRetained) {
+ needsSwap = false;
+ reg.purpose = p;
+ reg.locked = 1;
+ return;
+ }
+
+ // Okay, we need to swap. Find that reg.
+ needsSwap = true;
+ RegStatus *swap = FindReg(swapReg, swapPurpose);
+ if (swap) {
+ swap->purpose = reg.purpose;
+ swap->forceRetained = reg.forceRetained;
+ swap->locked = reg.locked;
+ } else {
+ _assert_msg_(!Has(swapPurpose), "softjit GrabReg() wrong purpose (%04X)", swapPurpose);
+ RegStatus newStatus = reg;
+ newStatus.reg = swapReg;
+ regs.push_back(newStatus);
+ }
+
+ reg.purpose = p;
+ reg.locked = 1;
+ reg.forceRetained = false;
+ return;
+ }
+
+ _assert_msg_(false, "softjit GrabReg() reg that isn't there");
+}
+
+RegCache::RegStatus *RegCache::FindReg(Reg r, Purpose p) {
+ for (auto ® : regs) {
+ if (reg.reg == r && reg.purpose == p) {
+ return ®
+ }
+ }
+
+ return nullptr;
+}
+
+};
diff --git a/GPU/Software/RasterizerRegCache.h b/GPU/Software/RasterizerRegCache.h
new file mode 100644
index 0000000000..ee3530fc00
--- /dev/null
+++ b/GPU/Software/RasterizerRegCache.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2021- PPSSPP Project.
+
+// 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, version 2.0 or later versions.
+
+// 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 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official git repository and contact information can be found at
+// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+
+#pragma once
+
+#include "ppsspp_config.h"
+
+#include
+#include
+
+#if defined(_M_SSE)
+#include
+#endif
+#if PPSSPP_ARCH(ARM_NEON) && PPSSPP_ARCH(ARM64)
+#if defined(_MSC_VER) && PPSSPP_ARCH(ARM64)
+#include
+#else
+#include
+#endif
+#endif
+
+#if PPSSPP_ARCH(ARM)
+#include "Common/ArmEmitter.h"
+#elif PPSSPP_ARCH(ARM64)
+#include "Common/Arm64Emitter.h"
+#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
+#include "Common/x64Emitter.h"
+#elif PPSSPP_ARCH(MIPS)
+#include "Common/MipsEmitter.h"
+#else
+#include "Common/FakeEmitter.h"
+#endif
+#include "GPU/Math3D.h"
+
+namespace Rasterizer {
+
+// While not part of the reg cache proper, this is the type it is built for.
+#if PPSSPP_ARCH(ARM)
+typedef ArmGen::ARMXCodeBlock CodeBlock;
+#elif PPSSPP_ARCH(ARM64)
+typedef Arm64Gen::ARM64CodeBlock CodeBlock;
+#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
+typedef Gen::XCodeBlock CodeBlock;
+#elif PPSSPP_ARCH(MIPS)
+typedef MIPSGen::MIPSCodeBlock CodeBlock;
+#else
+typedef FakeGen::FakeXCodeBlock CodeBlock;
+#endif
+
+// We also have the types of things that end up in regs.
+#if PPSSPP_ARCH(ARM64)
+typedef int32x4_t Vec4IntArg;
+static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4 &a) { return vld1q_s32(a.AsArray()); }
+#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
+typedef __m128i Vec4IntArg;
+static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4 &a) { return a.ivec; }
+#else
+typedef const Math3D::Vec4 &Vec4IntArg;
+static inline Vec4IntArg ToVec4IntArg(const Math3D::Vec4 &a) { return a; }
+#endif
+
+#if PPSSPP_ARCH(AMD64) && PPSSPP_PLATFORM(WINDOWS) && (defined(_MSC_VER) || defined(__clang__) || defined(__INTEL_COMPILER))
+#define SOFTRAST_CALL __vectorcall
+#else
+#define SOFTRAST_CALL
+#endif
+
+struct RegCache {
+ enum Purpose {
+ FLAG_GEN = 0x0100,
+ FLAG_TEMP = 0x1000,
+
+ VEC_ZERO = 0x0000,
+
+ GEN_SRC_ALPHA = 0x0100,
+ GEN_GSTATE = 0x0101,
+ GEN_CONST_BASE = 0x0102,
+ GEN_STENCIL = 0x0103,
+ GEN_COLOR_OFF = 0x0104,
+ GEN_DEPTH_OFF = 0x0105,
+
+ GEN_ARG_X = 0x0180,
+ GEN_ARG_Y = 0x0181,
+ GEN_ARG_Z = 0x0182,
+ GEN_ARG_FOG = 0x0183,
+ GEN_ARG_ID = 0x0184,
+ VEC_ARG_COLOR = 0x0080,
+ VEC_ARG_MASK = 0x0081,
+
+ VEC_TEMP0 = 0x1000,
+ VEC_TEMP1 = 0x1001,
+ VEC_TEMP2 = 0x1002,
+ VEC_TEMP3 = 0x1003,
+ VEC_TEMP4 = 0x1004,
+ VEC_TEMP5 = 0x1005,
+
+ GEN_TEMP0 = 0x1100,
+ GEN_TEMP1 = 0x1101,
+ GEN_TEMP2 = 0x1102,
+ GEN_TEMP3 = 0x1103,
+ GEN_TEMP4 = 0x1104,
+ GEN_TEMP5 = 0x1105,
+ GEN_TEMP_HELPER = 0x1106,
+
+ VEC_INVALID = 0xFEFF,
+ GEN_INVALID = 0xFFFF,
+ };
+
+#if PPSSPP_ARCH(ARM)
+ typedef ArmGen::ARMReg Reg;
+ static constexpr Reg REG_INVALID_VALUE = ArmGen::INVALID_REG;
+#elif PPSSPP_ARCH(ARM64)
+ typedef Arm64Gen::ARM64Reg Reg;
+ static constexpr Reg REG_INVALID_VALUE = Arm64Gen::INVALID_REG;
+#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
+ typedef Gen::X64Reg Reg;
+ static constexpr Reg REG_INVALID_VALUE = Gen::INVALID_REG;
+#elif PPSSPP_ARCH(MIPS)
+ typedef MIPSGen::MIPSReg Reg;
+ static constexpr Reg REG_INVALID_VALUE = MIPSGen::INVALID_REG;
+#else
+ typedef int Reg;
+ static constexpr Reg REG_INVALID_VALUE = -1;
+#endif
+
+ struct RegStatus {
+ Reg reg;
+ Purpose purpose;
+ uint8_t locked = 0;
+ bool forceRetained = false;
+ };
+
+ void Reset(bool validate);
+ void Add(Reg r, Purpose p);
+ void Change(Purpose history, Purpose destiny);
+ void Release(Reg &r, Purpose p);
+ void Unlock(Reg &r, Purpose p);
+ bool Has(Purpose p);
+ Reg Find(Purpose p);
+ Reg Alloc(Purpose p);
+ void ForceRetain(Purpose p);
+ void ForceRelease(Purpose p);
+
+ // For getting a specific reg. WARNING: May return a locked reg, so you have to check.
+ void GrabReg(Reg r, Purpose p, bool &needsSwap, Reg swapReg, Purpose swapPurpose);
+
+private:
+ RegStatus *FindReg(Reg r, Purpose p);
+
+ std::vector regs;
+};
+
+};
diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp
index dfa24ef322..155f1359b2 100644
--- a/GPU/Software/Sampler.cpp
+++ b/GPU/Software/Sampler.cpp
@@ -241,13 +241,14 @@ LinearFunc SamplerJitCache::GetLinear(const SamplerID &id) {
}
#if PPSSPP_ARCH(AMD64) && !PPSSPP_PLATFORM(UWP)
- addresses_[id] = GetCodePointer();
- LinearFunc func = CompileLinear(id);
- cache_[id] = (NearestFunc)func;
- return func;
-#else
- return nullptr;
+ if (g_Config.bSoftwareRenderingJit) {
+ addresses_[id] = GetCodePointer();
+ LinearFunc func = CompileLinear(id);
+ cache_[id] = (NearestFunc)func;
+ return func;
+ }
#endif
+ return nullptr;
}
template
diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h
index 025b798252..a14c3e5520 100644
--- a/GPU/Software/Sampler.h
+++ b/GPU/Software/Sampler.h
@@ -20,19 +20,9 @@
#include "ppsspp_config.h"
#include
-#if PPSSPP_ARCH(ARM)
-#include "Common/ArmEmitter.h"
-#elif PPSSPP_ARCH(ARM64)
-#include "Common/Arm64Emitter.h"
-#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
-#include "Common/x64Emitter.h"
-#elif PPSSPP_ARCH(MIPS)
-#include "Common/MipsEmitter.h"
-#else
-#include "Common/FakeEmitter.h"
-#endif
#include "GPU/Math3D.h"
#include "GPU/Software/FuncId.h"
+#include "GPU/Software/RasterizerRegCache.h"
namespace Sampler {
@@ -58,17 +48,7 @@ void Shutdown();
bool DescribeCodePtr(const u8 *ptr, std::string &name);
-#if PPSSPP_ARCH(ARM)
-class SamplerJitCache : public ArmGen::ARMXCodeBlock {
-#elif PPSSPP_ARCH(ARM64)
-class SamplerJitCache : public Arm64Gen::ARM64CodeBlock {
-#elif PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
-class SamplerJitCache : public Gen::XCodeBlock {
-#elif PPSSPP_ARCH(MIPS)
-class SamplerJitCache : public MIPSGen::MIPSCodeBlock {
-#else
-class SamplerJitCache : public FakeGen::FakeXCodeBlock {
-#endif
+class SamplerJitCache : public Rasterizer::CodeBlock {
public:
SamplerJitCache();
diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj
index 76458d8906..d8e70972e6 100644
--- a/UWP/GPU_UWP/GPU_UWP.vcxproj
+++ b/UWP/GPU_UWP/GPU_UWP.vcxproj
@@ -431,6 +431,7 @@
+
@@ -491,6 +492,7 @@
+
diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
index 591297863e..2f982e10b0 100644
--- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
+++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters
@@ -55,6 +55,7 @@
+
@@ -114,6 +115,7 @@
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index a3039ecd41..c62de2889f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -369,6 +369,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/GPU/Software/Lighting.cpp \
$(SRC)/GPU/Software/Rasterizer.cpp.arm \
$(SRC)/GPU/Software/RasterizerRectangle.cpp.arm \
+ $(SRC)/GPU/Software/RasterizerRegCache.cpp \
$(SRC)/GPU/Software/Sampler.cpp \
$(SRC)/GPU/Software/SoftGpu.cpp \
$(SRC)/GPU/Software/TransformUnit.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index fd8048c7ee..32c10ee8db 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -356,6 +356,7 @@ SOURCES_CXX += \
$(GPUDIR)/Software/Lighting.cpp \
$(GPUDIR)/Software/Rasterizer.cpp \
$(GPUDIR)/Software/RasterizerRectangle.cpp \
+ $(GPUDIR)/Software/RasterizerRegCache.cpp \
$(GPUDIR)/GLES/DepalettizeShaderGLES.cpp \
$(GPUDIR)/GLES/DepthBufferGLES.cpp \
$(GPUDIR)/GLES/DrawEngineGLES.cpp \