DX9/DX11: Workaround the viewpoint/EFB creation issues in e.g. SMG2 on NVIDIA hardwar...
[dolphin.git] / Source / Plugins / Plugin_VideoDX9 / Src / DLCompiler.cpp
blob5d81be3b6b2b9e01a63a4e8eff297a12b6ba2603
1 #include "stdafx.h"
3 #if 0
5 #include "OpcodeDecoding.h"
6 #include "VertexLoader.h"
7 #include "VertexHandler.h"
8 #include "DataReader.h"
9 #include "BPStructs.h"
10 #include "CPStructs.h"
11 #include "XFStructs.h"
12 #include "DLCompiler.h"
13 #include "x86.h"
14 #include "main.h"
15 #include "Utils.h"
17 CompiledDList::CompiledDList(u32 _addr, u32 _size)
19 dataSize = 0;
20 data = 0;
21 code = 0;
22 addr = _addr;
23 size = _size;
24 pass = 0;
25 numBatches = 0;
26 batches = 0;
29 CompiledDList::~CompiledDList()
31 if (data)
32 delete [] data;
33 if (code)
34 delete [] code;
35 if (batches)
36 delete [] batches;
40 bool CompiledDList::Call()
42 switch(pass) {
43 case 0: // First compiling pass : find data size
44 if (Pass1())
46 pass = 1;
47 return true;
49 else
50 return false;
51 case 1: // Second compiling pass : actually compile
52 //if pass1 succeeded, pass2 will too
53 Pass2();
54 pass = 2;
55 return true;
56 case 2: // Run pass - we have a compiled dlist, just call it
57 Run();
58 return true;
59 default:
60 //ERROR
61 return false;
66 bool CompiledDList::Pass1()
68 /* //find the size of code + data, if the dlist is worth recompiling etc
69 // at the same time, do the ordinary stuff
70 g_pDataReader = &dlistReader;
71 OpcodeReaders::SetDListReader(addr, addr+size);
72 dataSize = 0;
73 codeSize = 0;
74 numBatches = 0;
75 bool lastIsPrim = false;
76 while (OpcodeReaders::IsDListOKToRead())
78 int Cmd = g_pDataReader->Read8();
79 switch(Cmd)
81 case GX_LOAD_CP_REG: //0x08
83 u32 SubCmd = g_pDataReader->Read8();
84 u32 Value = g_pDataReader->Read32();
85 LoadCPReg(SubCmd,Value);
86 //COMPILER
87 codeSize+=13;
89 break;
91 case GX_LOAD_XF_REG:
93 u32 Cmd2 = g_pDataReader->Read32();
94 int dwTransferSize = ((Cmd2>>16)&15) + 1;
95 DWORD dwAddress = Cmd2 & 0xFFFF;
96 static u32 pData[16];
97 for (int i=0; i<dwTransferSize; i++)
98 pData[i] = g_pDataReader->Read32();
99 LoadXFReg(dwTransferSize,dwAddress,pData);
100 //COMPILER
101 dataSize+=dwTransferSize;
102 codeSize+=17;
104 break;
106 case GX_LOAD_BP_REG: //0x61
108 u32 cmd=g_pDataReader->Read32();
109 LoadBPReg(cmd);
110 codeSize+=9;
112 break;
114 case GX_LOAD_INDX_A: //used for position matrices
115 LoadIndexedXF(g_pDataReader->Read32(),0xC);
116 codeSize+=13;
117 break;
118 case GX_LOAD_INDX_B: //used for normal matrices
119 LoadIndexedXF(g_pDataReader->Read32(),0xD);
120 codeSize+=13;
121 break;
122 case GX_LOAD_INDX_C: //used for postmatrices
123 LoadIndexedXF(g_pDataReader->Read32(),0xE);
124 codeSize+=13;
125 break;
126 case GX_LOAD_INDX_D: //used for lights
127 LoadIndexedXF(g_pDataReader->Read32(),0xF);
128 codeSize+=13;
129 break;
131 case GX_CMD_CALL_DL:
132 MessageBox(0,"Display lists can't recurse!!","error",0);
133 break;
135 case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
136 break;
137 case GX_NOP:
138 break;
139 default:
140 if (Cmd&0x80)
142 int primitive = (Cmd&GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
143 if (lastIsPrim)
145 //join to last
147 else
149 //finish up last and commit
151 u16 numVertices = g_pDataReader->Read16();
152 tempvarray.Reset();
153 VertexLoader::SetVArray(&tempvarray);
154 VertexLoader *loader = &VertexLoader[Cmd&GX_VAT_MASK];
155 loader->Setup();
156 loader->PrepareRun();
157 int vsize = loader->GetVertexSize();
158 loader->RunVertices(numVertices);
159 CVertexHandler::DrawVertices(primitive, numVertices, &tempvarray);
160 CVertexHandler::Flush();
161 //COMPILER
162 codeSize+=21;
163 numBatches++;
164 lastIsPrim = true;
166 break;
169 if (lastIsPrim)
171 //finish up last and commit
173 codeSize*=2;*/
174 return true;
178 void CompiledDList::Pass2()
180 /* OpcodeReaders::SetDListReader(addr, addr+size);
182 data = new u32[dataSize];
183 code = new u8[codeSize]; //at least
185 batches = new Batch[numBatches];
186 int batchCount = 0;
187 u32 *dataptr = data;
189 x86Init();
190 x86SetPtr((s8*)code);
191 //WC8(0xCC);
193 //actually do the recompiling, emit code and data, protect the memory
194 // but again, at the same time do the ordinary stuff
195 // so the compiled display list won't be run until the third time actually
196 bool dump = false,lastIsGeom=false;
197 FILE *f;
199 #ifndef TEASER
200 if (dump)
202 f=fopen("D:\\dlistlogs.txt","a");
203 fprintf(f,"===========================================\n");
205 #endif
207 while (OpcodeReaders::IsDListOKToRead())
209 int Cmd = g_pDataReader->Read8();
210 switch(Cmd)
212 case GX_LOAD_CP_REG: //0x08
214 lastIsGeom = false;
215 u32 SubCmd = g_pDataReader->Read8();
216 u32 Value = g_pDataReader->Read32();
217 if (dump)
218 fprintf(f,"CP | %02x %08x\n",SubCmd,Value);
220 LoadCPReg(SubCmd,Value);
221 //COMPILER
222 PUSH_WordToStack(Value);
223 PUSH_WordToStack(SubCmd);
224 CALLFunc((u32)LoadCPReg);
226 break;
228 case GX_LOAD_XF_REG:
230 lastIsGeom = false;
231 u32 Cmd2 = g_pDataReader->Read32();
232 int dwTransferSize = ((Cmd2>>16)&15) + 1;
233 u32 dwAddress = Cmd2 & 0xFFFF;
234 static u32 pData[16];
236 u32 *oldDataPtr = dataptr;
238 if (dump)
240 fprintf(f,"XF | %01xx %04x\n",dwTransferSize,dwAddress);
241 for (int i=0; i<dwTransferSize; i++)
242 fprintf(f, "%08x | %f\n",oldDataPtr[i], *((float*)oldDataPtr+i));
246 for (int i=0; i<dwTransferSize; i++) // a little compiler here too
247 *dataptr++ = g_pDataReader->Read32();
250 LoadXFReg(dwTransferSize,dwAddress,oldDataPtr);
252 //COMPILER
253 PUSH_WordToStack((u32)oldDataPtr);
254 PUSH_WordToStack(dwAddress);
255 PUSH_WordToStack(dwTransferSize);
256 CALLFunc((u32)LoadXFReg);
258 break;
260 case GX_LOAD_BP_REG: //0x61
262 lastIsGeom = false;
263 u32 cmd=g_pDataReader->Read32();
264 if (dump)
265 fprintf(f,"BP | %08x\n",cmd);
267 LoadBPReg(cmd);
268 //COMPILER
269 PUSH_WordToStack(cmd);
270 CALLFunc((u32)LoadBPReg);
272 break;
274 case GX_LOAD_INDX_A: //usually used for position matrices
276 lastIsGeom = false;
277 u32 value = g_pDataReader->Read32();
278 LoadIndexedXF(value,0xC);
279 //COMPILER
280 PUSH_WordToStack(0xC);
281 PUSH_WordToStack(value);
282 CALLFunc((u32)LoadIndexedXF);
283 if (dump)
284 fprintf(f,"LOADINDEXA | pos matrix\n");
286 break;
287 case GX_LOAD_INDX_B: //usually used for normal matrices
289 lastIsGeom = false;
290 u32 value = g_pDataReader->Read32();
291 LoadIndexedXF(value,0xD);
292 //COMPILER
293 PUSH_WordToStack(0xD);
294 PUSH_WordToStack(value);
295 CALLFunc((u32)LoadIndexedXF);
296 if (dump)
297 fprintf(f,"LOADINDEXB | nrm matrix\n");
299 break;
300 case GX_LOAD_INDX_C: //usually used for postmatrices
302 lastIsGeom = false;
303 u32 value = g_pDataReader->Read32();
304 LoadIndexedXF(value,0xE);
305 //COMPILER
306 PUSH_WordToStack(0xE);
307 PUSH_WordToStack(value);
308 CALLFunc((u32)LoadIndexedXF);
309 if (dump)
310 fprintf(f,"LOADINDEXC | post matrix\n");
312 break;
313 case GX_LOAD_INDX_D: //usually used for lights
315 lastIsGeom = false;
316 u32 value = g_pDataReader->Read32();
317 LoadIndexedXF(value,0xF);
318 //COMPILER
319 PUSH_WordToStack(0xF);
320 PUSH_WordToStack(value);
321 CALLFunc((u32)LoadIndexedXF);
322 if (dump)
323 fprintf(f,"LOADINDEXD | light\n");
325 break;
326 case GX_CMD_CALL_DL:
327 // ERORRR
328 break;
330 case GX_CMD_INVL_VC:// Invalidate (vertex cache?)
331 if (dump)
332 fprintf(f,"invalidate vc\n");
333 break;
334 case GX_NOP:
335 if (dump)
336 fprintf(f,"nop\n");
337 break;
338 default:
339 if (Cmd&0x80)
341 int primitive = (Cmd&GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT;
342 //if (lastIsGeom) INCSTAT(stats.numJoins);
343 u16 numVertices = g_pDataReader->Read16();
344 if (dump)
345 fprintf(f,"DP: prim=%02x numv=%i\n",primitive,numVertices);
346 DecodedVArray &va = batches[batchCount].varray;
348 VertexLoader *loader = &VertexLoader[Cmd&GX_VAT_MASK];
349 TVtxDesc &vd = loader->GetVtxDesc();
351 VertexLoader::SetVArray(&va);
352 loader->Setup();
353 loader->PrepareRun();
354 // va.numColors = loader->GetNumColors();
355 // va.numUVs = loader->GetNumTCs();
356 // va.numNormals = loader->GetNumNormals();
357 //va.num
358 va.Create(numVertices,vd.PosMatIdx,
359 vd.Tex0MatIdx+vd.Tex1MatIdx+vd.Tex2MatIdx+vd.Tex3MatIdx+
360 vd.Tex4MatIdx+vd.Tex5MatIdx+vd.Tex6MatIdx+vd.Tex7MatIdx,
361 va.numNormals, va.numColors, va.numTCs);
363 int vsize = loader->GetVertexSize();
364 loader->RunVertices(numVertices);
365 CVertexHandler::DrawVertices(primitive, numVertices, &va);
366 CVertexHandler::Flush();
367 // YES we have now filled our varray
368 //LETS COMPILE
369 PUSH_WordToStack(primitive);
370 PUSH_WordToStack(batchCount);
371 PUSH_WordToStack((u32)this);
372 CALLFunc((u32)DrawHelperHelper);
373 batchCount++;
374 lastIsGeom = true;
375 if (dump)
376 fprintf(f,"DRAW PRIMITIVE: prim=%02x numv=%i\n",primitive,numVertices);
378 break;
381 if (dump)
383 fprintf(f,"***************************************\n\n\n");
385 RET();
386 if (dump)
387 fclose(f);*/
388 //we're done, next time just kick the compiled list off, much much faster than interpreting!
391 void CompiledDList::DrawHelperHelper(CompiledDList *dl, int vno, int prim)
393 Batch &b = dl->batches[vno];
394 CVertexHandler::DrawVertices(prim, b.varray.GetSize(), &b.varray);
397 void CompiledDList::Run()
399 //run the code
400 ((void (*)())(code))();
401 CVertexHandler::Flush();
404 DListCache::DLCache DListCache::dlists;
408 void DListCache::Init()
414 void DListCache::Shutdown()
416 DLCache::iterator iter = dlists.begin();
417 for (;iter!=dlists.end();iter++)
418 iter->second.Destroy();
419 dlists.clear();
423 void DListCache::Call(u32 _addr, u32 _size)
425 DLCache::iterator iter;
426 iter = dlists.find(_addr);
428 if (iter != dlists.end())
430 if (iter->second.size == _size)
432 iter->second.dlist->Call();
433 return;
435 else // wrong size, need to recompile
437 iter->second.Destroy();
438 iter=dlists.erase(iter);
442 //Make an entry in the table
443 DLCacheEntry entry;
444 entry.dlist = new CompiledDList(_addr, _size);
445 entry.dlist->Call();
446 entry.frameCount = frameCount;
447 entry.size = _size;
448 dlists[_addr] = entry;
450 INCSTAT(stats.numDListsCreated);
451 SETSTAT(stats.numDListsAlive,(int)dlists.size());
454 void DListCache::Cleanup()
456 for (DLCache::iterator iter=dlists.begin(); iter!=dlists.end();iter++)
458 DLCacheEntry &entry = iter->second;
459 if (entry.frameCount<frameCount-80)
461 entry.Destroy();
462 iter = dlists.erase(iter);
465 SETSTAT(stats.numDListsAlive,(int)dlists.size());
468 #endif