forked from dolphin-emu/dolphin
		
	git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1441 8ced0084-cf51-0410-be5f-012b33b47a6e
		
			
				
	
	
		
			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
 |