2015-05-23 22:55:12 -06:00
|
|
|
// Copyright 2009 Dolphin Emulator Project
|
2015-05-17 17:08:10 -06:00
|
|
|
// Licensed under GPLv2+
|
2013-04-17 21:09:55 -06:00
|
|
|
// Refer to the license.txt file included.
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2014-02-10 11:54:46 -07:00
|
|
|
#pragma once
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2014-05-24 19:55:13 -06:00
|
|
|
#include <string>
|
|
|
|
|
2014-03-10 09:15:40 -06:00
|
|
|
#include "Common/BitField.h"
|
2014-09-07 19:06:58 -06:00
|
|
|
#include "Common/CommonTypes.h"
|
2009-06-22 03:31:30 -06:00
|
|
|
|
|
|
|
#pragma pack(4)
|
|
|
|
|
2015-09-01 08:56:51 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
BPMEM_GENMODE = 0x00,
|
|
|
|
BPMEM_DISPLAYCOPYFILTER = 0x01, // 0x01 + 4
|
|
|
|
BPMEM_IND_MTXA = 0x06, // 0x06 + (3 * 3)
|
|
|
|
BPMEM_IND_MTXB = 0x07, // 0x07 + (3 * 3)
|
|
|
|
BPMEM_IND_MTXC = 0x08, // 0x08 + (3 * 3)
|
|
|
|
BPMEM_IND_IMASK = 0x0F,
|
|
|
|
BPMEM_IND_CMD = 0x10, // 0x10 + 16
|
|
|
|
BPMEM_SCISSORTL = 0x20,
|
|
|
|
BPMEM_SCISSORBR = 0x21,
|
|
|
|
BPMEM_LINEPTWIDTH = 0x22,
|
|
|
|
BPMEM_PERF0_TRI = 0x23,
|
|
|
|
BPMEM_PERF0_QUAD = 0x24,
|
|
|
|
BPMEM_RAS1_SS0 = 0x25,
|
|
|
|
BPMEM_RAS1_SS1 = 0x26,
|
|
|
|
BPMEM_IREF = 0x27,
|
|
|
|
BPMEM_TREF = 0x28, // 0x28 + 8
|
|
|
|
BPMEM_SU_SSIZE = 0x30, // 0x30 + (2 * 8)
|
|
|
|
BPMEM_SU_TSIZE = 0x31, // 0x31 + (2 * 8)
|
|
|
|
BPMEM_ZMODE = 0x40,
|
|
|
|
BPMEM_BLENDMODE = 0x41,
|
|
|
|
BPMEM_CONSTANTALPHA = 0x42,
|
|
|
|
BPMEM_ZCOMPARE = 0x43,
|
|
|
|
BPMEM_FIELDMASK = 0x44,
|
|
|
|
BPMEM_SETDRAWDONE = 0x45,
|
|
|
|
BPMEM_BUSCLOCK0 = 0x46,
|
|
|
|
BPMEM_PE_TOKEN_ID = 0x47,
|
|
|
|
BPMEM_PE_TOKEN_INT_ID = 0x48,
|
|
|
|
BPMEM_EFB_TL = 0x49,
|
|
|
|
BPMEM_EFB_BR = 0x4A,
|
|
|
|
BPMEM_EFB_ADDR = 0x4B,
|
|
|
|
BPMEM_MIPMAP_STRIDE = 0x4D,
|
|
|
|
BPMEM_COPYYSCALE = 0x4E,
|
|
|
|
BPMEM_CLEAR_AR = 0x4F,
|
|
|
|
BPMEM_CLEAR_GB = 0x50,
|
|
|
|
BPMEM_CLEAR_Z = 0x51,
|
|
|
|
BPMEM_TRIGGER_EFB_COPY = 0x52,
|
|
|
|
BPMEM_COPYFILTER0 = 0x53,
|
|
|
|
BPMEM_COPYFILTER1 = 0x54,
|
|
|
|
BPMEM_CLEARBBOX1 = 0x55,
|
|
|
|
BPMEM_CLEARBBOX2 = 0x56,
|
|
|
|
BPMEM_CLEAR_PIXEL_PERF = 0x57,
|
|
|
|
BPMEM_REVBITS = 0x58,
|
|
|
|
BPMEM_SCISSOROFFSET = 0x59,
|
|
|
|
BPMEM_PRELOAD_ADDR = 0x60,
|
|
|
|
BPMEM_PRELOAD_TMEMEVEN = 0x61,
|
|
|
|
BPMEM_PRELOAD_TMEMODD = 0x62,
|
|
|
|
BPMEM_PRELOAD_MODE = 0x63,
|
|
|
|
BPMEM_LOADTLUT0 = 0x64,
|
|
|
|
BPMEM_LOADTLUT1 = 0x65,
|
|
|
|
BPMEM_TEXINVALIDATE = 0x66,
|
|
|
|
BPMEM_PERF1 = 0x67,
|
|
|
|
BPMEM_FIELDMODE = 0x68,
|
|
|
|
BPMEM_BUSCLOCK1 = 0x69,
|
|
|
|
BPMEM_TX_SETMODE0 = 0x80, // 0x80 + 4
|
|
|
|
BPMEM_TX_SETMODE1 = 0x84, // 0x84 + 4
|
|
|
|
BPMEM_TX_SETIMAGE0 = 0x88, // 0x88 + 4
|
|
|
|
BPMEM_TX_SETIMAGE1 = 0x8C, // 0x8C + 4
|
|
|
|
BPMEM_TX_SETIMAGE2 = 0x90, // 0x90 + 4
|
|
|
|
BPMEM_TX_SETIMAGE3 = 0x94, // 0x94 + 4
|
|
|
|
BPMEM_TX_SETTLUT = 0x98, // 0x98 + 4
|
|
|
|
BPMEM_TX_SETMODE0_4 = 0xA0, // 0xA0 + 4
|
|
|
|
BPMEM_TX_SETMODE1_4 = 0xA4, // 0xA4 + 4
|
|
|
|
BPMEM_TX_SETIMAGE0_4 = 0xA8, // 0xA8 + 4
|
|
|
|
BPMEM_TX_SETIMAGE1_4 = 0xAC, // 0xA4 + 4
|
|
|
|
BPMEM_TX_SETIMAGE2_4 = 0xB0, // 0xB0 + 4
|
|
|
|
BPMEM_TX_SETIMAGE3_4 = 0xB4, // 0xB4 + 4
|
|
|
|
BPMEM_TX_SETTLUT_4 = 0xB8, // 0xB8 + 4
|
|
|
|
BPMEM_TEV_COLOR_ENV = 0xC0, // 0xC0 + (2 * 16)
|
|
|
|
BPMEM_TEV_ALPHA_ENV = 0xC1, // 0xC1 + (2 * 16)
|
|
|
|
BPMEM_TEV_COLOR_RA = 0xE0, // 0xE0 + (2 * 4)
|
|
|
|
BPMEM_TEV_COLOR_BG = 0xE1, // 0xE1 + (2 * 4)
|
|
|
|
BPMEM_FOGRANGE = 0xE8, // 0xE8 + 6
|
|
|
|
BPMEM_FOGPARAM0 = 0xEE,
|
|
|
|
BPMEM_FOGBMAGNITUDE = 0xEF,
|
|
|
|
BPMEM_FOGBEXPONENT = 0xF0,
|
|
|
|
BPMEM_FOGPARAM3 = 0xF1,
|
|
|
|
BPMEM_FOGCOLOR = 0xF2,
|
|
|
|
BPMEM_ALPHACOMPARE = 0xF3,
|
|
|
|
BPMEM_BIAS = 0xF4,
|
|
|
|
BPMEM_ZTEX2 = 0xF5,
|
|
|
|
BPMEM_TEV_KSEL = 0xF6, // 0xF6 + 8
|
|
|
|
BPMEM_BP_MASK = 0xFE,
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// Tev/combiner things
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2015-09-01 08:56:51 -06:00
|
|
|
// TEV scaling type
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVSCALE_1 = 0,
|
|
|
|
TEVSCALE_2 = 1,
|
|
|
|
TEVSCALE_4 = 2,
|
|
|
|
TEVDIVIDE_2 = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVCMP_R8 = 0,
|
|
|
|
TEVCMP_GR16 = 1,
|
|
|
|
TEVCMP_BGR24 = 2,
|
|
|
|
TEVCMP_RGB8 = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
// TEV combiner operator
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVOP_ADD = 0,
|
|
|
|
TEVOP_SUB = 1,
|
|
|
|
TEVCMP_R8_GT = 8,
|
|
|
|
TEVCMP_R8_EQ = 9,
|
|
|
|
TEVCMP_GR16_GT = 10,
|
|
|
|
TEVCMP_GR16_EQ = 11,
|
|
|
|
TEVCMP_BGR24_GT = 12,
|
|
|
|
TEVCMP_BGR24_EQ = 13,
|
|
|
|
TEVCMP_RGB8_GT = 14,
|
|
|
|
TEVCMP_RGB8_EQ = 15,
|
|
|
|
TEVCMP_A8_GT = TEVCMP_RGB8_GT,
|
|
|
|
TEVCMP_A8_EQ = TEVCMP_RGB8_EQ
|
|
|
|
};
|
|
|
|
|
|
|
|
// TEV color combiner input
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVCOLORARG_CPREV = 0,
|
|
|
|
TEVCOLORARG_APREV = 1,
|
|
|
|
TEVCOLORARG_C0 = 2,
|
|
|
|
TEVCOLORARG_A0 = 3,
|
|
|
|
TEVCOLORARG_C1 = 4,
|
|
|
|
TEVCOLORARG_A1 = 5,
|
|
|
|
TEVCOLORARG_C2 = 6,
|
|
|
|
TEVCOLORARG_A2 = 7,
|
|
|
|
TEVCOLORARG_TEXC = 8,
|
|
|
|
TEVCOLORARG_TEXA = 9,
|
|
|
|
TEVCOLORARG_RASC = 10,
|
|
|
|
TEVCOLORARG_RASA = 11,
|
|
|
|
TEVCOLORARG_ONE = 12,
|
|
|
|
TEVCOLORARG_HALF = 13,
|
|
|
|
TEVCOLORARG_KONST = 14,
|
|
|
|
TEVCOLORARG_ZERO = 15
|
|
|
|
};
|
|
|
|
|
|
|
|
// TEV alpha combiner input
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVALPHAARG_APREV = 0,
|
|
|
|
TEVALPHAARG_A0 = 1,
|
|
|
|
TEVALPHAARG_A1 = 2,
|
|
|
|
TEVALPHAARG_A2 = 3,
|
|
|
|
TEVALPHAARG_TEXA = 4,
|
|
|
|
TEVALPHAARG_RASA = 5,
|
|
|
|
TEVALPHAARG_KONST = 6,
|
|
|
|
TEVALPHAARG_ZERO = 7
|
|
|
|
};
|
|
|
|
|
|
|
|
// TEV output registers
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
GX_TEVPREV = 0,
|
|
|
|
GX_TEVREG0 = 1,
|
|
|
|
GX_TEVREG1 = 2,
|
|
|
|
GX_TEVREG2 = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
// Z-texture formats
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEV_ZTEX_TYPE_U8 = 0,
|
|
|
|
TEV_ZTEX_TYPE_U16 = 1,
|
|
|
|
TEV_ZTEX_TYPE_U24 = 2
|
|
|
|
};
|
|
|
|
|
|
|
|
// Z texture operator
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
ZTEXTURE_DISABLE = 0,
|
|
|
|
ZTEXTURE_ADD = 1,
|
|
|
|
ZTEXTURE_REPLACE = 2
|
|
|
|
};
|
|
|
|
|
|
|
|
// TEV bias value
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
TEVBIAS_ZERO = 0,
|
|
|
|
TEVBIAS_ADDHALF = 1,
|
|
|
|
TEVBIAS_SUBHALF = 2,
|
|
|
|
TEVBIAS_COMPARE = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture format
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
ITF_8 = 0,
|
|
|
|
ITF_5 = 1,
|
|
|
|
ITF_4 = 2,
|
|
|
|
ITF_3 = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture bias
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
ITB_NONE = 0,
|
|
|
|
ITB_S = 1,
|
|
|
|
ITB_T = 2,
|
|
|
|
ITB_ST = 3,
|
|
|
|
ITB_U = 4,
|
|
|
|
ITB_SU = 5,
|
|
|
|
ITB_TU = 6,
|
|
|
|
ITB_STU = 7
|
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture bump alpha
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
ITBA_OFF = 0,
|
|
|
|
ITBA_S = 1,
|
|
|
|
ITBA_T = 2,
|
|
|
|
ITBA_U = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
// Indirect texture wrap value
|
|
|
|
enum : u32
|
|
|
|
{
|
|
|
|
ITW_OFF = 0,
|
|
|
|
ITW_256 = 1,
|
|
|
|
ITW_128 = 2,
|
|
|
|
ITW_64 = 3,
|
|
|
|
ITW_32 = 4,
|
|
|
|
ITW_16 = 5,
|
|
|
|
ITW_0 = 6
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
|
|
|
|
union IND_MTXA
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
s32 ma : 11;
|
|
|
|
s32 mb : 11;
|
|
|
|
u32 s0 : 2; // bits 0-1 of scale factor
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union IND_MTXB
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
s32 mc : 11;
|
|
|
|
s32 md : 11;
|
|
|
|
u32 s1 : 2; // bits 2-3 of scale factor
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union IND_MTXC
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
s32 me : 11;
|
|
|
|
s32 mf : 11;
|
|
|
|
u32 s2 : 2; // bits 4-5 of scale factor
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
struct IND_MTX
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
IND_MTXA col0;
|
|
|
|
IND_MTXB col1;
|
|
|
|
IND_MTXC col2;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union IND_IMASK
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 mask : 24;
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
struct TevStageCombiner
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
union ColorCombiner
|
|
|
|
{
|
|
|
|
struct //abc=8bit,d=10bit
|
|
|
|
{
|
|
|
|
u32 d : 4; // TEVSELCC_X
|
|
|
|
u32 c : 4; // TEVSELCC_X
|
|
|
|
u32 b : 4; // TEVSELCC_X
|
|
|
|
u32 a : 4; // TEVSELCC_X
|
|
|
|
|
|
|
|
u32 bias : 2;
|
|
|
|
u32 op : 1;
|
|
|
|
u32 clamp : 1;
|
|
|
|
|
|
|
|
u32 shift : 2;
|
|
|
|
u32 dest : 2; //1,2,3
|
|
|
|
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
union AlphaCombiner
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 rswap : 2;
|
|
|
|
u32 tswap : 2;
|
|
|
|
u32 d : 3; // TEVSELCA_
|
|
|
|
u32 c : 3; // TEVSELCA_
|
|
|
|
u32 b : 3; // TEVSELCA_
|
|
|
|
u32 a : 3; // TEVSELCA_
|
|
|
|
|
|
|
|
u32 bias : 2; //GXTevBias
|
|
|
|
u32 op : 1;
|
|
|
|
u32 clamp : 1;
|
|
|
|
|
|
|
|
u32 shift : 2;
|
|
|
|
u32 dest : 2; //1,2,3
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
|
|
|
ColorCombiner colorC;
|
|
|
|
AlphaCombiner alphaC;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
// several discoveries:
|
|
|
|
// GXSetTevIndBumpST(tevstage, indstage, matrixind)
|
2014-03-10 05:30:55 -06:00
|
|
|
// if ( matrix == 2 ) realmat = 6; // 10
|
|
|
|
// else if ( matrix == 3 ) realmat = 7; // 11
|
|
|
|
// else if ( matrix == 1 ) realmat = 5; // 9
|
2009-06-22 03:31:30 -06:00
|
|
|
// GXSetTevIndirect(tevstage, indstage, 0, 3, realmat, 6, 6, 0, 0, 0)
|
|
|
|
// GXSetTevIndirect(tevstage+1, indstage, 0, 3, realmat+4, 6, 6, 1, 0, 0)
|
|
|
|
// GXSetTevIndirect(tevstage+2, indstage, 0, 0, 0, 0, 0, 1, 0, 0)
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
union TevStageIndirect
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 bt : 2; // Indirect tex stage ID
|
|
|
|
u32 fmt : 2; // Format: ITF_X
|
|
|
|
u32 bias : 3; // ITB_X
|
|
|
|
u32 bs : 2; // ITBA_X, indicates which coordinate will become the 'bump alpha'
|
|
|
|
u32 mid : 4; // Matrix ID to multiply offsets with
|
|
|
|
u32 sw : 3; // ITW_X, wrapping factor for S of regular coord
|
|
|
|
u32 tw : 3; // ITW_X, wrapping factor for T of regular coord
|
|
|
|
u32 lb_utclod : 1; // Use modified or unmodified texture coordinates for LOD computation
|
|
|
|
u32 fb_addprev : 1; // 1 if the texture coordinate results from the previous TEV stage should be added
|
|
|
|
u32 pad0 : 3;
|
|
|
|
u32 rid : 8;
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
struct
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
u32 hex : 21;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 unused : 11;
|
|
|
|
};
|
|
|
|
|
2014-05-04 23:44:10 -06:00
|
|
|
// If bs and mid are zero, the result of the stage is independent of
|
|
|
|
// the texture sample data, so we can skip sampling the texture.
|
|
|
|
bool IsActive() { return bs != ITBA_OFF || mid != 0; }
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union TwoTevStageOrders
|
|
|
|
{
|
2013-05-01 03:39:30 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 texmap0 : 3; // Indirect tex stage texmap
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 texcoord0 : 3;
|
|
|
|
u32 enable0 : 1; // 1 if should read from texture
|
|
|
|
u32 colorchan0 : 3; // RAS1_CC_X
|
|
|
|
|
|
|
|
u32 pad0 : 2;
|
|
|
|
|
|
|
|
u32 texmap1 : 3;
|
|
|
|
u32 texcoord1 : 3;
|
|
|
|
u32 enable1 : 1; // 1 if should read from texture
|
|
|
|
u32 colorchan1 : 3; // RAS1_CC_X
|
|
|
|
|
|
|
|
u32 pad1 : 2;
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
int getTexMap(int i){return i?texmap1:texmap0;}
|
|
|
|
int getTexCoord(int i){return i?texcoord1:texcoord0;}
|
|
|
|
int getEnable(int i){return i?enable1:enable0;}
|
|
|
|
int getColorChan(int i){return i?colorchan1:colorchan0;}
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
|
|
|
|
union TEXSCALE
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 ss0 : 4; // Indirect tex stage 0, 2^(-ss0)
|
|
|
|
u32 ts0 : 4; // Indirect tex stage 0
|
|
|
|
u32 ss1 : 4; // Indirect tex stage 1
|
|
|
|
u32 ts1 : 4; // Indirect tex stage 1
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 pad : 8;
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union RAS1_IREF
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 bi0 : 3; // Indirect tex stage 0 ntexmap
|
|
|
|
u32 bc0 : 3; // Indirect tex stage 0 ntexcoord
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 bi1 : 3;
|
|
|
|
u32 bc1 : 3;
|
|
|
|
u32 bi2 : 3;
|
|
|
|
u32 bc3 : 3;
|
|
|
|
u32 bi4 : 3;
|
|
|
|
u32 bc4 : 3;
|
|
|
|
u32 rid : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
|
Fix the Zelda: The Wind Waker heat effect glitch.
Let's talk a bit about this bug. 12nd oldest bug not fixed in Dolphin, it was a
lot of fun to debug and it kept me busy for a while :)
Shoutout to Nintendo for framework.map, without which this could have taken a
lot longer.
Basic debugging using apitrace shows that the heat effect is rendered in an
interesting way:
* An EFB copy texture is created, using the hardware scaler to divide the
texture resolution by two and that way create the blur effect.
* This texture is then warped using indirect texturing: a deformation map is
used to "move" the texture coordinates used to sample the framebuffer copy.
Pixel shader: http://pastie.org/private/25oe1pqn6s0h5yieks1jfw
Interestingly, when looking at apitrace, the deformation texture was only 4x4
pixels... weird. It also does not have any feature that you would expect from a
deformation map. Seeing how the heat effect glitches, this deformation texture
being wrong looks like a good candidate for the problem. Let's see how it's
loaded!
By NOPing random calls to GXSetTevIndirect, we find a call that when removed
breaks the effect completely. The parameters used for this call come from the
results of methods of JPAExTexShapeArc objects. 3 different objects go through
this code path, by breaking each one we can notice that the one "controlling"
the heat effect is the one at 0x81575b98.
Following the path of this object a bit more, we can see that it has a method
called "getIndTexId". When this is called, the returned texture ID is used to
index a map and get a JPATextureArc object stored at 0x81577bec.
Nice feature of JPATextureArc: they have a getName method. For this object, it
returns "AK_kagerouInd01". We can probably use that to see how this texture
should look like, by loading it "manually" from the Wind Waker DVD.
Unfortunately I don't know how to do that. Fortunately @Abahbob got me the
texture I wanted in less than 10min after I asked him on Twitter.
AK_kagerouInd01 is a 32x32 texture that really looks like a deformation map:
http://i.imgur.com/0TfZEVj.png . Fun fact: "kagerou" means "heat haze" in JP.
So apparently we're not using the right texture object when rendering! The
GXTexObj that maps to the JPATextureArc is at offset 0x81577bf0 and points to
data at 0x80ed0460, but we're loading texture data from 0x0039d860 instead.
I started to suspect the BP write that loads the texture parameters "did not
work" somehow. Logged that and yes: nothing gets loaded to texture stage 1! ...
but it turns out this is normal, the deformation map is loaded to texture stage
5 (hardcoded in the DOL). Wait, why is the TextureCache trying to load from
texture stage 1 then?!
Because someone sucked at hex.
Fixes issue 2338.
2014-01-05 03:16:08 -07:00
|
|
|
u32 getTexCoord(int i) { return (hex>>(6*i+3))&7; }
|
|
|
|
u32 getTexMap(int i) { return (hex>>(6*i))&7; }
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// Texture structs
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
union TexMode0
|
|
|
|
{
|
2014-06-08 16:36:26 -06:00
|
|
|
enum TextureFilter : u32
|
|
|
|
{
|
|
|
|
TEXF_NONE = 0,
|
|
|
|
TEXF_POINT = 1,
|
|
|
|
TEXF_LINEAR = 2
|
|
|
|
};
|
|
|
|
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 wrap_s : 2;
|
|
|
|
u32 wrap_t : 2;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 mag_filter : 1;
|
|
|
|
u32 min_filter : 3;
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 diag_lod : 1;
|
|
|
|
s32 lod_bias : 8;
|
|
|
|
u32 pad0 : 2;
|
|
|
|
u32 max_aniso : 2;
|
|
|
|
u32 lod_clamp : 1;
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
union TexMode1
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 min_lod : 8;
|
|
|
|
u32 max_lod : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
union TexImage0
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 width : 10; // Actually w-1
|
|
|
|
u32 height : 10; // Actually h-1
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 format : 4;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
union TexImage1
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 tmem_even : 15; // TMEM line index for even LODs
|
|
|
|
u32 cache_width : 3;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 cache_height : 3;
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 image_type : 1; // 1 if this texture is managed manually (0 means we'll autofetch the texture data whenever it changes)
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union TexImage2
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 tmem_odd : 15; // tmem line index for odd LODs
|
|
|
|
u32 cache_width : 3;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 cache_height : 3;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union TexImage3
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 image_base: 24; //address in memory >> 5 (was 20 for GC)
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
union TexTLUT
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 tmem_offset : 10;
|
|
|
|
u32 tlut_format : 2;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union ZTex1
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 bias : 24;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union ZTex2
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 type : 2; // TEV_Z_TYPE_X
|
|
|
|
u32 op : 2; // GXZTexOp
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
struct FourTexUnits
|
|
|
|
{
|
2013-04-24 07:21:54 -06:00
|
|
|
TexMode0 texMode0[4];
|
|
|
|
TexMode1 texMode1[4];
|
|
|
|
TexImage0 texImage0[4];
|
|
|
|
TexImage1 texImage1[4];
|
|
|
|
TexImage2 texImage2[4];
|
|
|
|
TexImage3 texImage3[4];
|
|
|
|
TexTLUT texTlut[4];
|
|
|
|
u32 unknown[4];
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// Geometry/other structs
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
union GenMode
|
|
|
|
{
|
2014-04-21 14:34:23 -06:00
|
|
|
enum CullMode : u32
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-04-21 14:34:23 -06:00
|
|
|
CULL_NONE = 0,
|
|
|
|
CULL_BACK = 1, // cull back-facing primitives
|
|
|
|
CULL_FRONT = 2, // cull front-facing primitives
|
|
|
|
CULL_ALL = 3, // cull all primitives
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
2014-04-21 14:34:23 -06:00
|
|
|
|
|
|
|
BitField< 0,4,u32> numtexgens;
|
2014-04-21 14:38:08 -06:00
|
|
|
BitField< 4,3,u32> numcolchans;
|
|
|
|
// 1 bit unused?
|
|
|
|
BitField< 8,1,u32> flat_shading; // unconfirmed
|
2014-04-21 14:34:23 -06:00
|
|
|
BitField< 9,1,u32> multisampling;
|
|
|
|
BitField<10,4,u32> numtevstages;
|
|
|
|
BitField<14,2,CullMode> cullmode;
|
|
|
|
BitField<16,3,u32> numindstages;
|
2014-09-20 12:27:34 -06:00
|
|
|
BitField<19,1,u32> zfreeze;
|
2014-04-21 14:34:23 -06:00
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union LPSize
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 linesize : 8; // in 1/6th pixels
|
|
|
|
u32 pointsize : 8; // in 1/6th pixels
|
|
|
|
u32 lineoff : 3;
|
|
|
|
u32 pointoff : 3;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 lineaspect : 1; // interlacing: adjust for pixels having AR of 1/2
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 padding : 1;
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
union X12Y12
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 y : 12;
|
|
|
|
u32 x : 12;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
union X10Y10
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 x : 10;
|
|
|
|
u32 y : 10;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// Framebuffer/pixel stuff (incl fog)
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
union BlendMode
|
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
enum BlendFactor : u32
|
|
|
|
{
|
|
|
|
ZERO = 0,
|
|
|
|
ONE = 1,
|
|
|
|
SRCCLR = 2, // for dst factor
|
|
|
|
INVSRCCLR = 3, // for dst factor
|
|
|
|
DSTCLR = SRCCLR, // for src factor
|
|
|
|
INVDSTCLR = INVSRCCLR, // for src factor
|
|
|
|
SRCALPHA = 4,
|
|
|
|
INVSRCALPHA = 5,
|
|
|
|
DSTALPHA = 6,
|
|
|
|
INVDSTALPHA = 7
|
|
|
|
};
|
|
|
|
|
|
|
|
enum LogicOp : u32
|
|
|
|
{
|
|
|
|
CLEAR = 0,
|
|
|
|
AND = 1,
|
|
|
|
AND_REVERSE = 2,
|
|
|
|
COPY = 3,
|
|
|
|
AND_INVERTED = 4,
|
|
|
|
NOOP = 5,
|
|
|
|
XOR = 6,
|
|
|
|
OR = 7,
|
|
|
|
NOR = 8,
|
|
|
|
EQUIV = 9,
|
|
|
|
INVERT = 10,
|
|
|
|
OR_REVERSE = 11,
|
|
|
|
COPY_INVERTED = 12,
|
|
|
|
OR_INVERTED = 13,
|
|
|
|
NAND = 14,
|
|
|
|
SET = 15
|
|
|
|
};
|
|
|
|
|
|
|
|
BitField< 0,1,u32> blendenable;
|
|
|
|
BitField< 1,1,u32> logicopenable;
|
|
|
|
BitField< 2,1,u32> dither;
|
|
|
|
BitField< 3,1,u32> colorupdate;
|
|
|
|
BitField< 4,1,u32> alphaupdate;
|
|
|
|
BitField< 5,3,BlendFactor> dstfactor;
|
|
|
|
BitField< 8,3,BlendFactor> srcfactor;
|
|
|
|
BitField<11,1,u32> subtract;
|
|
|
|
BitField<12,4,LogicOp> logicmode;
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
union FogParam0
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
|
|
|
u32 mantissa : 11;
|
|
|
|
u32 exponent : 8;
|
|
|
|
u32 sign : 1;
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2013-04-24 07:21:54 -06:00
|
|
|
float GetA()
|
|
|
|
{
|
2009-06-22 03:31:30 -06:00
|
|
|
union { u32 i; float f; } dummy;
|
2013-03-19 19:51:12 -06:00
|
|
|
dummy.i = ((u32)sign << 31) | ((u32)exponent << 23) | ((u32)mantissa << 12); // scale mantissa from 11 to 23 bits
|
2009-06-22 03:31:30 -06:00
|
|
|
return dummy.f;
|
|
|
|
}
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union FogParam3
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 c_mant : 11;
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 c_exp : 8;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 c_sign : 1;
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 proj : 1; // 0 - perspective, 1 - orthographic
|
|
|
|
u32 fsel : 3; // 0 - off, 2 - linear, 4 - exp, 5 - exp2, 6 - backward exp, 7 - backward exp2
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
// amount to subtract from eyespacez after range adjustment
|
2013-04-24 07:21:54 -06:00
|
|
|
float GetC()
|
2013-10-28 23:23:17 -06:00
|
|
|
{
|
2009-06-22 03:31:30 -06:00
|
|
|
union { u32 i; float f; } dummy;
|
2010-11-23 06:57:01 -07:00
|
|
|
dummy.i = ((u32)c_sign << 31) | ((u32)c_exp << 23) | ((u32)c_mant << 12); // scale mantissa from 11 to 23 bits
|
2009-06-22 03:31:30 -06:00
|
|
|
return dummy.f;
|
|
|
|
}
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2011-01-28 21:31:56 -07:00
|
|
|
union FogRangeKElement
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 HI : 12;
|
|
|
|
u32 LO : 12;
|
|
|
|
u32 regid : 8;
|
|
|
|
};
|
2013-03-25 17:56:34 -06:00
|
|
|
|
2013-01-19 04:57:55 -07:00
|
|
|
// TODO: Which scaling coefficient should we use here? This is just a guess!
|
2013-03-25 17:56:34 -06:00
|
|
|
float GetValue(int i) { return (i ? HI : LO) / 256.f; }
|
2011-01-28 21:31:56 -07:00
|
|
|
u32 HEX;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FogRangeParams
|
|
|
|
{
|
|
|
|
union RangeBase
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 Center : 10; // viewport center + 342
|
2011-01-28 21:31:56 -07:00
|
|
|
u32 Enabled : 1;
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 unused : 13;
|
|
|
|
u32 regid : 8;
|
2011-01-28 21:31:56 -07:00
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
RangeBase Base;
|
|
|
|
FogRangeKElement K[5];
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
// final eq: ze = A/(B_MAG - (Zs>>B_SHF));
|
|
|
|
struct FogParams
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
FogParam0 a;
|
|
|
|
u32 b_magnitude;
|
|
|
|
u32 b_shift; // b's exp + 1?
|
|
|
|
FogParam3 c_proj_fsel;
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
union FogColor
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 b : 8;
|
|
|
|
u32 g : 8;
|
|
|
|
u32 r : 8;
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
FogColor color; //0:b 8:g 16:r - nice!
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union ZMode
|
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
enum CompareMode : u32
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
NEVER = 0,
|
|
|
|
LESS = 1,
|
|
|
|
EQUAL = 2,
|
|
|
|
LEQUAL = 3,
|
|
|
|
GREATER = 4,
|
|
|
|
NEQUAL = 5,
|
|
|
|
GEQUAL = 6,
|
|
|
|
ALWAYS = 7
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
2014-03-24 13:21:34 -06:00
|
|
|
|
|
|
|
BitField<0,1,u32> testenable;
|
|
|
|
BitField<1,3,CompareMode> func;
|
|
|
|
BitField<4,1,u32> updateenable;
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union ConstantAlpha
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 alpha : 8;
|
|
|
|
u32 enable : 1;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2011-07-18 02:27:30 -06:00
|
|
|
union FieldMode
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
u32 texLOD : 1; // adjust vert tex LOD computation to account for interlacing
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
|
|
|
union FieldMask
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
// If bit is not set, do not write field to EFB
|
|
|
|
u32 odd : 1;
|
|
|
|
u32 even : 1;
|
|
|
|
};
|
|
|
|
u32 hex;
|
|
|
|
};
|
|
|
|
|
2014-03-23 14:44:23 -06:00
|
|
|
union PEControl
|
2009-06-22 03:31:30 -06:00
|
|
|
{
|
2014-03-23 14:44:23 -06:00
|
|
|
enum PixelFormat : u32
|
|
|
|
{
|
2014-03-27 21:52:27 -06:00
|
|
|
RGB8_Z24 = 0,
|
|
|
|
RGBA6_Z24 = 1,
|
|
|
|
RGB565_Z16 = 2,
|
|
|
|
Z24 = 3,
|
|
|
|
Y8 = 4,
|
|
|
|
U8 = 5,
|
|
|
|
V8 = 6,
|
|
|
|
YUV420 = 7,
|
|
|
|
INVALID_FMT = 0xffffffff, // Used by Dolphin to represent a missing value.
|
2014-03-23 14:44:23 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
enum DepthFormat : u32
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-03-23 14:44:23 -06:00
|
|
|
ZLINEAR = 0,
|
|
|
|
ZNEAR = 1,
|
|
|
|
ZMID = 2,
|
|
|
|
ZFAR = 3,
|
|
|
|
|
|
|
|
// It seems these Z formats aren't supported/were removed ?
|
|
|
|
ZINV_LINEAR = 4,
|
|
|
|
ZINV_NEAR = 5,
|
|
|
|
ZINV_MID = 6,
|
|
|
|
ZINV_FAR = 7
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
2013-07-22 06:38:09 -06:00
|
|
|
|
2014-03-23 14:44:23 -06:00
|
|
|
BitField< 0,3,PixelFormat> pixel_format;
|
|
|
|
BitField< 3,3,DepthFormat> zformat;
|
|
|
|
BitField< 6,1,u32> early_ztest;
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// Texture coordinate stuff
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
union TCInfo
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
struct
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 scale_minus_1 : 16;
|
|
|
|
u32 range_bias : 1;
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 cylindric_wrap : 1;
|
2011-04-15 16:34:54 -06:00
|
|
|
// These bits only have effect in the s field of TCoordInfo
|
2014-02-09 16:29:13 -07:00
|
|
|
u32 line_offset : 1;
|
|
|
|
u32 point_offset : 1;
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
struct TCoordInfo
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
TCInfo s;
|
|
|
|
TCInfo t;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-03-10 09:15:40 -06:00
|
|
|
union TevReg
|
2009-06-22 03:31:30 -06:00
|
|
|
{
|
2014-03-10 09:15:40 -06:00
|
|
|
u64 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2014-03-10 09:15:40 -06:00
|
|
|
// Access to individual registers
|
|
|
|
BitField< 0, 32,u64> low;
|
|
|
|
BitField<32, 32,u64> high;
|
|
|
|
|
2014-09-17 10:46:23 -06:00
|
|
|
// TODO: Check if Konst uses all 11 bits or just 8
|
|
|
|
|
2014-03-10 09:15:40 -06:00
|
|
|
// Low register
|
|
|
|
BitField< 0,11,s64> red;
|
|
|
|
|
|
|
|
BitField<12,11,s64> alpha;
|
|
|
|
BitField<23, 1,u64> type_ra;
|
|
|
|
|
|
|
|
// High register
|
|
|
|
BitField<32,11,s64> blue;
|
|
|
|
|
|
|
|
BitField<44,11,s64> green;
|
|
|
|
BitField<55, 1,u64> type_bg;
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union TevKSel
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
struct {
|
|
|
|
u32 swap1 : 2;
|
|
|
|
u32 swap2 : 2;
|
|
|
|
u32 kcsel0 : 5;
|
|
|
|
u32 kasel0 : 5;
|
|
|
|
u32 kcsel1 : 5;
|
|
|
|
u32 kasel1 : 5;
|
|
|
|
};
|
|
|
|
u32 hex;
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
int getKC(int i) {return i?kcsel1:kcsel0;}
|
|
|
|
int getKA(int i) {return i?kasel1:kasel0;}
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2013-01-08 09:18:45 -07:00
|
|
|
union AlphaTest
|
2009-06-22 03:31:30 -06:00
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
enum CompareMode : u32
|
2013-03-19 19:51:12 -06:00
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
NEVER = 0,
|
|
|
|
LESS = 1,
|
|
|
|
EQUAL = 2,
|
|
|
|
LEQUAL = 3,
|
|
|
|
GREATER = 4,
|
|
|
|
NEQUAL = 5,
|
|
|
|
GEQUAL = 6,
|
|
|
|
ALWAYS = 7
|
2013-03-19 19:51:12 -06:00
|
|
|
};
|
2014-03-24 13:21:34 -06:00
|
|
|
|
2014-03-26 03:02:57 -06:00
|
|
|
enum Op : u32
|
2014-03-24 13:21:34 -06:00
|
|
|
{
|
|
|
|
AND = 0,
|
|
|
|
OR = 1,
|
|
|
|
XOR = 2,
|
|
|
|
XNOR = 3
|
|
|
|
};
|
|
|
|
|
|
|
|
BitField< 0,8, u32> ref0;
|
|
|
|
BitField< 8,8, u32> ref1;
|
|
|
|
BitField<16,3, CompareMode> comp0;
|
|
|
|
BitField<19,3, CompareMode> comp1;
|
|
|
|
BitField<22,2, Op> logic;
|
|
|
|
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 hex;
|
2013-01-08 09:18:45 -07:00
|
|
|
|
|
|
|
enum TEST_RESULT
|
|
|
|
{
|
|
|
|
UNDETERMINED = 0,
|
|
|
|
FAIL = 1,
|
|
|
|
PASS = 2,
|
|
|
|
};
|
|
|
|
|
2014-10-17 13:50:41 -06:00
|
|
|
__forceinline TEST_RESULT TestResult() const
|
2013-08-12 04:52:28 -06:00
|
|
|
{
|
2014-03-10 05:30:55 -06:00
|
|
|
switch (logic)
|
2013-08-12 04:52:28 -06:00
|
|
|
{
|
2014-03-24 13:21:34 -06:00
|
|
|
case AND:
|
|
|
|
if (comp0 == ALWAYS && comp1 == ALWAYS)
|
2013-08-12 04:52:28 -06:00
|
|
|
return PASS;
|
2014-03-24 13:21:34 -06:00
|
|
|
if (comp0 == NEVER || comp1 == NEVER)
|
2013-08-12 04:52:28 -06:00
|
|
|
return FAIL;
|
|
|
|
break;
|
|
|
|
|
2014-03-24 13:21:34 -06:00
|
|
|
case OR:
|
|
|
|
if (comp0 == ALWAYS || comp1 == ALWAYS)
|
2013-08-12 04:52:28 -06:00
|
|
|
return PASS;
|
2014-03-24 13:21:34 -06:00
|
|
|
if (comp0 == NEVER && comp1 == NEVER)
|
2013-08-12 04:52:28 -06:00
|
|
|
return FAIL;
|
|
|
|
break;
|
|
|
|
|
2014-03-24 13:21:34 -06:00
|
|
|
case XOR:
|
|
|
|
if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS))
|
2013-08-12 04:52:28 -06:00
|
|
|
return PASS;
|
2014-03-24 13:21:34 -06:00
|
|
|
if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER))
|
2013-08-12 04:52:28 -06:00
|
|
|
return FAIL;
|
|
|
|
break;
|
|
|
|
|
2014-03-24 13:21:34 -06:00
|
|
|
case XNOR:
|
|
|
|
if ((comp0 == ALWAYS && comp1 == NEVER) || (comp0 == NEVER && comp1 == ALWAYS))
|
2013-08-12 04:52:28 -06:00
|
|
|
return FAIL;
|
2014-03-24 13:21:34 -06:00
|
|
|
if ((comp0 == ALWAYS && comp1 == ALWAYS) || (comp0 == NEVER && comp1 == NEVER))
|
2013-08-12 04:52:28 -06:00
|
|
|
return PASS;
|
|
|
|
break;
|
2014-12-02 17:20:52 -07:00
|
|
|
|
|
|
|
default:
|
|
|
|
return UNDETERMINED;
|
2013-08-12 04:52:28 -06:00
|
|
|
}
|
|
|
|
return UNDETERMINED;
|
|
|
|
}
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
union UPE_Copy
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 Hex;
|
2014-03-10 09:15:40 -06:00
|
|
|
|
|
|
|
BitField< 0,1,u32> clamp0; // if set clamp top
|
|
|
|
BitField< 1,1,u32> clamp1; // if set clamp bottom
|
|
|
|
BitField< 2,1,u32> yuv; // if set, color conversion from RGB to YUV
|
|
|
|
BitField< 3,4,u32> target_pixel_format; // realformat is (fmt/2)+((fmt&1)*8).... for some reason the msb is the lsb (pattern: cycling right shift)
|
|
|
|
BitField< 7,2,u32> gamma; // gamma correction.. 0 = 1.0 ; 1 = 1.7 ; 2 = 2.2 ; 3 is reserved
|
|
|
|
BitField< 9,1,u32> half_scale; // "mipmap" filter... 0 = no filter (scale 1:1) ; 1 = box filter (scale 2:1)
|
|
|
|
BitField<10,1,u32> scale_invert; // if set vertical scaling is on
|
|
|
|
BitField<11,1,u32> clear;
|
|
|
|
BitField<12,2,u32> frame_to_field; // 0 progressive ; 1 is reserved ; 2 = interlaced (even lines) ; 3 = interlaced 1 (odd lines)
|
|
|
|
BitField<14,1,u32> copy_to_xfb;
|
|
|
|
BitField<15,1,u32> intensity_fmt; // if set, is an intensity format (I4,I8,IA4,IA8)
|
|
|
|
BitField<16,1,u32> auto_conv; // if 0 automatic color conversion by texture format and pixel type
|
|
|
|
|
2014-08-30 14:51:27 -06:00
|
|
|
u32 tp_realFormat()
|
|
|
|
{
|
2010-12-18 11:23:22 -07:00
|
|
|
return target_pixel_format / 2 + (target_pixel_format & 1) * 8;
|
|
|
|
}
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
2012-01-29 13:17:22 -07:00
|
|
|
union BPU_PreloadTileInfo
|
|
|
|
{
|
|
|
|
u32 hex;
|
2013-04-24 07:21:54 -06:00
|
|
|
struct
|
|
|
|
{
|
2012-01-29 13:17:22 -07:00
|
|
|
u32 count : 15;
|
|
|
|
u32 type : 2;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct BPS_TmemConfig
|
|
|
|
{
|
|
|
|
u32 preload_addr;
|
|
|
|
u32 preload_tmem_even;
|
|
|
|
u32 preload_tmem_odd;
|
|
|
|
BPU_PreloadTileInfo preload_tile_info;
|
|
|
|
u32 tlut_src;
|
|
|
|
u32 tlut_dest;
|
|
|
|
u32 texinvalidate;
|
|
|
|
};
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
// All of BP memory
|
2009-09-02 15:00:45 -06:00
|
|
|
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2009-07-26 03:52:35 -06:00
|
|
|
struct BPCmd
|
2009-06-22 03:31:30 -06:00
|
|
|
{
|
|
|
|
int address;
|
|
|
|
int changes;
|
|
|
|
int newvalue;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct BPMemory
|
|
|
|
{
|
2013-03-19 19:51:12 -06:00
|
|
|
GenMode genMode;
|
|
|
|
u32 display_copy_filter[4]; // 01-04
|
|
|
|
u32 unknown; // 05
|
|
|
|
// indirect matrices (set by GXSetIndTexMtx, selected by TevStageIndirect::mid)
|
|
|
|
// abc form a 2x3 offset matrix, there's 3 such matrices
|
|
|
|
// the 3 offset matrices can either be indirect type, S-type, or T-type
|
2013-10-28 23:23:17 -06:00
|
|
|
// 6bit scale factor s is distributed across IND_MTXA/B/C.
|
2013-03-19 19:51:12 -06:00
|
|
|
// before using matrices scale by 2^-(s-17)
|
|
|
|
IND_MTX indmtx[3];//06-0e GXSetIndTexMtx, 2x3 matrices
|
|
|
|
IND_IMASK imask;//0f
|
|
|
|
TevStageIndirect tevind[16];//10 GXSetTevIndirect
|
|
|
|
X12Y12 scissorTL; //20
|
|
|
|
X12Y12 scissorBR; //21
|
|
|
|
LPSize lineptwidth; //22 line and point width
|
|
|
|
u32 sucounter; //23
|
|
|
|
u32 rascounter; //24
|
|
|
|
TEXSCALE texscale[2]; //25-26 GXSetIndTexCoordScale
|
|
|
|
RAS1_IREF tevindref; //27 GXSetIndTexOrder
|
|
|
|
TwoTevStageOrders tevorders[8]; //28-2F
|
|
|
|
TCoordInfo texcoords[8]; //0x30 s,t,s,t,s,t,s,t...
|
|
|
|
ZMode zmode; //40
|
|
|
|
BlendMode blendmode; //41
|
|
|
|
ConstantAlpha dstalpha; //42
|
2014-03-23 14:44:23 -06:00
|
|
|
PEControl zcontrol; //43 GXSetZCompLoc, GXPixModeSync
|
2013-03-19 19:51:12 -06:00
|
|
|
FieldMask fieldmask; //44
|
|
|
|
u32 drawdone; //45, bit1=1 if end of list
|
|
|
|
u32 unknown5; //46 clock?
|
|
|
|
u32 petoken; //47
|
|
|
|
u32 petokenint; // 48
|
|
|
|
X10Y10 copyTexSrcXY; // 49
|
|
|
|
X10Y10 copyTexSrcWH; // 4a
|
|
|
|
u32 copyTexDest; //4b// 4b == CopyAddress (GXDispCopy and GXTexCopy use it)
|
|
|
|
u32 unknown6; //4c
|
|
|
|
u32 copyMipMapStrideChannels; // 4d usually set to 4 when dest is single channel, 8 when dest is 2 channel, 16 when dest is RGBA
|
2014-02-09 16:29:13 -07:00
|
|
|
// also, doubles whenever mipmap box filter option is set (excent on RGBA). Probably to do with number of bytes to look at when smoothing
|
2013-03-19 19:51:12 -06:00
|
|
|
u32 dispcopyyscale; //4e
|
|
|
|
u32 clearcolorAR; //4f
|
|
|
|
u32 clearcolorGB; //50
|
|
|
|
u32 clearZValue; //51
|
|
|
|
UPE_Copy triggerEFBCopy; //52
|
|
|
|
u32 copyfilter[2]; //53,54
|
|
|
|
u32 boundbox0;//55
|
|
|
|
u32 boundbox1;//56
|
|
|
|
u32 unknown7[2];//57,58
|
|
|
|
X10Y10 scissorOffset; //59
|
|
|
|
u32 unknown8[6]; //5a,5b,5c,5d, 5e,5f
|
|
|
|
BPS_TmemConfig tmem_config; // 60-66
|
|
|
|
u32 metric; //67
|
|
|
|
FieldMode fieldmode;//68
|
|
|
|
u32 unknown10[7];//69-6F
|
|
|
|
u32 unknown11[16];//70-7F
|
|
|
|
FourTexUnits tex[2]; //80-bf
|
|
|
|
TevStageCombiner combiners[16]; //0xC0-0xDF
|
|
|
|
TevReg tevregs[4]; //0xE0
|
|
|
|
FogRangeParams fogRange; // 0xE8
|
|
|
|
FogParams fog; //0xEE,0xEF,0xF0,0xF1,0xF2
|
|
|
|
AlphaTest alpha_test; //0xF3
|
|
|
|
ZTex1 ztex1; //0xf4,0xf5
|
|
|
|
ZTex2 ztex2;
|
|
|
|
TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd
|
|
|
|
u32 bpMask; //0xFE
|
|
|
|
u32 unknown18; //ff
|
2013-07-22 06:38:09 -06:00
|
|
|
|
|
|
|
bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; }
|
|
|
|
bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; }
|
2009-06-22 03:31:30 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
extern BPMemory bpmem;
|
|
|
|
|
|
|
|
void LoadBPReg(u32 value0);
|
Add the 'desynced GPU thread' mode.
It's a relatively big commit (less big with -w), but it's hard to test
any of this separately...
The basic problem is that in netplay or movies, the state of the CPU
must be deterministic, including when the game receives notification
that the GPU has processed FIFO data. Dual core mode notifies the game
whenever the GPU thread actually gets around to doing the work, so it
isn't deterministic. Single core mode is because it notifies the game
'instantly' (after processing the data synchronously), but it's too slow
for many systems and games.
My old dc-netplay branch worked as follows: everything worked as normal
except the state of the CP registers was a lie, and the CPU thread only
delivered results when idle detection triggered (waiting for the GPU if
they weren't ready at that point). Usually, a game is idle iff all the
work for the frame has been done, except for a small amount of work
depending on the GPU result, so neither the CPU or the GPU waiting on
the other affected performance much. However, it's possible that the
game could be waiting for some earlier interrupt, and any of several
games which, for whatever reason, never went into a detectable idle
(even when I tried to improve the detection) would never receive results
at all. (The current method should have better compatibility, but it
also has slightly higher overhead and breaks some other things, so I
want to reimplement this, hopefully with less impact on the code, in the
future.)
With this commit, the basic idea is that the CPU thread acts as if the
work has been done instantly, like single core mode, but actually hands
it off asynchronously to the GPU thread (after backing up some data that
the game might change in memory before it's actually done). Since the
work isn't done, any feedback from the GPU to the CPU, such as real
XFB/EFB copies (virtual are OK), EFB pokes, performance queries, etc. is
broken; but most games work with these options disabled, and there is no
need to try to detect what the CPU thread is doing.
Technically: when the flag g_use_deterministic_gpu_thread (currently
stuck on) is on, the CPU thread calls RunGpu like in single core mode.
This function synchronously copies the data from the FIFO to the
internal video buffer and updates the CP registers, interrupts, etc.
However, instead of the regular ReadDataFromFifo followed by running the
opcode decoder, it runs ReadDataFromFifoOnCPU ->
OpcodeDecoder_Preprocess, which relatively quickly scans through the
FIFO data, detects SetFinish calls etc., which are immediately fired,
and saves certain associated data from memory (e.g. display lists) in
AuxBuffers (a parallel stream to the main FIFO, which is a bit slow at
the moment), before handing the data off to the GPU thread to actually
render. That makes up the bulk of this commit.
In various circumstances, including the aforementioned EFB pokes and
performance queries as well as swap requests (i.e. the end of a frame -
we don't want the CPU potentially pumping out frames too quickly and the
GPU falling behind*), SyncGPU is called to wait for actual completion.
The overhead mainly comes from OpcodeDecoder_Preprocess (which is,
again, synchronous), as well as the actual copying.
Currently, display lists and such are escrowed from main memory even
though they usually won't change over the course of a frame, and
textures are not even though they might, resulting in a small chance of
graphical glitches. When the texture locking (i.e. fault on write) code
lands, I can make this all correct and maybe a little faster.
* This suggests an alternate determinism method of just delaying results
until a short time before the end of each frame. For all I know this
might mostly work - I haven't tried it - but if any significant work
hinges on the competion of render to texture etc., the frame will be
missed.
2014-08-27 20:56:19 -06:00
|
|
|
void LoadBPRegPreprocess(u32 value0);
|
2009-06-22 03:31:30 -06:00
|
|
|
|
2014-05-24 19:55:13 -06:00
|
|
|
void GetBPRegInfo(const u8* data, std::string* name, std::string* desc);
|