/* * Copyright (C) 2007-2009 Gabest * http://www.gabest.org * * 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, 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 GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA. * http://www.gnu.org/copyleft/gpl.html * */ #pragma once #define PLUGIN_VERSION 0 #define VM_SIZE 4194304u #define HALF_VM_SIZE (VM_SIZE / 2u) #define PAGE_SIZE 8192u #define BLOCK_SIZE 256u #define COLUMN_SIZE 64u #define MAX_PAGES (VM_SIZE / PAGE_SIZE) #define MAX_BLOCKS (VM_SIZE / BLOCK_SIZE) #define MAX_COLUMNS (VM_SIZE / COLUMN_SIZE) //if defined, will send much info in reply to the API title info queri from PCSX2 //default should be undefined //#define GSTITLEINFO_API_FORCE_VERBOSE #include "GSVector.h" #pragma pack(push, 1) enum GS_PRIM { GS_POINTLIST = 0, GS_LINELIST = 1, GS_LINESTRIP = 2, GS_TRIANGLELIST = 3, GS_TRIANGLESTRIP = 4, GS_TRIANGLEFAN = 5, GS_SPRITE = 6, GS_INVALID = 7, }; enum GS_PRIM_CLASS { GS_POINT_CLASS = 0, GS_LINE_CLASS = 1, GS_TRIANGLE_CLASS = 2, GS_SPRITE_CLASS = 3, GS_INVALID_CLASS = 7, }; enum GIF_REG { GIF_REG_PRIM = 0x00, GIF_REG_RGBA = 0x01, GIF_REG_STQ = 0x02, GIF_REG_UV = 0x03, GIF_REG_XYZF2 = 0x04, GIF_REG_XYZ2 = 0x05, GIF_REG_TEX0_1 = 0x06, GIF_REG_TEX0_2 = 0x07, GIF_REG_CLAMP_1 = 0x08, GIF_REG_CLAMP_2 = 0x09, GIF_REG_FOG = 0x0a, GIF_REG_INVALID = 0x0b, GIF_REG_XYZF3 = 0x0c, GIF_REG_XYZ3 = 0x0d, GIF_REG_A_D = 0x0e, GIF_REG_NOP = 0x0f, }; enum GIF_REG_COMPLEX { GIF_REG_STQRGBAXYZF2 = 0x00, GIF_REG_STQRGBAXYZ2 = 0x01, }; enum GIF_A_D_REG { GIF_A_D_REG_PRIM = 0x00, GIF_A_D_REG_RGBAQ = 0x01, GIF_A_D_REG_ST = 0x02, GIF_A_D_REG_UV = 0x03, GIF_A_D_REG_XYZF2 = 0x04, GIF_A_D_REG_XYZ2 = 0x05, GIF_A_D_REG_TEX0_1 = 0x06, GIF_A_D_REG_TEX0_2 = 0x07, GIF_A_D_REG_CLAMP_1 = 0x08, GIF_A_D_REG_CLAMP_2 = 0x09, GIF_A_D_REG_FOG = 0x0a, GIF_A_D_REG_XYZF3 = 0x0c, GIF_A_D_REG_XYZ3 = 0x0d, GIF_A_D_REG_NOP = 0x0f, GIF_A_D_REG_TEX1_1 = 0x14, GIF_A_D_REG_TEX1_2 = 0x15, GIF_A_D_REG_TEX2_1 = 0x16, GIF_A_D_REG_TEX2_2 = 0x17, GIF_A_D_REG_XYOFFSET_1 = 0x18, GIF_A_D_REG_XYOFFSET_2 = 0x19, GIF_A_D_REG_PRMODECONT = 0x1a, GIF_A_D_REG_PRMODE = 0x1b, GIF_A_D_REG_TEXCLUT = 0x1c, GIF_A_D_REG_SCANMSK = 0x22, GIF_A_D_REG_MIPTBP1_1 = 0x34, GIF_A_D_REG_MIPTBP1_2 = 0x35, GIF_A_D_REG_MIPTBP2_1 = 0x36, GIF_A_D_REG_MIPTBP2_2 = 0x37, GIF_A_D_REG_TEXA = 0x3b, GIF_A_D_REG_FOGCOL = 0x3d, GIF_A_D_REG_TEXFLUSH = 0x3f, GIF_A_D_REG_SCISSOR_1 = 0x40, GIF_A_D_REG_SCISSOR_2 = 0x41, GIF_A_D_REG_ALPHA_1 = 0x42, GIF_A_D_REG_ALPHA_2 = 0x43, GIF_A_D_REG_DIMX = 0x44, GIF_A_D_REG_DTHE = 0x45, GIF_A_D_REG_COLCLAMP = 0x46, GIF_A_D_REG_TEST_1 = 0x47, GIF_A_D_REG_TEST_2 = 0x48, GIF_A_D_REG_PABE = 0x49, GIF_A_D_REG_FBA_1 = 0x4a, GIF_A_D_REG_FBA_2 = 0x4b, GIF_A_D_REG_FRAME_1 = 0x4c, GIF_A_D_REG_FRAME_2 = 0x4d, GIF_A_D_REG_ZBUF_1 = 0x4e, GIF_A_D_REG_ZBUF_2 = 0x4f, GIF_A_D_REG_BITBLTBUF = 0x50, GIF_A_D_REG_TRXPOS = 0x51, GIF_A_D_REG_TRXREG = 0x52, GIF_A_D_REG_TRXDIR = 0x53, GIF_A_D_REG_HWREG = 0x54, GIF_A_D_REG_SIGNAL = 0x60, GIF_A_D_REG_FINISH = 0x61, GIF_A_D_REG_LABEL = 0x62, }; enum GIF_FLG { GIF_FLG_PACKED = 0, GIF_FLG_REGLIST = 1, GIF_FLG_IMAGE = 2, GIF_FLG_IMAGE2 = 3 }; enum GS_PSM { PSM_PSMCT32 = 0, // 0000-0000 PSM_PSMCT24 = 1, // 0000-0001 PSM_PSMCT16 = 2, // 0000-0010 PSM_PSMCT16S = 10, // 0000-1010 PSM_PSGPU24 = 18, // 0001-0010 PSM_PSMT8 = 19, // 0001-0011 PSM_PSMT4 = 20, // 0001-0100 PSM_PSMT8H = 27, // 0001-1011 PSM_PSMT4HL = 36, // 0010-0100 PSM_PSMT4HH = 44, // 0010-1100 PSM_PSMZ32 = 48, // 0011-0000 PSM_PSMZ24 = 49, // 0011-0001 PSM_PSMZ16 = 50, // 0011-0010 PSM_PSMZ16S = 58, // 0011-1010 }; enum GS_TFX { TFX_MODULATE = 0, TFX_DECAL = 1, TFX_HIGHLIGHT = 2, TFX_HIGHLIGHT2 = 3, TFX_NONE = 4, }; enum GS_CLAMP { CLAMP_REPEAT = 0, CLAMP_CLAMP = 1, CLAMP_REGION_CLAMP = 2, CLAMP_REGION_REPEAT = 3, }; enum GS_ZTST { ZTST_NEVER = 0, ZTST_ALWAYS = 1, ZTST_GEQUAL = 2, ZTST_GREATER = 3, }; enum GS_ATST { ATST_NEVER = 0, ATST_ALWAYS = 1, ATST_LESS = 2, ATST_LEQUAL = 3, ATST_EQUAL = 4, ATST_GEQUAL = 5, ATST_GREATER = 6, ATST_NOTEQUAL = 7, }; enum GS_AFAIL { AFAIL_KEEP = 0, AFAIL_FB_ONLY = 1, AFAIL_ZB_ONLY = 2, AFAIL_RGB_ONLY = 3, }; enum class GS_MIN_FILTER : uint8_t { Nearest = 0, Linear = 1, Nearest_Mipmap_Nearest = 2, Nearest_Mipmap_Linear = 3, Linear_Mipmap_Nearest = 4, Linear_Mipmap_Linear = 5, }; enum class GSRendererType : int8_t { Undefined = -1, DX1011_HW = 3, DX1011_SW, Null = 11, OGL_HW, OGL_SW, #ifdef _WIN32 Default = Undefined #else // Use ogl renderer as default otherwise it crash at startup // GSRenderOGL only GSDeviceOGL (not GSDeviceNULL) Default = OGL_HW #endif }; #define REG32(name) \ union name \ { \ uint32 u32; \ struct { \ #define REG64(name) \ union name \ { \ uint64 u64; \ uint32 u32[2]; \ void operator = (const GSVector4i& v) {GSVector4i::storel(this, v);} \ bool operator == (const union name& r) const {return ((GSVector4i)r).eq(*this);} \ bool operator != (const union name& r) const {return !((GSVector4i)r).eq(*this);} \ operator GSVector4i() const {return GSVector4i::loadl(this);} \ struct { \ #define REG128(name)\ union name \ { \ uint64 u64[2]; \ uint32 u32[4]; \ struct { \ #define REG32_(prefix, name) REG32(prefix##name) #define REG64_(prefix, name) REG64(prefix##name) #define REG128_(prefix, name) REG128(prefix##name) #define REG_END }; }; #define REG_END2 }; #define REG32_SET(name) \ union name \ { \ uint32 u32; \ #define REG64_SET(name) \ union name \ { \ uint64 u64; \ uint32 u32[2]; \ #define REG128_SET(name)\ union name \ { \ __m128i m128; \ uint64 u64[2]; \ uint32 u32[4]; \ #define REG_SET_END }; REG64_(GSReg, BGCOLOR) uint8 R; uint8 G; uint8 B; uint8 _PAD1[5]; REG_END REG64_(GSReg, BUSDIR) uint32 DIR:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GSReg, CSR) uint32 rSIGNAL:1; uint32 rFINISH:1; uint32 rHSINT:1; uint32 rVSINT:1; uint32 rEDWINT:1; uint32 rZERO1:1; uint32 rZERO2:1; uint32 r_PAD1:1; uint32 rFLUSH:1; uint32 rRESET:1; uint32 r_PAD2:2; uint32 rNFIELD:1; uint32 rFIELD:1; uint32 rFIFO:2; uint32 rREV:8; uint32 rID:8; uint32 wSIGNAL:1; uint32 wFINISH:1; uint32 wHSINT:1; uint32 wVSINT:1; uint32 wEDWINT:1; uint32 wZERO1:1; uint32 wZERO2:1; uint32 w_PAD1:1; uint32 wFLUSH:1; uint32 wRESET:1; uint32 w_PAD2:2; uint32 wNFIELD:1; uint32 wFIELD:1; uint32 wFIFO:2; uint32 wREV:8; uint32 wID:8; REG_END REG64_(GSReg, DISPFB) // (-1/2) uint32 FBP:9; uint32 FBW:6; uint32 PSM:5; uint32 _PAD:12; uint32 DBX:11; uint32 DBY:11; uint32 _PAD2:10; REG_END2 uint32 Block() const {return FBP << 5;} REG_END2 REG64_(GSReg, DISPLAY) // (-1/2) uint32 DX:12; uint32 DY:11; uint32 MAGH:4; uint32 MAGV:2; uint32 _PAD:3; uint32 DW:12; uint32 DH:11; uint32 _PAD2:9; REG_END REG64_(GSReg, EXTBUF) uint32 EXBP:14; uint32 EXBW:6; uint32 FBIN:2; uint32 WFFMD:1; uint32 EMODA:2; uint32 EMODC:2; uint32 _PAD1:5; uint32 WDX:11; uint32 WDY:11; uint32 _PAD2:10; REG_END REG64_(GSReg, EXTDATA) uint32 SX:12; uint32 SY:11; uint32 SMPH:4; uint32 SMPV:2; uint32 _PAD1:3; uint32 WW:12; uint32 WH:11; uint32 _PAD2:9; REG_END REG64_(GSReg, EXTWRITE) uint32 WRITE:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GSReg, IMR) uint32 _PAD1:8; uint32 SIGMSK:1; uint32 FINISHMSK:1; uint32 HSMSK:1; uint32 VSMSK:1; uint32 EDWMSK:1; uint32 _PAD2:19; uint32 _PAD3:32; REG_END REG64_(GSReg, PMODE) union { struct { uint32 EN1:1; uint32 EN2:1; uint32 CRTMD:3; uint32 MMOD:1; uint32 AMOD:1; uint32 SLBG:1; uint32 ALP:8; uint32 _PAD:16; uint32 _PAD1:32; }; struct { uint32 EN:2; uint32 _PAD2:30; uint32 _PAD3:32; }; }; REG_END REG64_(GSReg, SIGLBLID) uint32 SIGID; uint32 LBLID; REG_END REG64_(GSReg, SMODE1) uint32 RC:3; uint32 LC:7; uint32 T1248:2; uint32 SLCK:1; uint32 CMOD:2; uint32 EX:1; uint32 PRST:1; uint32 SINT:1; uint32 XPCK:1; uint32 PCK2:2; uint32 SPML:4; uint32 GCONT:1; // YCrCb uint32 PHS:1; uint32 PVS:1; uint32 PEHS:1; uint32 PEVS:1; uint32 CLKSEL:2; uint32 NVCK:1; uint32 SLCK2:1; uint32 VCKSEL:2; uint32 VHP:1; uint32 _PAD1:27; REG_END /* // pal CLKSEL=1 CMOD=3 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 // ntsc CLKSEL=1 CMOD=2 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=4 T1248=1 VCKSEL=1 VHP=0 XPCK=0 // ntsc progressive (SoTC) CLKSEL=1 CMOD=0 EX=0 GCONT=0 LC=32 NVCK=1 PCK2=0 PEHS=0 PEVS=0 PHS=0 PRST=1 PVS=0 RC=4 SINT=0 SLCK=0 SLCK2=1 SPML=2 T1248=1 VCKSEL=1 VHP=1 XPCK=0 */ REG64_(GSReg, SMODE2) uint32 INT:1; uint32 FFMD:1; uint32 DPMS:2; uint32 _PAD2:28; uint32 _PAD3:32; REG_END REG64_(GSReg, SRFSH) uint32 _DUMMY; // TODO REG_END REG64_(GSReg, SYNCH1) uint32 _DUMMY; // TODO REG_END REG64_(GSReg, SYNCH2) uint32 _DUMMY; // TODO REG_END REG64_(GSReg, SYNCV) uint32 VFP:10; // Vertical Front Porchinterval (?s) uint32 VFPE:10; // Vertical Front Porchinterval End (?s) uint32 VBP:12; // Vertical Back Porchinterval (?s) uint32 VBPE:10; // Vertical Back Porchinterval End (?s) uint32 VDP:11; // Vertical Differential Phase uint32 VS:11; // Vertical Synchronization Timing REG_END REG64_SET(GSReg) GSRegBGCOLOR BGCOLOR; GSRegBUSDIR BUSDIR; GSRegCSR CSR; GSRegDISPFB DISPFB; GSRegDISPLAY DISPLAY; GSRegEXTBUF EXTBUF; GSRegEXTDATA EXTDATA; GSRegEXTWRITE EXTWRITE; GSRegIMR IMR; GSRegPMODE PMODE; GSRegSIGLBLID SIGLBLID; GSRegSMODE1 SMODE1; GSRegSMODE2 SMODE2; REG_SET_END // // GIFTag REG128(GIFTag) uint32 NLOOP:15; uint32 EOP:1; uint32 _PAD1:16; uint32 _PAD2:14; uint32 PRE:1; uint32 PRIM:11; uint32 FLG:2; // enum GIF_FLG uint32 NREG:4; uint64 REGS; REG_END // GIFReg REG64_(GIFReg, ALPHA) uint32 A:2; uint32 B:2; uint32 C:2; uint32 D:2; uint32 _PAD1:24; uint8 FIX; uint8 _PAD2[3]; REG_END2 // opaque => output will be Cs/As __forceinline bool IsOpaque() const {return ((A == B || (C == 2 && FIX == 0)) && D == 0) || (A == 0 && B == D && C == 2 && FIX == 0x80);} __forceinline bool IsOpaque(int amin, int amax) const {return ((A == B || amax == 0) && D == 0) || (A == 0 && B == D && amin == 0x80 && amax == 0x80);} __forceinline bool IsCd() { return (A == B) && (D == 1);} REG_END2 REG64_(GIFReg, BITBLTBUF) uint32 SBP:14; uint32 _PAD1:2; uint32 SBW:6; uint32 _PAD2:2; uint32 SPSM:6; uint32 _PAD3:2; uint32 DBP:14; uint32 _PAD4:2; uint32 DBW:6; uint32 _PAD5:2; uint32 DPSM:6; uint32 _PAD6:2; REG_END REG64_(GIFReg, CLAMP) union { struct { uint32 WMS:2; uint32 WMT:2; uint32 MINU:10; uint32 MAXU:10; uint32 _PAD1:8; uint32 _PAD2:2; uint32 MAXV:10; uint32 _PAD3:20; }; struct { uint64 _PAD4:24; uint64 MINV:10; uint64 _PAD5:30; }; }; REG_END REG64_(GIFReg, COLCLAMP) uint32 CLAMP:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GIFReg, DIMX) int32 DM00:3; int32 _PAD00:1; int32 DM01:3; int32 _PAD01:1; int32 DM02:3; int32 _PAD02:1; int32 DM03:3; int32 _PAD03:1; int32 DM10:3; int32 _PAD10:1; int32 DM11:3; int32 _PAD11:1; int32 DM12:3; int32 _PAD12:1; int32 DM13:3; int32 _PAD13:1; int32 DM20:3; int32 _PAD20:1; int32 DM21:3; int32 _PAD21:1; int32 DM22:3; int32 _PAD22:1; int32 DM23:3; int32 _PAD23:1; int32 DM30:3; int32 _PAD30:1; int32 DM31:3; int32 _PAD31:1; int32 DM32:3; int32 _PAD32:1; int32 DM33:3; int32 _PAD33:1; REG_END REG64_(GIFReg, DTHE) uint32 DTHE:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GIFReg, FBA) uint32 FBA:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GIFReg, FINISH) uint32 _PAD1[2]; REG_END REG64_(GIFReg, FOG) uint8 _PAD1[7]; uint8 F; REG_END REG64_(GIFReg, FOGCOL) uint8 FCR; uint8 FCG; uint8 FCB; uint8 _PAD1[5]; REG_END REG64_(GIFReg, FRAME) uint32 FBP:9; uint32 _PAD1:7; uint32 FBW:6; uint32 _PAD2:2; uint32 PSM:6; uint32 _PAD3:2; uint32 FBMSK; REG_END2 uint32 Block() const {return FBP << 5;} REG_END2 REG64_(GIFReg, HWREG) uint32 DATA_LOWER; uint32 DATA_UPPER; REG_END REG64_(GIFReg, LABEL) uint32 ID; uint32 IDMSK; REG_END REG64_(GIFReg, MIPTBP1) uint64 TBP1:14; uint64 TBW1:6; uint64 TBP2:14; uint64 TBW2:6; uint64 TBP3:14; uint64 TBW3:6; uint64 _PAD:4; REG_END REG64_(GIFReg, MIPTBP2) uint64 TBP4:14; uint64 TBW4:6; uint64 TBP5:14; uint64 TBW5:6; uint64 TBP6:14; uint64 TBW6:6; uint64 _PAD:4; REG_END REG64_(GIFReg, NOP) uint32 _PAD[2]; REG_END REG64_(GIFReg, PABE) uint32 PABE:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GIFReg, PRIM) uint32 PRIM:3; uint32 IIP:1; uint32 TME:1; uint32 FGE:1; uint32 ABE:1; uint32 AA1:1; uint32 FST:1; uint32 CTXT:1; uint32 FIX:1; uint32 _PAD1:21; uint32 _PAD2:32; REG_END REG64_(GIFReg, PRMODE) uint32 _PRIM:3; uint32 IIP:1; uint32 TME:1; uint32 FGE:1; uint32 ABE:1; uint32 AA1:1; uint32 FST:1; uint32 CTXT:1; uint32 FIX:1; uint32 _PAD2:21; uint32 _PAD3:32; REG_END REG64_(GIFReg, PRMODECONT) uint32 AC:1; uint32 _PAD1:31; uint32 _PAD2:32; REG_END REG64_(GIFReg, RGBAQ) uint8 R; uint8 G; uint8 B; uint8 A; float Q; REG_END REG64_(GIFReg, SCANMSK) uint32 MSK:2; uint32 _PAD1:30; uint32 _PAD2:32; REG_END REG64_(GIFReg, SCISSOR) uint32 SCAX0:11; uint32 _PAD1:5; uint32 SCAX1:11; uint32 _PAD2:5; uint32 SCAY0:11; uint32 _PAD3:5; uint32 SCAY1:11; uint32 _PAD4:5; REG_END REG64_(GIFReg, SIGNAL) uint32 ID; uint32 IDMSK; REG_END REG64_(GIFReg, ST) float S; float T; REG_END REG64_(GIFReg, TEST) uint32 ATE:1; uint32 ATST:3; uint32 AREF:8; uint32 AFAIL:2; uint32 DATE:1; uint32 DATM:1; uint32 ZTE:1; uint32 ZTST:2; uint32 _PAD1:13; uint32 _PAD2:32; REG_END2 __forceinline bool DoFirstPass() const {return !ATE || ATST != ATST_NEVER;} // not all pixels fail automatically __forceinline bool DoSecondPass() const {return ATE && ATST != ATST_ALWAYS && AFAIL != AFAIL_KEEP;} // pixels may fail, write fb/z __forceinline bool NoSecondPass() const {return ATE && ATST != ATST_ALWAYS && AFAIL == AFAIL_KEEP;} // pixels may fail, no output REG_END2 REG64_(GIFReg, TEX0) union { struct { uint32 TBP0:14; uint32 TBW:6; uint32 PSM:6; uint32 TW:4; uint32 _PAD1:2; uint32 _PAD2:2; uint32 TCC:1; uint32 TFX:2; uint32 CBP:14; uint32 CPSM:4; uint32 CSM:1; uint32 CSA:5; uint32 CLD:3; }; struct { uint64 _PAD3:30; uint64 TH:4; uint64 _PAD4:30; }; }; REG_END2 __forceinline bool IsRepeating() const { if(TBW < 2) { if(PSM == PSM_PSMT8) return TW > 7 || TH > 6; if(PSM == PSM_PSMT4) return TW > 7 || TH > 7; } // The recast of TBW seems useless but it avoid tons of warning from GCC... return ((uint32)TBW << 6u) < (1u << TW); } REG_END2 REG64_(GIFReg, TEX1) uint32 LCM:1; uint32 _PAD1:1; uint32 MXL:3; uint32 MMAG:1; uint32 MMIN:3; uint32 MTBA:1; uint32 _PAD2:9; uint32 L:2; uint32 _PAD3:11; int32 K:12; // 1:7:4 uint32 _PAD4:20; REG_END2 bool IsMinLinear() const {return (MMIN == 1) || (MMIN & 4);} bool IsMagLinear() const {return MMAG;} REG_END2 REG64_(GIFReg, TEX2) uint32 _PAD1:20; uint32 PSM:6; uint32 _PAD2:6; uint32 _PAD3:5; uint32 CBP:14; uint32 CPSM:4; uint32 CSM:1; uint32 CSA:5; uint32 CLD:3; REG_END REG64_(GIFReg, TEXA) uint8 TA0; uint8 _PAD1:7; uint8 AEM:1; uint16 _PAD2; uint8 TA1:8; uint8 _PAD3[3]; REG_END REG64_(GIFReg, TEXCLUT) uint32 CBW:6; uint32 COU:6; uint32 COV:10; uint32 _PAD1:10; uint32 _PAD2:32; REG_END REG64_(GIFReg, TEXFLUSH) uint32 _PAD1:32; uint32 _PAD2:32; REG_END REG64_(GIFReg, TRXDIR) uint32 XDIR:2; uint32 _PAD1:30; uint32 _PAD2:32; REG_END REG64_(GIFReg, TRXPOS) uint32 SSAX:11; uint32 _PAD1:5; uint32 SSAY:11; uint32 _PAD2:5; uint32 DSAX:11; uint32 _PAD3:5; uint32 DSAY:11; uint32 DIRY:1; uint32 DIRX:1; uint32 _PAD4:3; REG_END REG64_(GIFReg, TRXREG) uint32 RRW:12; uint32 _PAD1:20; uint32 RRH:12; uint32 _PAD2:20; REG_END // GSState::GIFPackedRegHandlerUV and GSState::GIFRegHandlerUV will make sure that the _PAD1/2 bits are set to zero REG64_(GIFReg, UV) uint16 U; // uint32 _PAD1:2; uint16 V; // uint32 _PAD2:2; uint32 _PAD3; REG_END // GSState::GIFRegHandlerXYOFFSET will make sure that the _PAD1/2 bits are set to zero REG64_(GIFReg, XYOFFSET) uint32 OFX; // :16; uint32 _PAD1:16; uint32 OFY; // :16; uint32 _PAD2:16; REG_END REG64_(GIFReg, XYZ) uint16 X; uint16 Y; uint32 Z; REG_END REG64_(GIFReg, XYZF) uint16 X; uint16 Y; uint32 Z:24; uint32 F:8; REG_END REG64_(GIFReg, ZBUF) uint32 ZBP:9; uint32 _PAD1:15; // uint32 PSM:4; // uint32 _PAD2:4; uint32 PSM:6; uint32 _PAD2:2; uint32 ZMSK:1; uint32 _PAD3:31; REG_END2 uint32 Block() const {return ZBP << 5;} REG_END2 REG64_SET(GIFReg) GIFRegALPHA ALPHA; GIFRegBITBLTBUF BITBLTBUF; GIFRegCLAMP CLAMP; GIFRegCOLCLAMP COLCLAMP; GIFRegDIMX DIMX; GIFRegDTHE DTHE; GIFRegFBA FBA; GIFRegFINISH FINISH; GIFRegFOG FOG; GIFRegFOGCOL FOGCOL; GIFRegFRAME FRAME; GIFRegHWREG HWREG; GIFRegLABEL LABEL; GIFRegMIPTBP1 MIPTBP1; GIFRegMIPTBP2 MIPTBP2; GIFRegNOP NOP; GIFRegPABE PABE; GIFRegPRIM PRIM; GIFRegPRMODE PRMODE; GIFRegPRMODECONT PRMODECONT; GIFRegRGBAQ RGBAQ; GIFRegSCANMSK SCANMSK; GIFRegSCISSOR SCISSOR; GIFRegSIGNAL SIGNAL; GIFRegST ST; GIFRegTEST TEST; GIFRegTEX0 TEX0; GIFRegTEX1 TEX1; GIFRegTEX2 TEX2; GIFRegTEXA TEXA; GIFRegTEXCLUT TEXCLUT; GIFRegTEXFLUSH TEXFLUSH; GIFRegTRXDIR TRXDIR; GIFRegTRXPOS TRXPOS; GIFRegTRXREG TRXREG; GIFRegUV UV; GIFRegXYOFFSET XYOFFSET; GIFRegXYZ XYZ; GIFRegXYZF XYZF; GIFRegZBUF ZBUF; REG_SET_END // GIFPacked REG128_(GIFPacked, PRIM) uint32 PRIM:11; uint32 _PAD1:21; uint32 _PAD2[3]; REG_END REG128_(GIFPacked, RGBA) uint8 R; uint8 _PAD1[3]; uint8 G; uint8 _PAD2[3]; uint8 B; uint8 _PAD3[3]; uint8 A; uint8 _PAD4[3]; REG_END REG128_(GIFPacked, STQ) float S; float T; float Q; uint32 _PAD1:32; REG_END REG128_(GIFPacked, UV) uint32 U:14; uint32 _PAD1:18; uint32 V:14; uint32 _PAD2:18; uint32 _PAD3:32; uint32 _PAD4:32; REG_END REG128_(GIFPacked, XYZF2) uint16 X; uint16 _PAD1; uint16 Y; uint16 _PAD2; uint32 _PAD3:4; uint32 Z:24; uint32 _PAD4:4; uint32 _PAD5:4; uint32 F:8; uint32 _PAD6:3; uint32 ADC:1; uint32 _PAD7:16; REG_END2 uint32 Skip() const {return u32[3] & 0x8000;} REG_END2 REG128_(GIFPacked, XYZ2) uint16 X; uint16 _PAD1; uint16 Y; uint16 _PAD2; uint32 Z; uint32 _PAD3:15; uint32 ADC:1; uint32 _PAD4:16; REG_END2 uint32 Skip() const {return u32[3] & 0x8000;} REG_END2 REG128_(GIFPacked, FOG) uint32 _PAD1; uint32 _PAD2; uint32 _PAD3; uint32 _PAD4:4; uint32 F:8; uint32 _PAD5:20; REG_END REG128_(GIFPacked, A_D) uint64 DATA; uint8 ADDR:8; // enum GIF_A_D_REG uint8 _PAD1[3+4]; REG_END REG128_(GIFPacked, NOP) uint32 _PAD1; uint32 _PAD2; uint32 _PAD3; uint32 _PAD4; REG_END REG128_SET(GIFPackedReg) GIFReg r; GIFPackedPRIM PRIM; GIFPackedRGBA RGBA; GIFPackedSTQ STQ; GIFPackedUV UV; GIFPackedXYZF2 XYZF2; GIFPackedXYZ2 XYZ2; GIFPackedFOG FOG; GIFPackedA_D A_D; GIFPackedNOP NOP; REG_SET_END struct alignas(32) GIFPath { GIFTag tag; uint32 nloop; uint32 nreg; uint32 reg; uint32 type; GSVector4i regs; enum {TYPE_UNKNOWN, TYPE_ADONLY, TYPE_STQRGBAXYZF2, TYPE_STQRGBAXYZ2}; __forceinline void SetTag(const void* mem) { const GIFTag* RESTRICT src = (const GIFTag*)mem; // the compiler has a hard time not reloading every time a field of src is accessed uint32 a = src->u32[0]; uint32 b = src->u32[1]; tag.u32[0] = a; tag.u32[1] = b; nloop = a & 0x7fff; if(nloop == 0) return; GSVector4i v = GSVector4i::loadl(&src->REGS); // REGS not stored to tag.REGS, only into this->regs, restored before saving the state though nreg = (b & 0xf0000000) ? (b >> 28) : 16; // src->NREG regs = v.upl8(v >> 4) & GSVector4i::x0f(nreg); reg = 0; type = TYPE_UNKNOWN; if(tag.FLG == GIF_FLG_PACKED) { if(regs.eq8(GSVector4i(0x0e0e0e0e)).mask() == (1 << nreg) - 1) { type = TYPE_ADONLY; } else { switch(nreg) { case 1: break; case 2: break; case 3: if(regs.u32[0] == 0x00040102) type = TYPE_STQRGBAXYZF2; // many games, TODO: formats mixed with NOPs (xeno2: 040f010f02, 04010f020f, mgs3: 04010f0f02, 0401020f0f, 04010f020f) if(regs.u32[0] == 0x00050102) type = TYPE_STQRGBAXYZ2; // GoW (has other crazy formats, like ...030503050103) // TODO: common types with UV instead break; case 4: break; case 5: break; case 6: break; case 7: break; case 8: break; case 9: if(regs.u32[0] == 0x02040102 && regs.u32[1] == 0x01020401 && regs.u32[2] == 0x00000004) {type = TYPE_STQRGBAXYZF2; nreg = 3; nloop *= 3;} // ffx break; case 10: break; case 11: break; case 12: if(regs.u32[0] == 0x02040102 && regs.u32[1] == 0x01020401 && regs.u32[2] == 0x04010204) {type = TYPE_STQRGBAXYZF2; nreg = 3; nloop *= 4;} // dq8 (not many, mostly 040102) break; case 13: break; case 14: break; case 15: break; case 16: break; default: __assume(0); } } } } __forceinline uint8 GetReg() const { return regs.u8[reg]; } __forceinline uint8 GetReg(uint32 index) const { return regs.u8[index]; } __forceinline bool StepReg() { if(++reg == nreg) { reg = 0; if(--nloop == 0) { return false; } } return true; } }; struct GSPrivRegSet { union { struct { GSRegPMODE PMODE; uint64 _pad1; GSRegSMODE1 SMODE1; uint64 _pad2; GSRegSMODE2 SMODE2; uint64 _pad3; GSRegSRFSH SRFSH; uint64 _pad4; GSRegSYNCH1 SYNCH1; uint64 _pad5; GSRegSYNCH2 SYNCH2; uint64 _pad6; GSRegSYNCV SYNCV; uint64 _pad7; struct { GSRegDISPFB DISPFB; uint64 _pad1; GSRegDISPLAY DISPLAY; uint64 _pad2; } DISP[2]; GSRegEXTBUF EXTBUF; uint64 _pad8; GSRegEXTDATA EXTDATA; uint64 _pad9; GSRegEXTWRITE EXTWRITE; uint64 _pad10; GSRegBGCOLOR BGCOLOR; uint64 _pad11; }; uint8 _pad12[0x1000]; }; union { struct { GSRegCSR CSR; uint64 _pad13; GSRegIMR IMR; uint64 _pad14; uint64 _unk1[4]; GSRegBUSDIR BUSDIR; uint64 _pad15; uint64 _unk2[6]; GSRegSIGLBLID SIGLBLID; uint64 _pad16; }; uint8 _pad17[0x1000]; }; void Dump(FILE* fp) { for(int i = 0; i < 2; i++) { if (!fp) return; if(i == 0 && !PMODE.EN1) continue; if(i == 1 && !PMODE.EN2) continue; fprintf(fp, "DISPFB[%d] BP=%05x BW=%u PSM=%u DBX=%u DBY=%u\n", i, DISP[i].DISPFB.Block(), DISP[i].DISPFB.FBW, DISP[i].DISPFB.PSM, DISP[i].DISPFB.DBX, DISP[i].DISPFB.DBY ); fprintf(fp, "DISPLAY[%d] DX=%u DY=%u DW=%u DH=%u MAGH=%u MAGV=%u\n", i, DISP[i].DISPLAY.DX, DISP[i].DISPLAY.DY, DISP[i].DISPLAY.DW, DISP[i].DISPLAY.DH, DISP[i].DISPLAY.MAGH, DISP[i].DISPLAY.MAGV ); } fprintf(fp, "PMODE EN1=%u EN2=%u CRTMD=%u MMOD=%u AMOD=%u SLBG=%u ALP=%u\n", PMODE.EN1, PMODE.EN2, PMODE.CRTMD, PMODE.MMOD, PMODE.AMOD, PMODE.SLBG, PMODE.ALP ); fprintf(fp, "SMODE1 CLKSEL=%u CMOD=%u EX=%u GCONT=%u LC=%u NVCK=%u PCK2=%u PEHS=%u PEVS=%u PHS=%u PRST=%u PVS=%u RC=%u SINT=%u SLCK=%u SLCK2=%u SPML=%u T1248=%u VCKSEL=%u VHP=%u XPCK=%u\n", SMODE1.CLKSEL, SMODE1.CMOD, SMODE1.EX, SMODE1.GCONT, SMODE1.LC, SMODE1.NVCK, SMODE1.PCK2, SMODE1.PEHS, SMODE1.PEVS, SMODE1.PHS, SMODE1.PRST, SMODE1.PVS, SMODE1.RC, SMODE1.SINT, SMODE1.SLCK, SMODE1.SLCK2, SMODE1.SPML, SMODE1.T1248, SMODE1.VCKSEL, SMODE1.VHP, SMODE1.XPCK ); fprintf(fp, "SMODE2 INT=%u FFMD=%u DPMS=%u\n", SMODE2.INT, SMODE2.FFMD, SMODE2.DPMS ); fprintf(fp, "SRFSH %08x_%08x\n", SRFSH.u32[0], SRFSH.u32[1] ); fprintf(fp, "SYNCH1 %08x_%08x\n", SYNCH1.u32[0], SYNCH1.u32[1] ); fprintf(fp, "SYNCH2 %08x_%08x\n", SYNCH2.u32[0], SYNCH2.u32[1] ); fprintf(fp, "SYNCV VBP=%u VBPE=%u VDP=%u VFP=%u VFPE=%u VS=%u\n", SYNCV.VBP, SYNCV.VBPE, SYNCV.VDP, SYNCV.VFP, SYNCV.VFPE, SYNCV.VS ); fprintf(fp, "CSR %08x_%08x\n", CSR.u32[0], CSR.u32[1] ); fprintf(fp, "BGCOLOR B=%u G=%u R=%u\n", BGCOLOR.B, BGCOLOR.G, BGCOLOR.R ); fprintf(fp, "EXTBUF BP=0x%x BW=%u FBIN=%u WFFMD=%u EMODA=%u EMODC=%u WDX=%u WDY=%u\n", EXTBUF.EXBP, EXTBUF.EXBW, EXTBUF.FBIN, EXTBUF.WFFMD, EXTBUF.EMODA, EXTBUF.EMODC, EXTBUF.WDX, EXTBUF.WDY ); fprintf(fp, "EXTDATA SX=%u SY=%u SMPH=%u SMPV=%u WW=%u WH=%u\n", EXTDATA.SX, EXTDATA.SY, EXTDATA.SMPH, EXTDATA.SMPV, EXTDATA.WW, EXTDATA.WH ); fprintf(fp, "EXTWRITE EN=%u\n", EXTWRITE.WRITE); } void Dump(const std::string& filename) { FILE* fp = fopen(filename.c_str(), "wt"); if (fp) { Dump(fp); fclose(fp); } } }; #pragma pack(pop) enum {KEYPRESS=1, KEYRELEASE=2}; struct GSKeyEventData {uint32 key, type;}; enum {FREEZE_LOAD=0, FREEZE_SAVE=1, FREEZE_SIZE=2}; struct GSFreezeData {int size; uint8* data;}; enum stateType {ST_WRITE, ST_TRANSFER, ST_VSYNC}; enum class GSVideoMode : uint8 { Unknown, NTSC, PAL, VESA, SDTV_480P, HDTV_720P, HDTV_1080I }; // Ordering was done to keep compatibility with older ini file. enum class BiFiltering : uint8 { Nearest, Forced, PS2, Forced_But_Sprite, }; enum class TriFiltering : uint8 { None, PS2, Forced, }; enum class HWMipmapLevel : int { Automatic = -1, Off, Basic, Full }; enum class CRCHackLevel : int8 { Automatic = -1, None, Minimum, Partial, Full, Aggressive }; #ifdef ENABLE_ACCURATE_BUFFER_EMULATION const GSVector2i default_rt_size(2048, 2048); #else const GSVector2i default_rt_size(1280, 1024); #endif