468 lines
10 KiB
C++
468 lines
10 KiB
C++
#include "stdafx.h"
|
|
|
|
#if 0
|
|
|
|
#include "OpcodeDecoding.h"
|
|
#include "VertexLoader.h"
|
|
#include "VertexHandler.h"
|
|
#include "DataReader.h"
|
|
#include "BPStructs.h"
|
|
#include "CPStructs.h"
|
|
#include "XFStructs.h"
|
|
#include "DLCompiler.h"
|
|
#include "x86.h"
|
|
#include "main.h"
|
|
#include "Utils.h"
|
|
|
|
CompiledDList::CompiledDList(u32 _addr, u32 _size)
|
|
{
|
|
dataSize = 0;
|
|
data = 0;
|
|
code = 0;
|
|
addr = _addr;
|
|
size = _size;
|
|
pass = 0;
|
|
numBatches = 0;
|
|
batches = 0;
|
|
}
|
|
|
|
CompiledDList::~CompiledDList()
|
|
{
|
|
if (data)
|
|
delete [] data;
|
|
if (code)
|
|
delete [] code;
|
|
if (batches)
|
|
delete [] batches;
|
|
}
|
|
|
|
|
|
bool CompiledDList::Call()
|
|
{
|
|
switch(pass) {
|
|
case 0: // First compiling pass : find data size
|
|
if (Pass1())
|
|
{
|
|
pass = 1;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
case 1: // Second compiling pass : actually compile
|
|
//if pass1 succeeded, pass2 will too
|
|
Pass2();
|
|
pass = 2;
|
|
return true;
|
|
case 2: // Run pass - we have a compiled dlist, just call it
|
|
Run();
|
|
return true;
|
|
default:
|
|
//ERROR
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
bool CompiledDList::Pass1()
|
|
{
|
|
/* //find the size of code + data, if the dlist is worth recompiling etc
|
|
// at the same time, do the ordinary stuff
|
|
g_pDataReader = &dlistReader;
|
|
OpcodeReaders::SetDListReader(addr, addr+size);
|
|
dataSize = 0;
|
|
codeSize = 0;
|
|
numBatches = 0;
|
|
bool lastIsPrim = false;
|
|
while (OpcodeReaders::IsDListOKToRead())
|
|
{
|
|
int Cmd = g_pDataReader->Read8();
|
|
switch(Cmd)
|
|
{
|
|
case GX_LOAD_CP_REG: //0x08
|
|
{
|
|
u32 SubCmd = g_pDataReader->Read8();
|
|
u32 Value = g_pDataReader->Read32();
|
|
LoadCPReg(SubCmd,Value);
|
|
//COMPILER
|
|
codeSize+=13;
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_XF_REG:
|
|
{
|
|
u32 Cmd2 = g_pDataReader->Read32();
|
|
int dwTransferSize = ((Cmd2>>16)&15) + 1;
|
|
DWORD dwAddress = Cmd2 & 0xFFFF;
|
|
static u32 pData[16];
|
|
for (int i=0; i<dwTransferSize; i++)
|
|
pData[i] = g_pDataReader->Read32();
|
|
LoadXFReg(dwTransferSize,dwAddress,pData);
|
|
//COMPILER
|
|
dataSize+=dwTransferSize;
|
|
codeSize+=17;
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_BP_REG: //0x61
|
|
{
|
|
u32 cmd=g_pDataReader->Read32();
|
|
LoadBPReg(cmd);
|
|
codeSize+=9;
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_INDX_A: //used for position matrices
|
|
LoadIndexedXF(g_pDataReader->Read32(),0xC);
|
|
codeSize+=13;
|
|
break;
|
|
case GX_LOAD_INDX_B: //used for normal matrices
|
|
LoadIndexedXF(g_pDataReader->Read32(),0xD);
|
|
codeSize+=13;
|
|
break;
|
|
case GX_LOAD_INDX_C: //used for postmatrices
|
|
LoadIndexedXF(g_pDataReader->Read32(),0xE);
|
|
codeSize+=13;
|
|
break;
|
|
case GX_LOAD_INDX_D: //used for lights
|
|
LoadIndexedXF(g_pDataReader->Read32(),0xF);
|
|
codeSize+=13;
|
|
break;
|
|
|
|
case GX_CMD_CALL_DL:
|
|
MessageBox(0,"Display lists can't recurse!!","error",0);
|
|
break;
|
|
|
|
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
|
|
break;
|
|
case GX_NOP:
|
|
break;
|
|
default:
|
|
if (Cmd&0x80)
|
|
{
|
|
int primitive = (Cmd&GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
|
|
if (lastIsPrim)
|
|
{
|
|
//join to last
|
|
}
|
|
else
|
|
{
|
|
//finish up last and commit
|
|
}
|
|
u16 numVertices = g_pDataReader->Read16();
|
|
tempvarray.Reset();
|
|
VertexLoader::SetVArray(&tempvarray);
|
|
VertexLoader *loader = &VertexLoader[Cmd&GX_VAT_MASK];
|
|
loader->Setup();
|
|
loader->PrepareRun();
|
|
int vsize = loader->GetVertexSize();
|
|
loader->RunVertices(numVertices);
|
|
CVertexHandler::DrawVertices(primitive, numVertices, &tempvarray);
|
|
CVertexHandler::Flush();
|
|
//COMPILER
|
|
codeSize+=21;
|
|
numBatches++;
|
|
lastIsPrim = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (lastIsPrim)
|
|
{
|
|
//finish up last and commit
|
|
}
|
|
codeSize*=2;*/
|
|
return true;
|
|
}
|
|
|
|
|
|
void CompiledDList::Pass2()
|
|
{
|
|
/* OpcodeReaders::SetDListReader(addr, addr+size);
|
|
|
|
data = new u32[dataSize];
|
|
code = new u8[codeSize]; //at least
|
|
|
|
batches = new Batch[numBatches];
|
|
int batchCount = 0;
|
|
u32 *dataptr = data;
|
|
|
|
x86Init();
|
|
x86SetPtr((s8*)code);
|
|
//WC8(0xCC);
|
|
|
|
//actually do the recompiling, emit code and data, protect the memory
|
|
// but again, at the same time do the ordinary stuff
|
|
// so the compiled display list won't be run until the third time actually
|
|
bool dump = false,lastIsGeom=false;
|
|
FILE *f;
|
|
|
|
#ifndef TEASER
|
|
if (dump)
|
|
{
|
|
f=fopen("D:\\dlistlogs.txt","a");
|
|
fprintf(f,"===========================================\n");
|
|
}
|
|
#endif
|
|
|
|
while (OpcodeReaders::IsDListOKToRead())
|
|
{
|
|
int Cmd = g_pDataReader->Read8();
|
|
switch(Cmd)
|
|
{
|
|
case GX_LOAD_CP_REG: //0x08
|
|
{
|
|
lastIsGeom = false;
|
|
u32 SubCmd = g_pDataReader->Read8();
|
|
u32 Value = g_pDataReader->Read32();
|
|
if (dump)
|
|
fprintf(f,"CP | %02x %08x\n",SubCmd,Value);
|
|
|
|
LoadCPReg(SubCmd,Value);
|
|
//COMPILER
|
|
PUSH_WordToStack(Value);
|
|
PUSH_WordToStack(SubCmd);
|
|
CALLFunc((u32)LoadCPReg);
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_XF_REG:
|
|
{
|
|
lastIsGeom = false;
|
|
u32 Cmd2 = g_pDataReader->Read32();
|
|
int dwTransferSize = ((Cmd2>>16)&15) + 1;
|
|
u32 dwAddress = Cmd2 & 0xFFFF;
|
|
static u32 pData[16];
|
|
|
|
u32 *oldDataPtr = dataptr;
|
|
|
|
if (dump)
|
|
{
|
|
fprintf(f,"XF | %01xx %04x\n",dwTransferSize,dwAddress);
|
|
for (int i=0; i<dwTransferSize; i++)
|
|
fprintf(f, "%08x | %f\n",oldDataPtr[i], *((float*)oldDataPtr+i));
|
|
}
|
|
|
|
|
|
for (int i=0; i<dwTransferSize; i++) // a little compiler here too
|
|
*dataptr++ = g_pDataReader->Read32();
|
|
|
|
|
|
LoadXFReg(dwTransferSize,dwAddress,oldDataPtr);
|
|
|
|
//COMPILER
|
|
PUSH_WordToStack((u32)oldDataPtr);
|
|
PUSH_WordToStack(dwAddress);
|
|
PUSH_WordToStack(dwTransferSize);
|
|
CALLFunc((u32)LoadXFReg);
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_BP_REG: //0x61
|
|
{
|
|
lastIsGeom = false;
|
|
u32 cmd=g_pDataReader->Read32();
|
|
if (dump)
|
|
fprintf(f,"BP | %08x\n",cmd);
|
|
|
|
LoadBPReg(cmd);
|
|
//COMPILER
|
|
PUSH_WordToStack(cmd);
|
|
CALLFunc((u32)LoadBPReg);
|
|
}
|
|
break;
|
|
|
|
case GX_LOAD_INDX_A: //usually used for position matrices
|
|
{
|
|
lastIsGeom = false;
|
|
u32 value = g_pDataReader->Read32();
|
|
LoadIndexedXF(value,0xC);
|
|
//COMPILER
|
|
PUSH_WordToStack(0xC);
|
|
PUSH_WordToStack(value);
|
|
CALLFunc((u32)LoadIndexedXF);
|
|
if (dump)
|
|
fprintf(f,"LOADINDEXA | pos matrix\n");
|
|
}
|
|
break;
|
|
case GX_LOAD_INDX_B: //usually used for normal matrices
|
|
{
|
|
lastIsGeom = false;
|
|
u32 value = g_pDataReader->Read32();
|
|
LoadIndexedXF(value,0xD);
|
|
//COMPILER
|
|
PUSH_WordToStack(0xD);
|
|
PUSH_WordToStack(value);
|
|
CALLFunc((u32)LoadIndexedXF);
|
|
if (dump)
|
|
fprintf(f,"LOADINDEXB | nrm matrix\n");
|
|
}
|
|
break;
|
|
case GX_LOAD_INDX_C: //usually used for postmatrices
|
|
{
|
|
lastIsGeom = false;
|
|
u32 value = g_pDataReader->Read32();
|
|
LoadIndexedXF(value,0xE);
|
|
//COMPILER
|
|
PUSH_WordToStack(0xE);
|
|
PUSH_WordToStack(value);
|
|
CALLFunc((u32)LoadIndexedXF);
|
|
if (dump)
|
|
fprintf(f,"LOADINDEXC | post matrix\n");
|
|
}
|
|
break;
|
|
case GX_LOAD_INDX_D: //usually used for lights
|
|
{
|
|
lastIsGeom = false;
|
|
u32 value = g_pDataReader->Read32();
|
|
LoadIndexedXF(value,0xF);
|
|
//COMPILER
|
|
PUSH_WordToStack(0xF);
|
|
PUSH_WordToStack(value);
|
|
CALLFunc((u32)LoadIndexedXF);
|
|
if (dump)
|
|
fprintf(f,"LOADINDEXD | light\n");
|
|
}
|
|
break;
|
|
case GX_CMD_CALL_DL:
|
|
// ERORRR
|
|
break;
|
|
|
|
case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
|
|
if (dump)
|
|
fprintf(f,"invalidate vc\n");
|
|
break;
|
|
case GX_NOP:
|
|
if (dump)
|
|
fprintf(f,"nop\n");
|
|
break;
|
|
default:
|
|
if (Cmd&0x80)
|
|
{
|
|
int primitive = (Cmd&GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
|
|
//if (lastIsGeom) INCSTAT(stats.numJoins);
|
|
u16 numVertices = g_pDataReader->Read16();
|
|
if (dump)
|
|
fprintf(f,"DP: prim=%02x numv=%i\n",primitive,numVertices);
|
|
DecodedVArray &va = batches[batchCount].varray;
|
|
|
|
VertexLoader *loader = &VertexLoader[Cmd&GX_VAT_MASK];
|
|
TVtxDesc &vd = loader->GetVtxDesc();
|
|
|
|
VertexLoader::SetVArray(&va);
|
|
loader->Setup();
|
|
loader->PrepareRun();
|
|
// va.numColors = loader->GetNumColors();
|
|
// va.numUVs = loader->GetNumTCs();
|
|
// va.numNormals = loader->GetNumNormals();
|
|
//va.num
|
|
va.Create(numVertices,vd.PosMatIdx,
|
|
vd.Tex0MatIdx+vd.Tex1MatIdx+vd.Tex2MatIdx+vd.Tex3MatIdx+
|
|
vd.Tex4MatIdx+vd.Tex5MatIdx+vd.Tex6MatIdx+vd.Tex7MatIdx,
|
|
va.numNormals, va.numColors, va.numTCs);
|
|
|
|
int vsize = loader->GetVertexSize();
|
|
loader->RunVertices(numVertices);
|
|
CVertexHandler::DrawVertices(primitive, numVertices, &va);
|
|
CVertexHandler::Flush();
|
|
// YES we have now filled our varray
|
|
//LETS COMPILE
|
|
PUSH_WordToStack(primitive);
|
|
PUSH_WordToStack(batchCount);
|
|
PUSH_WordToStack((u32)this);
|
|
CALLFunc((u32)DrawHelperHelper);
|
|
batchCount++;
|
|
lastIsGeom = true;
|
|
if (dump)
|
|
fprintf(f,"DRAW PRIMITIVE: prim=%02x numv=%i\n",primitive,numVertices);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (dump)
|
|
{
|
|
fprintf(f,"***************************************\n\n\n");
|
|
}
|
|
RET();
|
|
if (dump)
|
|
fclose(f);*/
|
|
//we're done, next time just kick the compiled list off, much much faster than interpreting!
|
|
}
|
|
|
|
void CompiledDList::DrawHelperHelper(CompiledDList *dl, int vno, int prim)
|
|
{
|
|
Batch &b = dl->batches[vno];
|
|
CVertexHandler::DrawVertices(prim, b.varray.GetSize(), &b.varray);
|
|
}
|
|
|
|
void CompiledDList::Run()
|
|
{
|
|
//run the code
|
|
((void (*)())(code))();
|
|
CVertexHandler::Flush();
|
|
}
|
|
|
|
DListCache::DLCache DListCache::dlists;
|
|
|
|
|
|
|
|
void DListCache::Init()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
void DListCache::Shutdown()
|
|
{
|
|
DLCache::iterator iter = dlists.begin();
|
|
for (;iter!=dlists.end();iter++)
|
|
iter->second.Destroy();
|
|
dlists.clear();
|
|
}
|
|
|
|
|
|
void DListCache::Call(u32 _addr, u32 _size)
|
|
{
|
|
DLCache::iterator iter;
|
|
iter = dlists.find(_addr);
|
|
|
|
if (iter != dlists.end())
|
|
{
|
|
if (iter->second.size == _size)
|
|
{
|
|
iter->second.dlist->Call();
|
|
return;
|
|
}
|
|
else // wrong size, need to recompile
|
|
{
|
|
iter->second.Destroy();
|
|
iter=dlists.erase(iter);
|
|
}
|
|
}
|
|
|
|
//Make an entry in the table
|
|
DLCacheEntry entry;
|
|
entry.dlist = new CompiledDList(_addr, _size);
|
|
entry.dlist->Call();
|
|
entry.frameCount = frameCount;
|
|
entry.size = _size;
|
|
dlists[_addr] = entry;
|
|
|
|
INCSTAT(stats.numDListsCreated);
|
|
SETSTAT(stats.numDListsAlive,(int)dlists.size());
|
|
}
|
|
|
|
void DListCache::Cleanup()
|
|
{
|
|
for (DLCache::iterator iter=dlists.begin(); iter!=dlists.end();iter++)
|
|
{
|
|
DLCacheEntry &entry = iter->second;
|
|
if (entry.frameCount<frameCount-80)
|
|
{
|
|
entry.Destroy();
|
|
iter = dlists.erase(iter);
|
|
}
|
|
}
|
|
SETSTAT(stats.numDListsAlive,(int)dlists.size());
|
|
}
|
|
|
|
#endif
|