Import lots of stuff from Dolphin's VideoCommon.

This commit is contained in:
neobrain
2013-05-13 12:25:04 +02:00
parent 1cb0df847e
commit 86171ea7fc
9 changed files with 2061 additions and 15 deletions

1011
source/BPMemory.h Normal file

File diff suppressed because it is too large Load Diff

257
source/CPMemory.h Normal file
View File

@@ -0,0 +1,257 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _CPMEMORY_H
#define _CPMEMORY_H
//#include "Common.h"
// Vertex array numbers
enum
{
ARRAY_POSITION = 0,
ARRAY_NORMAL = 1,
ARRAY_COLOR = 2,
ARRAY_COLOR2 = 3,
ARRAY_TEXCOORD0 = 4,
};
// Vertex components
enum
{
NOT_PRESENT = 0,
DIRECT = 1,
INDEX8 = 2,
INDEX16 = 3,
};
enum
{
FORMAT_UBYTE = 0, // 2 Cmp
FORMAT_BYTE = 1, // 3 Cmp
FORMAT_USHORT = 2,
FORMAT_SHORT = 3,
FORMAT_FLOAT = 4,
};
enum
{
FORMAT_16B_565 = 0, // NA
FORMAT_24B_888 = 1,
FORMAT_32B_888x = 2,
FORMAT_16B_4444 = 3,
FORMAT_24B_6666 = 4,
FORMAT_32B_8888 = 5,
};
enum
{
VAT_0_FRACBITS = 0x3e0001f0,
VAT_1_FRACBITS = 0x07c3e1f0,
VAT_2_FRACBITS = 0xf87c3e1f,
};
#pragma pack(4)
union TVtxDesc
{
u64 Hex;
struct
{
// 0: not present
// 1: present
u32 PosMatIdx : 1;
u32 Tex0MatIdx : 1;
u32 Tex1MatIdx : 1;
u32 Tex2MatIdx : 1;
u32 Tex3MatIdx : 1;
u32 Tex4MatIdx : 1;
u32 Tex5MatIdx : 1;
u32 Tex6MatIdx : 1;
u32 Tex7MatIdx : 1;
// 00: not present
// 01: direct
// 10: 8 bit index
// 11: 16 bit index
u32 Position : 2;
u32 Normal : 2;
u32 Color0 : 2;
u32 Color1 : 2;
u32 Tex0Coord : 2;
u32 Tex1Coord : 2;
u32 Tex2Coord : 2;
u32 Tex3Coord : 2;
u32 Tex4Coord : 2;
u32 Tex5Coord : 2;
u32 Tex6Coord : 2;
u32 Tex7Coord : 2;
u32 :31;
};
struct
{
u32 Hex0, Hex1;
};
};
union UVAT_group0
{
u32 Hex;
struct
{
// 0:8
u32 PosElements : 1;
u32 PosFormat : 3;
u32 PosFrac : 5;
// 9:12
u32 NormalElements : 1;
u32 NormalFormat : 3;
// 13:16
u32 Color0Elements : 1;
u32 Color0Comp : 3;
// 17:20
u32 Color1Elements : 1;
u32 Color1Comp : 3;
// 21:29
u32 Tex0CoordElements : 1;
u32 Tex0CoordFormat : 3;
u32 Tex0Frac : 5;
// 30:31
u32 ByteDequant : 1;
u32 NormalIndex3 : 1;
};
};
union UVAT_group1
{
u32 Hex;
struct
{
// 0:8
u32 Tex1CoordElements : 1;
u32 Tex1CoordFormat : 3;
u32 Tex1Frac : 5;
// 9:17
u32 Tex2CoordElements : 1;
u32 Tex2CoordFormat : 3;
u32 Tex2Frac : 5;
// 18:26
u32 Tex3CoordElements : 1;
u32 Tex3CoordFormat : 3;
u32 Tex3Frac : 5;
// 27:30
u32 Tex4CoordElements : 1;
u32 Tex4CoordFormat : 3;
//
u32 : 1;
};
};
union UVAT_group2
{
u32 Hex;
struct
{
// 0:4
u32 Tex4Frac : 5;
// 5:13
u32 Tex5CoordElements : 1;
u32 Tex5CoordFormat : 3;
u32 Tex5Frac : 5;
// 14:22
u32 Tex6CoordElements : 1;
u32 Tex6CoordFormat : 3;
u32 Tex6Frac : 5;
// 23:31
u32 Tex7CoordElements : 1;
u32 Tex7CoordFormat : 3;
u32 Tex7Frac : 5;
};
};
struct ColorAttr
{
u8 Elements;
u8 Comp;
};
struct TexAttr
{
u8 Elements;
u8 Format;
u8 Frac;
};
struct TVtxAttr
{
u8 PosElements;
u8 PosFormat;
u8 PosFrac;
u8 NormalElements;
u8 NormalFormat;
ColorAttr color[2];
TexAttr texCoord[8];
u8 ByteDequant;
u8 NormalIndex3;
};
// Matrix indices
union TMatrixIndexA
{
struct
{
u32 PosNormalMtxIdx : 6;
u32 Tex0MtxIdx : 6;
u32 Tex1MtxIdx : 6;
u32 Tex2MtxIdx : 6;
u32 Tex3MtxIdx : 6;
};
struct
{
u32 Hex : 30;
u32 unused : 2;
};
};
union TMatrixIndexB
{
struct
{
u32 Tex4MtxIdx : 6;
u32 Tex5MtxIdx : 6;
u32 Tex6MtxIdx : 6;
u32 Tex7MtxIdx : 6;
};
struct
{
u32 Hex : 24;
u32 unused : 8;
};
};
#pragma pack()
extern u32 arraybases[16];
extern u8 *cached_arraybases[16];
extern u32 arraystrides[16];
extern TMatrixIndexA MatrixIndexA;
extern TMatrixIndexB MatrixIndexB;
struct VAT
{
UVAT_group0 g0;
UVAT_group1 g1;
UVAT_group2 g2;
};
extern TVtxDesc g_VtxDesc;
extern VAT g_VtxAttr[8];
// Might move this into its own file later.
//void LoadCPReg(u32 SubCmd, u32 Value);
// Fills memory with data from CP regs
//void FillCPMemoryArray(u32 *memory);
#endif // _CPMEMORY_H

224
source/FifoAnalyzer.h Normal file
View File

@@ -0,0 +1,224 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
//#include "FifoAnalyzer.h"
//#include "Core.h"
#include "VertexLoader.h"
#include "VertexLoader_Position.h"
#include "VertexLoader_Normal.h"
#include "VertexLoader_TextCoord.h"
struct CPMemory
{
TVtxDesc vtxDesc;
VAT vtxAttr[8];
u32 arrayBases[16];
u32 arrayStrides[16];
};
/*void Init()
{
VertexLoader_Normal::Init();
VertexLoader_Position::Init();
VertexLoader_TextCoord::Init();
}*/
u8 ReadFifo8(u8 *&data)
{
u8 value = data[0];
data += 1;
return value;
}
u16 ReadFifo16(u8 *&data)
{
u16 value = be16toh(*(u16*)data);
data += 2;
return value;
}
u32 ReadFifo32(u8 *&data)
{
u32 value = be32toh(*(u32*)data);
data += 4;
return value;
}
/*void InitBPMemory(BPMemory *bpMem)
{
memset(bpMem, 0, sizeof(BPMemory));
bpMem->bpMask = 0x00FFFFFF;
}
BPCmd DecodeBPCmd(u32 value, const BPMemory &bpMem)
{
//handle the mask register
int opcode = value >> 24;
int oldval = ((u32*)&bpMem)[opcode];
int newval = (oldval & ~bpMem.bpMask) | (value & bpMem.bpMask);
int changes = (oldval ^ newval) & 0xFFFFFF;
BPCmd bp = {opcode, changes, newval};
return bp;
}
void LoadBPReg(const BPCmd &bp, BPMemory &bpMem)
{
((u32*)&bpMem)[bp.address] = bp.newvalue;
//reset the mask register
if (bp.address != 0xFE)
bpMem.bpMask = 0xFFFFFF;
}
void GetTlutLoadData(u32 &tlutAddr, u32 &memAddr, u32 &tlutXferCount, BPMemory &bpMem)
{
tlutAddr = (bpMem.tmem_config.tlut_dest & 0x3FF) << 9;
tlutXferCount = (bpMem.tmem_config.tlut_dest & 0x1FFC00) >> 5;
// TODO - figure out a cleaner way.
if (Core::g_CoreStartupParameter.bWii)
memAddr = bpMem.tmem_config.tlut_src << 5;
else
memAddr = (bpMem.tmem_config.tlut_src & 0xFFFFF) << 5;
}
*/
void LoadCPReg(u32 subCmd, u32 value, CPMemory &cpMem)
{
switch (subCmd & 0xF0)
{
case 0x50:
cpMem.vtxDesc.Hex &= ~0x1FFFF; // keep the Upper bits
cpMem.vtxDesc.Hex |= value;
break;
case 0x60:
cpMem.vtxDesc.Hex &= 0x1FFFF; // keep the lower 17Bits
cpMem.vtxDesc.Hex |= (u64)value << 17;
break;
case 0x70:
// _assert_((subCmd & 0x0F) < 8);
cpMem.vtxAttr[subCmd & 7].g0.Hex = value;
break;
case 0x80:
// _assert_((subCmd & 0x0F) < 8);
cpMem.vtxAttr[subCmd & 7].g1.Hex = value;
break;
case 0x90:
// _assert_((subCmd & 0x0F) < 8);
cpMem.vtxAttr[subCmd & 7].g2.Hex = value;
break;
case 0xA0:
cpMem.arrayBases[subCmd & 0xF] = value;
break;
case 0xB0:
cpMem.arrayStrides[subCmd & 0xF] = value & 0xFF;
break;
}
}
void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMem)
{
const TVtxDesc &vtxDesc = cpMem.vtxDesc;
const VAT &vtxAttr = cpMem.vtxAttr[vatIndex];
// Colors
const u32 colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1};
const u32 colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp};
const u32 tcElements[8] =
{
vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements,
vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements,
vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements
};
const u32 tcFormat[8] =
{
vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat,
vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat,
vtxAttr.g2.Tex6CoordFormat, vtxAttr.g2.Tex7CoordFormat
};
// Add position and texture matrix indices
u64 vtxDescHex = cpMem.vtxDesc.Hex;
for (int i = 0; i < 9; ++i)
{
sizes[i] = vtxDescHex & 1;
vtxDescHex >>= 1;
}
// Position
sizes[9] = VertexLoader_Position::GetSize(vtxDesc.Position, vtxAttr.g0.PosFormat, vtxAttr.g0.PosElements);
// Normals
if (vtxDesc.Normal != NOT_PRESENT)
{
sizes[10] = VertexLoader_Normal::GetSize(vtxDesc.Normal, vtxAttr.g0.NormalFormat, vtxAttr.g0.NormalElements, vtxAttr.g0.NormalIndex3);
}
else
{
sizes[10] = 0;
}
// Colors
for (int i = 0; i < 2; i++)
{
int size = 0;
switch (colDesc[i])
{
case NOT_PRESENT:
break;
case DIRECT:
switch (colComp[i])
{
case FORMAT_16B_565: size = 2; break;
case FORMAT_24B_888: size = 3; break;
case FORMAT_32B_888x: size = 4; break;
case FORMAT_16B_4444: size = 2; break;
case FORMAT_24B_6666: size = 3; break;
case FORMAT_32B_8888: size = 4; break;
default: /*_assert_(0);*/ break;
}
break;
case INDEX8:
size = 1;
break;
case INDEX16:
size = 2;
break;
}
sizes[11 + i] = size;
}
// Texture coordinates
vtxDescHex = vtxDesc.Hex >> 17;
for (int i = 0; i < 8; i++)
{
sizes[13 + i] = VertexLoader_TextCoord::GetSize(vtxDescHex & 3, tcFormat[i], tcElements[i]);
vtxDescHex >>= 2;
}
}
u32 CalculateVertexSize(int vatIndex, const CPMemory &cpMem)
{
u32 vertexSize = 0;
int sizes[21];
CalculateVertexElementSizes(sizes, vatIndex, cpMem);
for (int i = 0; i < 21; ++i)
vertexSize += sizes[i];
return vertexSize;
}

42
source/OpcodeDecoding.h Normal file
View File

@@ -0,0 +1,42 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _OPCODE_DECODING_H
#define _OPCODE_DECODING_H
#define GX_NOP 0x00
#define GX_LOAD_BP_REG 0x61
#define GX_LOAD_CP_REG 0x08
#define GX_LOAD_XF_REG 0x10
#define GX_LOAD_INDX_A 0x20
#define GX_LOAD_INDX_B 0x28
#define GX_LOAD_INDX_C 0x30
#define GX_LOAD_INDX_D 0x38
#define GX_CMD_CALL_DL 0x40
#define GX_CMD_UNKNOWN_METRICS 0x44
#define GX_CMD_INVL_VC 0x48
#define GX_PRIMITIVE_MASK 0x78
#define GX_PRIMITIVE_SHIFT 3
#define GX_VAT_MASK 0x07
//these are defined 1/8th of their real values and without their top bit
#define GX_DRAW_QUADS 0x0 // 0x80
#define GX_DRAW_TRIANGLES 0x2 // 0x90
#define GX_DRAW_TRIANGLE_STRIP 0x3 // 0x98
#define GX_DRAW_TRIANGLE_FAN 0x4 // 0xA0
#define GX_DRAW_LINES 0x5 // 0xA8
#define GX_DRAW_LINE_STRIP 0x6 // 0xB0
#define GX_DRAW_POINTS 0x7 // 0xB8
#define GX_DRAW_NONE 0x1; // This is a fake value to used in the backends
extern bool g_bRecordFifoData;
void OpcodeDecoder_Init();
void OpcodeDecoder_Shutdown();
u32 OpcodeDecoder_Run(bool skipped_frame);
void ExecuteDisplayList(u32 address, u32 size);
#endif // _OPCODE_DECODING_H

146
source/VertexLoader.h Normal file
View File

@@ -0,0 +1,146 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _VERTEXLOADER_H
#define _VERTEXLOADER_H
// Top vertex loaders
// Metroid Prime: P I16-flt N I16-s16 T0 I16-u16 T1 i16-flt
#include <algorithm>
#include <string>
//#include "Common.h"
#include "CPMemory.h"
//#include "DataReader.h"
//#include "NativeVertexFormat.h"
//#include "x64Emitter.h"
class VertexLoaderUID
{
u32 vid[5];
size_t hash;
public:
VertexLoaderUID()
{
}
void InitFromCurrentState(int vtx_attr_group)
{
vid[0] = g_VtxDesc.Hex & 0xFFFFFFFF;
vid[1] = g_VtxDesc.Hex >> 32;
vid[2] = g_VtxAttr[vtx_attr_group].g0.Hex & ~VAT_0_FRACBITS;
vid[3] = g_VtxAttr[vtx_attr_group].g1.Hex & ~VAT_1_FRACBITS;
vid[4] = g_VtxAttr[vtx_attr_group].g2.Hex & ~VAT_2_FRACBITS;
hash = CalculateHash();
}
bool operator < (const VertexLoaderUID &other) const
{
// This is complex because of speed.
if (vid[0] < other.vid[0])
return true;
else if (vid[0] > other.vid[0])
return false;
for (int i = 1; i < 5; ++i)
{
if (vid[i] < other.vid[i])
return true;
else if (vid[i] > other.vid[i])
return false;
}
return false;
}
bool operator == (const VertexLoaderUID& rh) const
{
return hash == rh.hash && std::equal(vid, vid + sizeof(vid) / sizeof(vid[0]), rh.vid);
}
size_t GetHash() const
{
return hash;
}
private:
size_t CalculateHash()
{
size_t h = -1;
for (unsigned int i = 0; i < sizeof(vid) / sizeof(vid[0]); ++i)
{
h = h * 137 + vid[i];
}
return h;
}
};
// ARMTODO: This should be done in a better way
#define _M_GENERIC
#ifndef _M_GENERIC
class VertexLoader : public Gen::XCodeBlock, NonCopyable
#else
class VertexLoader
#endif
{
public:
VertexLoader(const TVtxDesc &vtx_desc, const VAT &vtx_attr);
~VertexLoader();
int GetVertexSize() const {return m_VertexSize;}
int SetupRunVertices(int vtx_attr_group, int primitive, int const count);
void RunVertices(int vtx_attr_group, int primitive, int count);
void RunCompiledVertices(int vtx_attr_group, int primitive, int count, u8* Data);
// For debugging / profiling
void AppendToString(std::string *dest) const;
int GetNumLoadedVerts() const { return m_numLoadedVertices; }
private:
enum
{
NRM_ZERO = 0,
NRM_ONE = 1,
NRM_THREE = 3,
};
int m_VertexSize; // number of bytes of a raw GC vertex. Computed by CompileVertexTranslator.
// GC vertex format
TVtxAttr m_VtxAttr; // VAT decoded into easy format
TVtxDesc m_VtxDesc; // Not really used currently - or well it is, but could be easily avoided.
// PC vertex format
// NativeVertexFormat *m_NativeFmt;
// int native_stride;
// Pipeline. To be JIT compiled in the future.
// TPipelineFunction m_PipelineStages[64]; // TODO - figure out real max. it's lower.
// int m_numPipelineStages;
const u8 *m_compiledCode;
int m_numLoadedVertices;
void SetVAT(u32 _group0, u32 _group1, u32 _group2);
void CompileVertexTranslator();
void ConvertVertices(int count);
// void WriteCall(TPipelineFunction);
#ifndef _M_GENERIC
void WriteGetVariable(int bits, Gen::OpArg dest, void *address);
void WriteSetVariable(int bits, void *address, Gen::OpArg dest);
#endif
};
#endif

View File

@@ -0,0 +1,112 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _VERTEXLOADER_NORMAL_H
#define _VERTEXLOADER_NORMAL_H
//#include "Common.h"
//#include "CommonTypes.h"
class VertexLoader_Normal
{
public:
// Init
static void Init(void);
// GetFunction
// static TPipelineFunction GetFunction(unsigned int _type,
// unsigned int _format, unsigned int _elements, unsigned int _index3);
private:
enum ENormalType
{
NRM_NOT_PRESENT = 0,
NRM_DIRECT = 1,
NRM_INDEX8 = 2,
NRM_INDEX16 = 3,
NUM_NRM_TYPE
};
enum ENormalFormat
{
FORMAT_UBYTE = 0,
FORMAT_BYTE = 1,
FORMAT_USHORT = 2,
FORMAT_SHORT = 3,
FORMAT_FLOAT = 4,
NUM_NRM_FORMAT
};
static int FormatBaseSize(int format)
{
if (format == FORMAT_UBYTE) return 1;
else if (format == FORMAT_BYTE) return 1;
else if (format == FORMAT_USHORT) return 2;
else if (format == FORMAT_SHORT) return 2;
else if (format == FORMAT_FLOAT) return sizeof(float);
else return 0;
}
enum ENormalElements
{
NRM_NBT = 0,
NRM_NBT3 = 1,
NUM_NRM_ELEMENTS
};
enum ENormalIndices
{
NRM_INDICES1 = 0,
NRM_INDICES3 = 1,
NUM_NRM_INDICES
};
/* struct Set
{
template <typename T>
void operator=(const T&)
{
gc_size = T::size;
function = T::function;
}
int gc_size;
// TPipelineFunction function;
};*/
// static Set m_Table[NUM_NRM_TYPE][NUM_NRM_INDICES][NUM_NRM_ELEMENTS][NUM_NRM_FORMAT];
public:
// GetSize
static unsigned int GetSize(unsigned int _type, unsigned int _format,
unsigned int _elements, unsigned int _index3)
{
if (_type == NRM_DIRECT)
{
int base_size = FormatBaseSize(_format);
int num = (_elements == NRM_NBT) ? 1 : 3;
return base_size * num * 3;
}
else if (_type == NRM_INDEX8 || _type == NRM_INDEX16)
{
int base_size = (_type == NRM_INDEX8) ? 1 : 2;
if (_index3 == NRM_INDICES1)
return base_size;
else
{
if ( _elements == NRM_NBT)
return base_size;
else
return 3 * base_size;
}
}
else
return 0;
}
};
#endif

View File

@@ -0,0 +1,39 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef VERTEXLOADER_POSITION_H
#define VERTEXLOADER_POSITION_H
class VertexLoader_Position {
public:
// Init
static void Init(void);
// GetSize
static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements)
{
const int tableReadPositionVertexSize[4][8][2] =
{
{
{0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,},
},
{
{2, 3,}, {2, 3,}, {4, 6,}, {4, 6,}, {8, 12,},
},
{
{1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,},
},
{
{2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,},
},
};
return tableReadPositionVertexSize[_type][_format][_elements];
}
// GetFunction
// static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements);
};
#endif

View File

@@ -0,0 +1,46 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef VERTEXLOADER_TEXCOORD_H
#define VERTEXLOADER_TEXCOORD_H
//#include "NativeVertexFormat.h"
class VertexLoader_TextCoord
{
public:
// Init
static void Init(void);
// GetSize
static unsigned int GetSize(unsigned int _type, unsigned int _format, unsigned int _elements)
{
const int tableReadTexCoordVertexSize[4][8][2] =
{
{
{0, 0,}, {0, 0,}, {0, 0,}, {0, 0,}, {0, 0,},
},
{
{1, 2,}, {1, 2,}, {2, 4,}, {2, 4,}, {4, 8,},
},
{
{1, 1,}, {1, 1,}, {1, 1,}, {1, 1,}, {1, 1,},
},
{
{2, 2,}, {2, 2,}, {2, 2,}, {2, 2,}, {2, 2,},
},
};
return tableReadTexCoordVertexSize[_type][_format][_elements];
}
// GetFunction
// static TPipelineFunction GetFunction(unsigned int _type, unsigned int _format, unsigned int _elements);
// GetDummyFunction
// It is important to synchronize tcIndex.
// static TPipelineFunction GetDummyFunction();
};
#endif

View File

@@ -93,6 +93,20 @@ uint16_t le16toh(uint16_t val)
return ((val&0xff)<<8)|((val&0xff00)>>8);
}
uint64_t be64toh(uint64_t val)
{
return val;
}
uint32_t be32toh(uint32_t val)
{
return val;
}
uint16_t be16toh(uint16_t val)
{
return val;
}
#elif BYTE_ORDER==LITTLE_ENDIAN
#error other stuff
@@ -252,25 +266,26 @@ struct FifoData
wgPipe->U32 = (i<<24)|(le32toh(bpmem[i])&0xffffff);
}
#define LoadCPReg(addr, val) { wgPipe->U8 = 0x08; wgPipe->U8 = addr; wgPipe->U32 = val; }
#define MLoadCPReg(addr, val) { wgPipe->U8 = 0x08; wgPipe->U8 = addr; wgPipe->U32 = val; }
LoadCPReg(0x30, le32toh(cpmem[0x30]));
LoadCPReg(0x40, le32toh(cpmem[0x40]));
LoadCPReg(0x50, le32toh(cpmem[0x50]));
LoadCPReg(0x60, le32toh(cpmem[0x60]));
MLoadCPReg(0x30, le32toh(cpmem[0x30]));
MLoadCPReg(0x40, le32toh(cpmem[0x40]));
MLoadCPReg(0x50, le32toh(cpmem[0x50]));
MLoadCPReg(0x60, le32toh(cpmem[0x60]));
for (int i = 0; i < 8; ++i)
{
LoadCPReg(0x70 + i, le32toh(cpmem[0x70 + i]));
LoadCPReg(0x80 + i, le32toh(cpmem[0x80 + i]));
LoadCPReg(0x90 + i, le32toh(cpmem[0x90 + i]));
MLoadCPReg(0x70 + i, le32toh(cpmem[0x70 + i]));
MLoadCPReg(0x80 + i, le32toh(cpmem[0x80 + i]));
MLoadCPReg(0x90 + i, le32toh(cpmem[0x90 + i]));
}
for (int i = 0; i < 16; ++i)
{
LoadCPReg(0xa0 + i, le32toh(cpmem[0xa0 + i]));
LoadCPReg(0xb0 + i, le32toh(cpmem[0xb0 + i]));
MLoadCPReg(0xa0 + i, le32toh(cpmem[0xa0 + i]));
MLoadCPReg(0xb0 + i, le32toh(cpmem[0xb0 + i]));
}
#undef MLoadCPReg
for (unsigned int i = 0; i < xfmem.size(); i += 16)
{
@@ -345,6 +360,160 @@ void LoadDffData(FifoData& out)
out.xfregs.insert(out.xfregs.begin(), xf_regs_ptr, xf_regs_ptr + xf_regs_size);
}
struct AnalyzedFrameInfo
{
std::vector<u32> object_starts;
std::vector<u32> object_ends;
// std::vector<MemoryUpdate> memory_updates;
};
#include "OpcodeDecoding.h"
#include "BPMemory.h"
#include "FifoAnalyzer.h"
class FifoDataAnalyzer
{
public:
void AnalyzeFrames(FifoData& data, std::vector<AnalyzedFrameInfo>& frame_info)
{
// TODO: Load BP mem
u32 *cpMem = &data.cpmem[0];
LoadCPReg(0x50, cpMem[0x50], m_cpmem);
LoadCPReg(0x60, cpMem[0x60], m_cpmem);
for (int i = 0; i < 8; ++i)
{
LoadCPReg(0x70 + i, cpMem[0x70 + i], m_cpmem);
LoadCPReg(0x80 + i, cpMem[0x80 + i], m_cpmem);
LoadCPReg(0x90 + i, cpMem[0x90 + i], m_cpmem);
}
frame_info.clear();
frame_info.resize(data.frames.size());
m_drawingObject = false;
for (unsigned int frame_idx = 0; frame_idx < data.frames.size(); ++frame_idx)
{
FifoFrameData& src_frame = data.frames[frame_idx];
AnalyzedFrameInfo& dst_frame = frame_info[frame_idx];
u32 cmd_start = 0;
while (cmd_start < src_frame.fifoData.size())
{
bool was_drawing = m_drawingObject;
u32 cmd_size = DecodeCommand(&src_frame.fifoData[cmd_start]);
// TODO: Check that cmd_size != 0
if (was_drawing != m_drawingObject)
{
if (m_drawingObject)
dst_frame.object_starts.push_back(cmd_start);
else
dst_frame.object_ends.push_back(cmd_start);
}
cmd_start += cmd_size;
}
if (dst_frame.object_ends.size() < dst_frame.object_starts.size())
dst_frame.object_ends.push_back(cmd_start);
}
}
u32 DecodeCommand(u8* data)
{
u8* data_start = data;
u8 cmd = ReadFifo8(data);
switch (cmd)
{
case GX_NOP:
case 0x44:
case GX_CMD_INVL_VC:
break;
case GX_LOAD_CP_REG:
{
m_drawingObject = false;
u32 cmd2 = ReadFifo8(data);
u32 value = ReadFifo32(data);
LoadCPReg(cmd2, value, m_cpmem);
break;
}
case GX_LOAD_XF_REG:
{
m_drawingObject = false;
u32 cmd2 = ReadFifo32(data);
u8 stream_size = ((cmd2 >> 16) & 0xf) + 1; // TODO: Check if this works!
data += stream_size * 4;
break;
}
case GX_LOAD_INDX_A:
case GX_LOAD_INDX_B:
case GX_LOAD_INDX_C:
case GX_LOAD_INDX_D:
m_drawingObject = false;
data += 4;
break;
case GX_CMD_CALL_DL:
// The recorder should have expanded display lists into the fifo stream and skipped the call to start them
// That is done to make it easier to track where memory is updated
//_assert_(false);
printf("Shouldn't have a DL here...\n");
data += 8;
break;
case GX_LOAD_BP_REG:
{
m_drawingObject = false;
u32 cmd2 = ReadFifo32(data);
//BPCmd bp = FifoAnalyzer::DecodeBPCmd(cmd2, m_BpMem); // TODO
//FifoAnalyzer::LoadBPReg(bp, m_BpMem);
// TODO: Load BP reg..
// TODO
// if (bp.address == BPMEM_TRIGGER_EFB_COPY)
// StoreEfbCopyRegion();
break;
}
default:
if (cmd & 0x80)
{
m_drawingObject = true;
u32 vtxAttrGroup = cmd & GX_VAT_MASK;
int vertex_size = CalculateVertexSize(vtxAttrGroup, m_cpmem);
u16 stream_size = ReadFifo16(data);
data += stream_size * vertex_size;
}
else
{
printf("Invalid fifo command 0x%x\n", cmd);
}
break;
}
return data - data_start;
}
private:
bool m_drawingObject;
CPMemory m_cpmem;
};
#pragma pack(pop)
#define DEFAULT_FIFO_SIZE (256*1024)
@@ -398,6 +567,10 @@ int main()
FifoData fifo_data;
LoadDffData(fifo_data);
FifoDataAnalyzer analyzer;
std::vector<AnalyzedFrameInfo> analyzed_frames;
analyzer.AnalyzeFrames(fifo_data, analyzed_frames);
for (unsigned int i = 0; i < fifo_data.frames[0].fifoData.size(); ++i)
{
printf("%02x", fifo_data.frames[0].fifoData[i]);
@@ -417,10 +590,6 @@ int main()
fifo_data.ApplyInitialState();
for (unsigned int i = 0; i < fifo_data.frames[cur_frame].fifoData.size(); ++i)
wgPipe->U8 = fifo_data.frames[cur_frame].fifoData[i];
#endif
// for (element = frame_elements[cur_frame])
{
// switch (element.type)
{
@@ -447,10 +616,10 @@ int main()
// memcpy (GetPointer(element.start_addr), element.data, element.size);
// break;
}
wgPipe->U8 = fifo_data.frames[cur_frame].fifoData[i];
}
// finish frame...
#if ENABLE_CONSOLE!=1
GX_CopyDisp(frameBuffer[fb],GX_TRUE);
VIDEO_SetNextFramebuffer(frameBuffer[fb]);