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 \