pcsx2/plugins/GSdx/GS.h
Kojin 79f2468952 GSdx: Purge D3D11 Software
F9 now has the following functionality on Windows:
- If the renderer in the config is D3D11, switch between D3D11 and SW
- If the renderer in the config is OGL, switch between OGL and SW
- If the renderer in the config is SW, switch between SW and the renderer returned by GetBestRenderer()
2020-09-21 20:30:20 -04:00

1460 lines
26 KiB
C++

/*
* 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,
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