diff --git a/libpcsxcore/gpu.c b/libpcsxcore/gpu.c index 324c2a00..61a7b3dc 100755 --- a/libpcsxcore/gpu.c +++ b/libpcsxcore/gpu.c @@ -19,6 +19,7 @@ #include "psxhw.h" #include "gpu.h" #include "psxdma.h" +#include "pgxp_gte.h" #define GPUSTATUS_ODDLINES 0x80000000 #define GPUSTATUS_DMABITS 0x60000000 // Two bits @@ -142,6 +143,7 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU #endif break; } + GPU_pgxpMemory(madr, PGXP_GetMem()); GPU_writeDataMem(ptr, size); #if 0 diff --git a/libpcsxcore/gte.c b/libpcsxcore/gte.c index 599672c9..04a3968c 100755 --- a/libpcsxcore/gte.c +++ b/libpcsxcore/gte.c @@ -7,6 +7,7 @@ #include "gte.h" #include "psxmem.h" +#include "pgxp_gte.h" #define GTE_SF(op) ((op >> 19) & 1) #define GTE_MX(op) ((op >> 17) & 3) @@ -251,6 +252,7 @@ static void CTC2(u32 value, int reg) { void gteMFC2() { if (!_Rt_) return; psxRegs.GPR.r[_Rt_] = MFC2(_Rd_); + PGXP_MFC2(_Rt_, _Rd_, psxRegs.CP2D.p[_Rd_].d); } void gteCFC2() { @@ -259,6 +261,7 @@ void gteCFC2() { } void gteMTC2() { + PGXP_MTC2(_Rt_, _Rd_, psxRegs.GPR.p[_Rt_].d); MTC2(psxRegs.GPR.r[_Rt_], _Rd_); } @@ -269,11 +272,15 @@ void gteCTC2() { #define _oB_ (psxRegs.GPR.r[_Rs_] + _Imm_) void gteLWC2() { - MTC2(psxMemRead32(_oB_), _Rt_); + u32 val = psxMemRead32(_oB_); + PGXP_LWC2(_oB_, _Rt_, val); + MTC2(val, _Rt_); } void gteSWC2() { - psxMemWrite32(_oB_, MFC2(_Rt_)); + u32 val = MFC2(_Rt_); + PGXP_SWC2(_oB_, _Rt_, val); + psxMemWrite32(_oB_, val); } inline s64 gte_shift(s64 a, int sf) { @@ -490,10 +497,9 @@ int docop2(int op) { SX2 = Lm_G1(F((s64) OFX + ((s64) IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)) >> 16); SY2 = Lm_G2(F((s64) OFY + ((s64) IR2 * h_over_sz3)) >> 16); - GPU_addVertex(SX2, SY2, - Lm_G1_ia((s64) OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)), - Lm_G2_ia((s64) OFY + (s64)(IR2 * h_over_sz3)), - ((s64)SZ3)); + PGXP_pushSXYZ2s(Lm_G1_ia((s64)OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)), + Lm_G2_ia((s64)OFY + (s64)(IR2 * h_over_sz3)), + SZ3); MAC0 = F((s64) DQB + ((s64) DQA * h_over_sz3)); IR0 = Lm_H(m_mac0, 1); @@ -503,8 +509,10 @@ int docop2(int op) { #ifdef GTE_LOG GTELOG("%08x NCLIP", op); #endif - - MAC0 = F((s64) (SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1)); + if (PGXP_NLCIP_valid()) + MAC0 = F(PGXP_NCLIP()); + else + MAC0 = F((s64) (SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1)); return 1; case 0x0c: @@ -879,10 +887,9 @@ int docop2(int op) { SX2 = Lm_G1(F((s64) OFX + ((s64) IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)) >> 16); SY2 = Lm_G2(F((s64) OFY + ((s64) IR2 * h_over_sz3)) >> 16); - GPU_addVertex(SX2, SY2, - Lm_G1_ia((s64) OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)), - Lm_G2_ia((s64) OFY + (s64)(IR2 * h_over_sz3)), - ((s64)SZ3)); + PGXP_pushSXYZ2s(Lm_G1_ia((s64)OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)), + Lm_G2_ia((s64)OFY + (s64)(IR2 * h_over_sz3)), + SZ3); } MAC0 = F((s64) DQB + ((s64) DQA * h_over_sz3)); diff --git a/libpcsxcore/ix86/iR3000A.c b/libpcsxcore/ix86/iR3000A.c index d7f68890..d18c47ec 100755 --- a/libpcsxcore/ix86/iR3000A.c +++ b/libpcsxcore/ix86/iR3000A.c @@ -25,6 +25,7 @@ #include "ix86.h" #include +#include "pgxp_gte.h" #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON @@ -1546,14 +1547,15 @@ static void recLW() { // SysPrintf("unhandled r32 %x\n", addr); } + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode iPushOfB(); - CALLFunc((u32)psxMemRead32); + CALLFunc((u32)PGXP_psxMemRead32Trace); if (_Rt_) { iRegs[_Rt_].state = ST_UNK; MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } // ADD32ItoR(ESP, 4); - resp+= 4; + resp+= 8; } extern u32 LWL_MASK[4]; @@ -1601,12 +1603,13 @@ void recLWL() { if (_Imm_) ADD32ItoR(EAX, _Imm_); } PUSH32R (EAX); + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemRead32); + CALLFunc((u32)PGXP_psxMemRead32Trace); if (_Rt_) { - ADD32ItoR(ESP, 4); + ADD32ItoR(ESP, 8); POP32R (EDX); AND32ItoR(EDX, 0x3); // shift = addr & 3; @@ -1629,7 +1632,7 @@ void recLWL() { MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } else { // ADD32ItoR(ESP, 8); - resp+= 8; + resp+= 12; } } @@ -1756,12 +1759,13 @@ void recLWR() { if (_Imm_) ADD32ItoR(EAX, _Imm_); } PUSH32R (EAX); + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemRead32); + CALLFunc((u32)PGXP_psxMemRead32Trace); if (_Rt_) { - ADD32ItoR(ESP, 4); + ADD32ItoR(ESP, 8); POP32R (EDX); AND32ItoR(EDX, 0x3); // shift = addr & 3; @@ -1785,7 +1789,7 @@ void recLWR() { MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX); } else { // ADD32ItoR(ESP, 8); - resp+= 8; + resp+= 12; } } @@ -1978,15 +1982,16 @@ static void recSW() { // SysPrintf("unhandled w32 %x\n", addr); } + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode if (IsConst(_Rt_)) { PUSH32I (iRegs[_Rt_].k); } else { PUSH32M ((u32)&psxRegs.GPR.r[_Rt_]); } iPushOfB(); - CALLFunc((u32)psxMemWrite32); + CALLFunc((u32)PGXP_psxMemWrite32Trace); // ADD32ItoR(ESP, 8); - resp+= 8; + resp+= 12; } //#endif @@ -2104,12 +2109,13 @@ void recSWL() { if (_Imm_) ADD32ItoR(EAX, _Imm_); } PUSH32R (EAX); + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemRead32); + CALLFunc((u32)PGXP_psxMemRead32Trace); - ADD32ItoR(ESP, 4); + ADD32ItoR(ESP, 8); POP32R (EDX); AND32ItoR(EDX, 0x3); // shift = addr & 3; @@ -2126,6 +2132,8 @@ void recSWL() { } SHR32CLtoR(EDX); // _rRt_ >> SWL_SHIFT[shift] + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode + OR32RtoR (EAX, EDX); PUSH32R (EAX); @@ -2137,9 +2145,9 @@ void recSWL() { AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemWrite32); + CALLFunc((u32)PGXP_psxMemWrite32Trace); // ADD32ItoR(ESP, 8); - resp+= 8; + resp+= 12; } extern u32 SWR_MASK[4]; @@ -2186,12 +2194,13 @@ void recSWR() { if (_Imm_) ADD32ItoR(EAX, _Imm_); } PUSH32R (EAX); + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemRead32); + CALLFunc((u32)PGXP_psxMemRead32Trace); - ADD32ItoR(ESP, 4); + ADD32ItoR(ESP, 8); POP32R (EDX); AND32ItoR(EDX, 0x3); // shift = addr & 3; @@ -2208,6 +2217,8 @@ void recSWR() { } SHL32CLtoR(EDX); // _rRt_ << SWR_SHIFT[shift] + PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode + OR32RtoR (EAX, EDX); PUSH32R (EAX); @@ -2219,9 +2230,9 @@ void recSWR() { AND32ItoR(EAX, ~3); PUSH32R (EAX); - CALLFunc((u32)psxMemWrite32); + CALLFunc((u32)PGXP_psxMemWrite32Trace); // ADD32ItoR(ESP, 8); - resp += 8; + resp += 12; } /*REC_FUNC(SLL); diff --git a/libpcsxcore/pgxp_gte.c b/libpcsxcore/pgxp_gte.c new file mode 100644 index 00000000..4b22c778 --- /dev/null +++ b/libpcsxcore/pgxp_gte.c @@ -0,0 +1,437 @@ +/*************************************************************************** +* Copyright (C) 2016 by iCatButler * +* * +* 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; either version 2 of the License, or * +* (at your option) any later version. * +* * +* 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 for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +/************************************************************************** +* pgxp_gte.c +* PGXP - Parallel/Precision Geometry Xform Pipeline +* +* Created on: 12 Mar 2016 +* Author: iCatButler +***************************************************************************/ + +#include "pgxp_gte.h" +#include "psxmem.h" + +typedef struct +{ + float x; + float y; + float z; + unsigned int valid; + unsigned int count; +} precise_value; + +typedef union +{ + struct + { + s16 x; + s16 y; + }; + u32 word; +} low_value; + +#define tolerance 1.0f + +precise_value GTE_reg[32]; +precise_value CPU_reg[32]; + +precise_value Mem[2048 * 1024 / 4]; // mirror 2MB in 32-bit words +precise_value Scratch[2048 * 1024 / 4]; // mirror 2MB in 32-bit words + +void PGXP_Init() +{ + memset(Mem, 0, sizeof(Mem)); +} + +char* PGXP_GetMem() +{ + return (char*)(Mem); +} + +#define VRAM 0 +#define SCRATCH 1 + +precise_value* ReadMem(u32 addr) +{ + u32 memType; + uint32_t paddr = addr; + int* ip = NULL; + + switch (paddr >> 20) + { + case 0x800: + case 0x801: + case 0xa00: + case 0xa01: + case 0x000: + case 0x001: + memType = VRAM; + break; + case 0x1f8: + memType = SCRATCH; + break; + default: + return NULL; + } + +#ifdef GTE_LOG + //GTE_LOG("PGXP_Read %x [%x] |", addr, paddr); +#endif + if (memType == VRAM) + { + paddr = (paddr & 0x1FFFFF) >> 2; + return &Mem[paddr]; + } + else if (memType == SCRATCH) + { + paddr = (paddr & 0x1FFFFF) >> 2; + return &Scratch[paddr]; + } + + return NULL; +} + +void WriteMem(precise_value value, u32 addr) +{ + u32 memType; + uint32_t paddr = addr; + int* ip = NULL; + + switch (paddr >> 20) + { + case 0x800: + case 0x801: + case 0xa00: + case 0xa01: + case 0x000: + case 0x001: + memType = VRAM; + break; + case 0x1f8: + memType = SCRATCH; + break; + default: + if (value.valid) + *ip = 5; + return; + } + +#ifdef GTE_LOG + GTE_LOG("PGXP_Write %x [%x] |", addr, paddr); +#endif + + // Store to RAM + if (memType == VRAM) + { + paddr = (paddr & 0x1FFFFF) >> 2; + Mem[paddr] = value; + } + else if (memType == SCRATCH) + { + paddr = (paddr & 0x1FFFFF) >> 2;// (paddr & 0x3FFF) >> 2; + Scratch[paddr] = value; + } +} + +#define SX0 (GTE_reg[ 12 ].x) +#define SY0 (GTE_reg[ 12 ].y) +#define SX1 (GTE_reg[ 13 ].x) +#define SY1 (GTE_reg[ 13 ].y) +#define SX2 (GTE_reg[ 14 ].x) +#define SY2 (GTE_reg[ 14 ].y) + +#define SXY0 (GTE_reg[ 12 ]) +#define SXY1 (GTE_reg[ 13 ]) +#define SXY2 (GTE_reg[ 14 ]) +#define SXYP (GTE_reg[ 15 ]) + +unsigned int PGXP_validate(float high, s16 low) +{ + if (fabs(high - (float)(low)) < tolerance) + return 1; + return 0; +} + +// Check that value is still within tolerance of low precision value and invalidate if not +precise_value PGXP_validateXY(precise_value *high, u32 low) +{ + low_value temp; + precise_value ret; + + ret.valid = 0; + temp.word = low; + + if (!high) + return ret; + + high->valid = (high->valid && PGXP_validate(high->x, temp.x) && PGXP_validate(high->y, temp.y)); + + // Cheat + //if (!high->valid) + //{ + // high->x = temp.x; + // high->y = temp.y; + // high->valid = 1; + //} + + return *high; +} + +u32 PGXP_compareXY(precise_value high, u32 low) +{ + low_value temp; + temp.word = low; + + if (PGXP_validate(high.x, temp.x) && PGXP_validate(high.y, temp.y)) + return 1; + return 0; +} + +precise_value PGXP_copyXY(u32 low) +{ + low_value temp; + precise_value ret; + + ret.valid = 0; + temp.word = low; + + ret.x = temp.x; + ret.y = temp.y; + ret.count = 0; + ret.valid = 1; + + return ret; +} + +void PGXP_pushSXYZ2f(float _x, float _y, float _z) +{ + static unsigned int uCount = 0; + // push values down FIFO + SXY0 = SXY1; + SXY1 = SXY2; + + SXY2.x = _x; + SXY2.y = _y; + SXY2.z = _z; + SXY2.valid = 1; + SXY2.count = uCount++; + +#ifdef GTE_LOG + GTE_LOG("PGPR_PUSH (%f, %f) %u %u|", SXY2.x, SXY2.y, SXY2.valid, SXY2.count); +#endif +} + +void PGXP_pushSXYZ2s(s64 _x, s64 _y, s64 _z) +{ + float fx = (float)(_x) / (float)(1 << 16); + float fy = (float)(_y) / (float)(1 << 16); + float fz = (float)(_z); + + PGXP_pushSXYZ2f(fx, fy, fz); +} + +int PGXP_NLCIP_valid() +{ + if (SXY0.valid && SXY1.valid && SXY2.valid) + return 1; + return 0; +} + +float PGXP_NCLIP() +{ + float nclip = ((SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1)); + + // ensure fractional values are not incorrectly rounded to 0 + if (fabs(nclip) < 1.0f) + nclip += (nclip < 0.f ? -2 : 2); + + return nclip; +} + +static precise_value PGXP_MFC2_int(u32 reg) +{ + switch (reg) + { + case 15: + GTE_reg[reg] = SXYP = SXY2; + break; + } + + return GTE_reg[reg]; +} + + +static void PGXP_MTC2_int(precise_value value, u32 reg) +{ + switch(reg) + { + case 15: + // push FIFO + SXY0 = SXY1; + SXY1 = SXY2; + SXY2 = value; + SXYP = SXY2; + break; + + case 31: + return; + } + + GTE_reg[reg] = value; +} + +// copy GTE data reg to GPR reg (MFC2) +void PGXP_MFC2(u32 gpr, u32 gtr, u32 value) +{ + if (!gpr) return; +#ifdef GTE_LOG + GTE_LOG("PGXP_MFC2 [%x] [%x] %x (%u %u)|", gpr, gtr, value, GTE_reg[gtr].valid, GTE_reg[gtr].count); +#endif + + CPU_reg[gpr] = PGXP_validateXY(>E_reg[gtr], value); +} + +// copy GPR reg to GTE data reg (MTC2) +void PGXP_MTC2(u32 gpr, u32 gtr, u32 value) +{ +#ifdef GTE_LOG + GTE_LOG("PGXP_MTC2 [%x] [%x] %x (%u %u)|", gpr, gtr, value, CPU_reg[gtr].valid, CPU_reg[gtr].count); +#endif + PGXP_MTC2_int(PGXP_validateXY(&CPU_reg[gpr], value), gtr); +} + +// copy memory to GTE reg +void PGXP_LWC2(u32 addr, u32 gtr, u32 value) +{ +#ifdef GTE_LOG + precise_value* pp = ReadMem(addr); + precise_value p; + low_value temp; + temp.word = value; + + p.x = p.y = p.valid = 0; + + if (pp) + p = *pp; + + GTE_LOG("PGXP_LWC2 %x [%x] %x (%d, %d) (%f, %f) %u %u|", addr, gtr, value, temp.x, temp.y, p.x, p.y, p.valid, p.count); +#endif + PGXP_MTC2_int(PGXP_validateXY(ReadMem(addr), value), gtr); +} + +//copy GTE reg to memory +void PGXP_SWC2(u32 addr, u32 gtr, u32 value) +{ +#ifdef GTE_LOG + low_value temp; + temp.word = value; + + if (PGXP_compareXY(GTE_reg[gtr], value)) + GTE_LOG("PGPR_SWC2 %x [%x] %x (%d, %d) (%f, %f) %u %u|", addr, gtr, value, temp.x, temp.y, GTE_reg[gtr].x, GTE_reg[gtr].y, GTE_reg[gtr].valid, GTE_reg[gtr].count); +#endif + WriteMem(PGXP_validateXY(>E_reg[gtr], value), addr); +} + +// ltore 32bit word +void PGPR_L32(u32 addr, u32 code, u32 value) +{ + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + u32 op = ((code >> 26)); + precise_value p; + + low_value temp; + temp.word = value; + + p.x = p.y = p.valid = p.count = 0; + + switch (op) + { + case 34: //LWL + CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value); + break; + case 35: //LW + CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value); + break; + case 37: //LWR + CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value); + break; + case 50: //LWC2 (GTE vertex reads) + GTE_reg[reg] = PGXP_validateXY(ReadMem(addr), value); + break; + default: + // invalidate register + // WriteMem(p, addr); + break; + } + +#ifdef GTE_LOG + GTE_LOG("PGPR_L32 %u: %x %x[%x %x] (%d, %d) (%f, %f) %x %u|", op, addr, value, code, reg, temp.x, temp.y, CPU_reg[reg].x, CPU_reg[reg].y, CPU_reg[reg].valid, CPU_reg[reg].count); +#endif +} + +// store 32bit word +void PGPR_S32(u32 addr, u32 code, u32 value) +{ + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + u32 op = ((code >> 26)); + precise_value p; + + low_value temp; + temp.word = value; + + p.x = p.y = p.valid = p.count = 0; + +#ifdef GTE_LOG + GTE_LOG("PGPR_S32 %u: %x %x[%x %x] (%d, %d) (%f, %f) %x %u|", op, addr, value, code, reg, temp.x, temp.y, CPU_reg[reg].x, CPU_reg[reg].y, CPU_reg[reg].valid, CPU_reg[reg].count); +#endif + + switch (op) + { + case 42: //SWL + WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr); + break; + case 43: //SW + WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr); + break; + case 46: //SWR + WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr); + break; + case 58: //SWC2 (GTE vertex writes) + WriteMem(PGXP_validateXY(>E_reg[reg], value), addr); + break; + default: + // invalidate memory + // WriteMem(p, addr); + break; + } +} + +u32 PGXP_psxMemRead32Trace(u32 mem, u32 code) +{ + u32 value = psxMemRead32(mem); + PGPR_L32(mem, code, value); + return value; +} + +void PGXP_psxMemWrite32Trace(u32 mem, u32 value, u32 code) +{ + PGPR_S32(mem, code, value); + psxMemWrite32(mem, value); +} \ No newline at end of file diff --git a/libpcsxcore/pgxp_gte.h b/libpcsxcore/pgxp_gte.h new file mode 100644 index 00000000..c97c5b29 --- /dev/null +++ b/libpcsxcore/pgxp_gte.h @@ -0,0 +1,58 @@ +/*************************************************************************** +* Copyright (C) 2016 by iCatButler * +* * +* 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; either version 2 of the License, or * +* (at your option) any later version. * +* * +* 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 for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +/************************************************************************** +* pgxp_gte.h +* PGXP - Parallel/Precision Geometry Xform Pipeline +* +* Created on: 12 Mar 2016 +* Author: iCatButler +***************************************************************************/ + +#ifndef _PGXP_GTE_H_ +#define _PGXP_GTE_H_ + +#include "psxcommon.h" + +void PGXP_Init(); // initialise memory +char* PGXP_GetMem(); // return pointer to precision memory + +// -- GTE functions +// Transforms +void PGXP_pushSXYZ2f(float _x, float _y, float _z); +void PGXP_pushSXYZ2s(s64 _x, s64 _y, s64 _z); +int PGXP_NLCIP_valid(); +float PGXP_NCLIP(); + +// Data transfer tracking +void PGXP_MFC2(u32 gpr, u32 gtr, u32 value); // copy GTE reg to GPR reg (MFC2) +void PGXP_MTC2(u32 gpr, u32 gtr, u32 value); // copy GPR reg to GTR reg (MTC2) +void PGXP_LWC2(u32 addr, u32 gtr, u32 value); // copy memory to GTE reg +void PGXP_SWC2(u32 addr, u32 gtr, u32 value); // copy GTE reg to memory + +// -- CPU functions +// Data transfer tracking +void PGPR_L32(u32 addr, u32 code, u32 value); // load 32bit word +void PGPR_S32(u32 addr, u32 code, u32 value); // store 32bit word + +// Memory Read/Write hooks +u32 PGXP_psxMemRead32Trace(u32 mem, u32 code); +void PGXP_psxMemWrite32Trace(u32 mem, u32 value, u32 code); + +#endif /* _PGXP_GTE_H_ */ diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c index 05770154..54c7e468 100755 --- a/libpcsxcore/plugins.c +++ b/libpcsxcore/plugins.c @@ -54,6 +54,7 @@ GPUvBlank GPU_vBlank; GPUvisualVibration GPU_visualVibration; GPUcursor GPU_cursor; GPUaddVertex GPU_addVertex; +GPUpgxpMemory GPU_pgxpMemory; CDRinit CDR_init; CDRshutdown CDR_shutdown; @@ -214,6 +215,7 @@ void CALLBACK GPU__vBlank(int val) {} void CALLBACK GPU__visualVibration(unsigned long iSmall, unsigned long iBig) {} void CALLBACK GPU__cursor(int player, int x, int y) {} void CALLBACK GPU__addVertex(short sx,short sy,s64 fx,s64 fy,s64 fz) {} +void CALLBACK GPU__pgxpMemory(unsigned char* pMem, unsigned int count, unsigned int addr, unsigned char* pVRAM) {} #define LoadGpuSym1(dest, name) \ LoadSym(GPU_##dest, GPU##dest, name, TRUE); @@ -259,6 +261,7 @@ static int LoadGPUplugin(const char *GPUdll) { LoadGpuSym0(visualVibration, "GPUvisualVibration"); LoadGpuSym0(cursor, "GPUcursor"); LoadGpuSym0(addVertex, "GPUaddVertex"); + LoadGpuSym0(pgxpMemory, "GPUpgxpMemory"); LoadGpuSym0(configure, "GPUconfigure"); LoadGpuSym0(test, "GPUtest"); LoadGpuSym0(about, "GPUabout"); diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h index f8cfdf44..8f2cc189 100755 --- a/libpcsxcore/plugins.h +++ b/libpcsxcore/plugins.h @@ -96,6 +96,7 @@ typedef void (CALLBACK* GPUvBlank)(int); typedef void (CALLBACK* GPUvisualVibration)(uint32_t, uint32_t); typedef void (CALLBACK* GPUcursor)(int, int, int); typedef void (CALLBACK* GPUaddVertex)(short,short,s64,s64,s64); +typedef void (CALLBACK* GPUpgxpMemory)(unsigned int, unsigned char*); // GPU function pointers extern GPUupdateLace GPU_updateLace; @@ -125,6 +126,7 @@ extern GPUvBlank GPU_vBlank; extern GPUvisualVibration GPU_visualVibration; extern GPUcursor GPU_cursor; extern GPUaddVertex GPU_addVertex; +extern GPUpgxpMemory GPU_pgxpMemory; // CD-ROM Functions typedef long (CALLBACK* CDRinit)(void); diff --git a/libpcsxcore/r3000a.c b/libpcsxcore/r3000a.c index fe908ecb..cb2f4025 100755 --- a/libpcsxcore/r3000a.c +++ b/libpcsxcore/r3000a.c @@ -44,6 +44,7 @@ int psxInit() { Log = 0; if (psxMemInit() == -1) return -1; + PGXP_Init(); return psxCpu->Init(); } diff --git a/plugins/peopsxgl/draw.c b/plugins/peopsxgl/draw.c index cb838d33..c3fed1cf 100755 --- a/plugins/peopsxgl/draw.c +++ b/plugins/peopsxgl/draw.c @@ -28,6 +28,7 @@ #include "menu.h" #include "gte_accuracy.h" +#include "pgxp_gpu.h" #if defined(_MACGL) // if you use it, you must include it @@ -943,7 +944,7 @@ void offsetline(void) #define VERTEX_OFFX 0.2f #define VERTEX_OFFY 0.2f -BOOL offsetline(void) +BOOL offsetline(unsigned int* addr) { short x0,x1,y0,y1,dx,dy;float px,py; @@ -1004,6 +1005,8 @@ BOOL offsetline(void) else py= 0.0f; } } + + PGXP_GetVertices(addr, vertex); vertex[0].x=(short)((float)x0-px); vertex[3].x=(short)((float)x0+py); @@ -1040,7 +1043,7 @@ BOOL offsetline(void) ///////////////////////////////////////////////////////// -BOOL offset2(void) +BOOL offset2(unsigned int* addr) { if(bDisplayNotSet) SetOGLDisplaySettings(1); @@ -1066,6 +1069,8 @@ BOOL offset2(void) vertex[1].y=ly1; } + PGXP_GetVertices(addr, vertex); + vertex[0].x+=PSXDisplay.CumulOffset.x; vertex[1].x+=PSXDisplay.CumulOffset.x; vertex[0].y+=PSXDisplay.CumulOffset.y; @@ -1076,7 +1081,7 @@ BOOL offset2(void) ///////////////////////////////////////////////////////// -BOOL offset3(void) +BOOL offset3(unsigned int* addr) { if(bDisplayNotSet) SetOGLDisplaySettings(1); @@ -1109,6 +1114,8 @@ BOOL offset3(void) vertex[2].y=ly2; } + PGXP_GetVertices(addr, vertex); + vertex[0].x+=PSXDisplay.CumulOffset.x; vertex[1].x+=PSXDisplay.CumulOffset.x; vertex[2].x+=PSXDisplay.CumulOffset.x; @@ -1121,7 +1128,7 @@ BOOL offset3(void) ///////////////////////////////////////////////////////// -BOOL offset4(void) +BOOL offset4(unsigned int* addr) { if(bDisplayNotSet) SetOGLDisplaySettings(1); @@ -1161,6 +1168,8 @@ BOOL offset4(void) vertex[3].y=ly3; } + PGXP_GetVertices(addr, vertex); + vertex[0].x+=PSXDisplay.CumulOffset.x; vertex[1].x+=PSXDisplay.CumulOffset.x; vertex[2].x+=PSXDisplay.CumulOffset.x; diff --git a/plugins/peopsxgl/draw.h b/plugins/peopsxgl/draw.h index 10501d37..2f524904 100755 --- a/plugins/peopsxgl/draw.h +++ b/plugins/peopsxgl/draw.h @@ -35,10 +35,10 @@ BOOL bSetupPixelFormat(HDC hDC); int GLinitialize(); void GLcleanup(); -BOOL offset2(void); -BOOL offset3(void); -BOOL offset4(void); -BOOL offsetline(void); +BOOL offset2(unsigned int* addr); +BOOL offset3(unsigned int* addr); +BOOL offset4(unsigned int* addr); +BOOL offsetline(unsigned int* addr); void offsetST(void); void offsetBlk(void); void offsetScreenUpload(int Position); diff --git a/plugins/peopsxgl/gpu.c b/plugins/peopsxgl/gpu.c index d5af3330..65e074d5 100755 --- a/plugins/peopsxgl/gpu.c +++ b/plugins/peopsxgl/gpu.c @@ -48,6 +48,7 @@ static int iOldMode=0; #include "fps.h" #include "key.h" #include "gte_accuracy.h" +#include "PGXP_gpu.h" #ifdef _WINDOWS #include "resource.h" #include "ssave.h" @@ -3145,7 +3146,11 @@ long CALLBACK GPUdmaChain(uint32_t *baseAddrL, uint32_t addr) dmaMem=addr+4; - if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count); + if (count > 0) + { + PGXP_SetAddress(dmaMem >> 2); + GPUwriteDataMem(&baseAddrL[dmaMem >> 2], count); + } addr = baseAddrL[addr>>2]&0xffffff; } diff --git a/plugins/peopsxgl/prim.c b/plugins/peopsxgl/prim.c index 6a06a9be..0c78145d 100755 --- a/plugins/peopsxgl/prim.c +++ b/plugins/peopsxgl/prim.c @@ -3105,7 +3105,7 @@ void primPolyF4(unsigned char *baseAddr) lx3 = sgpuData[8]; ly3 = sgpuData[9]; - if(offset4()) return; + if(offset4(baseAddr)) return; bDrawTextured = FALSE; bDrawSmoothShaded = FALSE; @@ -3214,7 +3214,7 @@ void primPolyG4(unsigned char * baseAddr) lx3 = sgpuData[14]; ly3 = sgpuData[15]; - if(offset4()) return; + if(offset4(baseAddr)) return; bDrawTextured = FALSE; bDrawSmoothShaded = TRUE; @@ -3430,7 +3430,7 @@ void primPolyFT3(unsigned char * baseAddr) lx2 = sgpuData[10]; ly2 = sgpuData[11]; - if(offset3()) return; + if(offset3(baseAddr)) return; // do texture UV coordinates stuff gl_ux[0]=gl_ux[3]=baseAddr[8];//gpuData[2]&0xff; @@ -3868,7 +3868,7 @@ void primPolyFT4(unsigned char * baseAddr) lx3 = sgpuData[14]; ly3 = sgpuData[15]; - if(offset4()) return; + if(offset4(baseAddr)) return; gl_vy[0]=baseAddr[9];//((gpuData[2]>>8)&0xff); gl_vy[1]=baseAddr[17];//((gpuData[4]>>8)&0xff); @@ -3953,7 +3953,7 @@ void primPolyGT3(unsigned char *baseAddr) lx2 = sgpuData[14]; ly2 = sgpuData[15]; - if(offset3()) return; + if(offset3(baseAddr)) return; // do texture stuff gl_ux[0]=gl_ux[3]=baseAddr[8];//gpuData[2]&0xff; @@ -4062,7 +4062,7 @@ void primPolyG3(unsigned char *baseAddr) lx2 = sgpuData[10]; ly2 = sgpuData[11]; - if(offset3()) return; + if(offset3(baseAddr)) return; bDrawTextured = FALSE; bDrawSmoothShaded = TRUE; @@ -4109,7 +4109,7 @@ void primPolyGT4(unsigned char *baseAddr) lx3 = sgpuData[20]; ly3 = sgpuData[21]; - if(offset4()) return; + if(offset4(baseAddr)) return; // do texture stuff gl_ux[0]=baseAddr[8];//gpuData[2]&0xff; @@ -4227,7 +4227,7 @@ void primPolyF3(unsigned char *baseAddr) lx2 = sgpuData[6]; ly2 = sgpuData[7]; - if(offset3()) return; + if(offset3(baseAddr)) return; bDrawTextured = FALSE; bDrawSmoothShaded = FALSE; @@ -4318,7 +4318,7 @@ void primLineGEx(unsigned char *baseAddr) ly1 = (short)((gpuData[i]>>16) & 0xffff); lx1 = (short)(gpuData[i] & 0xffff); - if(offsetline()) bDraw=FALSE; else bDraw=TRUE; + if(offsetline(baseAddr)) bDraw=FALSE; else bDraw=TRUE; if (bDraw && ((lx0 != lx1) || (ly0 != ly1))) { @@ -4367,7 +4367,7 @@ void primLineG2(unsigned char *baseAddr) if((lx0 == lx1) && (ly0 == ly1)) return; - if(offsetline()) return; + if(offsetline(baseAddr)) return; SetRenderState(gpuData[0]); SetRenderMode(gpuData[0], FALSE); @@ -4445,7 +4445,7 @@ void primLineFEx(unsigned char *baseAddr) ly1 = (short)((gpuData[i]>>16) & 0xffff); lx1 = (short)(gpuData[i] & 0xffff); - if(!offsetline()) + if(!offsetline(baseAddr)) { if(iOffscreenDrawing) { @@ -4481,7 +4481,7 @@ void primLineF2(unsigned char *baseAddr) lx1 = sgpuData[4]; ly1 = sgpuData[5]; - if(offsetline()) return; + if(offsetline(baseAddr)) return; bDrawTextured = FALSE; bDrawSmoothShaded = FALSE; diff --git a/win32/pcsxr.vcxproj b/win32/pcsxr.vcxproj index 6a273ff5..81893bf4 100755 --- a/win32/pcsxr.vcxproj +++ b/win32/pcsxr.vcxproj @@ -199,6 +199,7 @@ %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -418,6 +419,7 @@ + diff --git a/win32/pcsxr.vcxproj.filters b/win32/pcsxr.vcxproj.filters index 09c5b72b..5c714f63 100755 --- a/win32/pcsxr.vcxproj.filters +++ b/win32/pcsxr.vcxproj.filters @@ -192,6 +192,9 @@ zlib + + libpcsxcore + @@ -355,6 +358,9 @@ zlib + + libpcsxcore + diff --git a/win32/plugins/peopsxgl/gpuPeopsOpenGL.def b/win32/plugins/peopsxgl/gpuPeopsOpenGL.def index 17d2e66c..83d853a7 100755 --- a/win32/plugins/peopsxgl/gpuPeopsOpenGL.def +++ b/win32/plugins/peopsxgl/gpuPeopsOpenGL.def @@ -34,3 +34,4 @@ EXPORTS GPUsetframelimit @27 GPUvisualVibration @28 GPUaddVertex @29 + GPUpgxpMemory @30 diff --git a/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj b/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj index b72348bd..f65ce2cb 100755 --- a/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj +++ b/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj @@ -152,6 +152,7 @@ + %(AdditionalIncludeDirectories) %(PreprocessorDefinitions) @@ -221,6 +222,7 @@ + diff --git a/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj.filters b/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj.filters index 69b2b9b9..d34a9a34 100755 --- a/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj.filters +++ b/win32/plugins/peopsxgl/gpuPeopsOpenGL.vcxproj.filters @@ -45,6 +45,9 @@ peopsxgl + + peopsxgl + @@ -90,6 +93,9 @@ peopsxgl + + peopsxgl + diff --git a/win32/plugins/peopsxgl/pgxp_gpu.c b/win32/plugins/peopsxgl/pgxp_gpu.c new file mode 100644 index 00000000..5b64382a --- /dev/null +++ b/win32/plugins/peopsxgl/pgxp_gpu.c @@ -0,0 +1,90 @@ +/*************************************************************************** +* Copyright (C) 2016 by iCatButler * +* * +* 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; either version 2 of the License, or * +* (at your option) any later version. * +* * +* 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 for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +/************************************************************************** +* pgxp_gpu.c +* PGXP - Parallel/Precision Geometry Xform Pipeline +* +* Created on: 25 Mar 2016 +* Author: iCatButler +***************************************************************************/ + +#include "pgxp_gpu.h" +#include "stdafx.h" +#include "externals.h" + +#include + +typedef struct +{ + float x; + float y; + float z; + unsigned int valid; + unsigned int count; +} PGXP_vertex; + +const unsigned int primStrideTable[] = { 1, 2, 1, 2, 2, 3, 2, 3, 0 }; +const unsigned int primCountTable[] = { 3, 3, 4, 4, 3, 3, 4, 4, 0 }; + +PGXP_vertex* PGXP_Mem = NULL; // pointer to parallel memory +unsigned int currentAddr = 0; // address of current DMA + +// Set current DMA address and pointer to parallel memory +void CALLBACK GPUpgxpMemory(unsigned int addr, unsigned char* pVRAM) +{ + if (pVRAM) + PGXP_Mem = (PGXP_vertex*)(pVRAM); + currentAddr = addr; +} + +// Set current DMA address +void PGXP_SetAddress(unsigned int addr) +{ + currentAddr = addr; +} + +// Get parallel vertex values +int PGXP_GetVertices(unsigned int* addr, void* pOutput) +{ + unsigned int primCmd = ((*addr >> 24) & 0xff); // primitive command + unsigned int primIdx = (primCmd - 0x20) >> 2; // index to primitive lookup + OGLVertex* pVertex = (OGLVertex*)pOutput; // pointer to output vertices + unsigned int stride = primStrideTable[primIdx]; // stride between vertices + unsigned int count = primCountTable[primIdx]; // number of vertices + PGXP_vertex* primStart = NULL; // pointer to first vertex + + if (PGXP_Mem == NULL) + return 0; + + // Offset to start of primitive + primStart = &PGXP_Mem[currentAddr + 1]; + + for (unsigned i = 0; i < count; ++i) + { + if (primStart[stride * i].valid) + { + pVertex[i].x = primStart[stride * i].x; + pVertex[i].y = primStart[stride * i].y; + } + } + + return 1; +} + diff --git a/win32/plugins/peopsxgl/pgxp_gpu.h b/win32/plugins/peopsxgl/pgxp_gpu.h new file mode 100644 index 00000000..1777dc19 --- /dev/null +++ b/win32/plugins/peopsxgl/pgxp_gpu.h @@ -0,0 +1,34 @@ +/*************************************************************************** +* Copyright (C) 2016 by iCatButler * +* * +* 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; either version 2 of the License, or * +* (at your option) any later version. * +* * +* 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 for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program; if not, write to the * +* Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +***************************************************************************/ + +/************************************************************************** +* pgxp_gpu.h +* PGXP - Parallel/Precision Geometry Xform Pipeline +* +* Created on: 25 Mar 2016 +* Author: iCatButler +***************************************************************************/ + +#ifndef _PGXP_GPU_H_ +#define _PGXP_GPU_H_ + +void PGXP_SetAddress(unsigned int addr); +int PGXP_GetVertices(unsigned int* addr, void* pOutput); + +#endif // _PGXP_GPU_H_