1 // Copyright (c) 2012- PPSSPP Project.
2
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
11
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18 #include <cstdio>
19
20 #include "Core/MemMap.h"
21 #include "GPU/ge_constants.h"
22 #include "GPU/GPU.h"
23 #include "GPU/GPUState.h"
24
GeDescribeVertexType(u32 op,char * buffer,int len)25 void GeDescribeVertexType(u32 op, char *buffer, int len) {
26 bool through = (op & GE_VTYPE_THROUGH_MASK) == GE_VTYPE_THROUGH;
27 int tc = (op & GE_VTYPE_TC_MASK) >> GE_VTYPE_TC_SHIFT;
28 int col = (op & GE_VTYPE_COL_MASK) >> GE_VTYPE_COL_SHIFT;
29 int nrm = (op & GE_VTYPE_NRM_MASK) >> GE_VTYPE_NRM_SHIFT;
30 int pos = (op & GE_VTYPE_POS_MASK) >> GE_VTYPE_POS_SHIFT;
31 int weight = (op & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT;
32 int weightCount = ((op & GE_VTYPE_WEIGHTCOUNT_MASK) >> GE_VTYPE_WEIGHTCOUNT_SHIFT) + 1;
33 int morphCount = (op & GE_VTYPE_MORPHCOUNT_MASK) >> GE_VTYPE_MORPHCOUNT_SHIFT;
34 int idx = (op & GE_VTYPE_IDX_MASK) >> GE_VTYPE_IDX_SHIFT;
35
36 static const char *colorNames[] = {
37 NULL,
38 "unsupported1",
39 "unsupported2",
40 "unsupported3",
41 "BGR 565",
42 "ABGR 1555",
43 "ABGR 4444",
44 "ABGR 8888",
45 };
46 static const char *typeNames[] = {
47 NULL,
48 "u8",
49 "u16",
50 "float",
51 };
52 static const char *typeNamesI[] = {
53 NULL,
54 "u8",
55 "u16",
56 "u32",
57 };
58 static const char *typeNamesS[] = {
59 NULL,
60 "s8",
61 "s16",
62 "float",
63 };
64
65 char *w = buffer, *end = buffer + len;
66 if (through)
67 w += snprintf(w, end - w, "through, ");
68 if (typeNames[tc] && w < end)
69 w += snprintf(w, end - w, "%s texcoords, ", typeNames[tc]);
70 if (colorNames[col] && w < end)
71 w += snprintf(w, end - w, "%s colors, ", colorNames[col]);
72 if (typeNames[nrm] && w < end)
73 w += snprintf(w, end - w, "%s normals, ", typeNamesS[nrm]);
74 if (typeNames[pos] && w < end)
75 w += snprintf(w, end - w, "%s positions, ", typeNamesS[pos]);
76 if (typeNames[weight] && w < end)
77 w += snprintf(w, end - w, "%s weights (%d), ", typeNames[weight], weightCount);
78 else if (weightCount > 1 && w < end)
79 w += snprintf(w, end - w, "unknown weights (%d), ", weightCount);
80 if (morphCount > 0 && w < end)
81 w += snprintf(w, end - w, "%d morphs, ", morphCount);
82 if (typeNamesI[idx] && w < end)
83 w += snprintf(w, end - w, "%s indexes, ", typeNamesI[idx]);
84
85 if (w < buffer + 2)
86 snprintf(buffer, len, "none");
87 // Otherwise, get rid of the pesky trailing comma.
88 else if (w < end)
89 w[-2] = '\0';
90 }
91
GeDisassembleOp(u32 pc,u32 op,u32 prev,char * buffer,int bufsize)92 void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) {
93 u32 cmd = op >> 24;
94 u32 data = op & 0xFFFFFF;
95
96 // Handle control and drawing commands here directly. The others we delegate.
97 switch (cmd)
98 {
99 case GE_CMD_NOP:
100 if (data != 0)
101 snprintf(buffer, bufsize, "NOP: data= %06x", data);
102 else
103 snprintf(buffer, bufsize, "NOP");
104 break;
105
106 // Pretty sure this is some sort of NOP to eat some pipelining issue,
107 // often seen after CALL instructions.
108 case GE_CMD_NOP_FF:
109 if (data != 0)
110 snprintf(buffer, bufsize, "NOP_FF: data= %06x", data);
111 else
112 snprintf(buffer, bufsize, "NOP_FF");
113 break;
114
115 case GE_CMD_BASE:
116 snprintf(buffer, bufsize, "BASE: %06x", data);
117 break;
118
119 case GE_CMD_VADDR:
120 snprintf(buffer, bufsize, "VADDR: %06x => %08x", data, gstate_c.getRelativeAddress(data));
121 break;
122
123 case GE_CMD_IADDR:
124 snprintf(buffer, bufsize, "IADDR: %06x => %08x", data, gstate_c.getRelativeAddress(data));
125 break;
126
127 case GE_CMD_PRIM:
128 {
129 u32 count = data & 0xFFFF;
130 u32 type = (data >> 16) & 7;
131 static const char* types[8] = {
132 "POINTS",
133 "LINES",
134 "LINE_STRIP",
135 "TRIANGLES",
136 "TRIANGLE_STRIP",
137 "TRIANGLE_FAN",
138 "RECTANGLES",
139 "CONTINUE_PREVIOUS",
140 };
141 if (gstate.vertType & GE_VTYPE_IDX_MASK)
142 snprintf(buffer, bufsize, "DRAW PRIM %s: count= %i vaddr= %08x, iaddr= %08x", type < 7 ? types[type] : "INVALID", count, gstate_c.vertexAddr, gstate_c.indexAddr);
143 else
144 snprintf(buffer, bufsize, "DRAW PRIM %s: count= %i vaddr= %08x", type < 7 ? types[type] : "INVALID", count, gstate_c.vertexAddr);
145 }
146 break;
147
148 case GE_CMD_BEZIER:
149 {
150 int bz_ucount = data & 0xFF;
151 int bz_vcount = (data >> 8) & 0xFF;
152 if (data & 0xFF0000)
153 snprintf(buffer, bufsize, "DRAW BEZIER: %i x %i (extra %x)", bz_ucount, bz_vcount, data >> 16);
154 else
155 snprintf(buffer, bufsize, "DRAW BEZIER: %i x %i", bz_ucount, bz_vcount);
156 }
157 break;
158
159 case GE_CMD_SPLINE:
160 {
161 int sp_ucount = data & 0xFF;
162 int sp_vcount = (data >> 8) & 0xFF;
163 int sp_utype = (data >> 16) & 0x3;
164 int sp_vtype = (data >> 18) & 0x3;
165 if (data & 0xF00000)
166 snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i (type %ix%i, extra %x)", sp_ucount, sp_vcount, sp_utype, sp_vtype, data >> 20);
167 else
168 snprintf(buffer, bufsize, "DRAW SPLINE: %i x %i (type %ix%i)", sp_ucount, sp_vcount, sp_utype, sp_vtype);
169 }
170 break;
171
172 case GE_CMD_JUMP:
173 {
174 u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF;
175 snprintf(buffer, bufsize, "JUMP: %08x to %08x", pc, target);
176 }
177 break;
178
179 case GE_CMD_CALL:
180 {
181 u32 retval = pc + 4;
182 u32 target = gstate_c.getRelativeAddress(op & 0xFFFFFF);
183 snprintf(buffer, bufsize, "CALL: %08x to %08x, ret=%08x", pc, target, retval);
184 }
185 break;
186
187 case GE_CMD_RET:
188 if (data)
189 snprintf(buffer, bufsize, "RET: data= %06x", data);
190 else
191 snprintf(buffer, bufsize, "RET");
192 break;
193
194 case GE_CMD_SIGNAL:
195 snprintf(buffer, bufsize, "SIGNAL %06x", data);
196 break;
197
198 case GE_CMD_FINISH:
199 snprintf(buffer, bufsize, "FINISH %06x", data);
200 break;
201
202 case GE_CMD_END:
203 switch (prev >> 24)
204 {
205 case GE_CMD_SIGNAL:
206 {
207 snprintf(buffer, bufsize, "END - ");
208 // TODO: see http://code.google.com/p/jpcsp/source/detail?r=2935#
209 int behaviour = (prev >> 16) & 0xFF;
210 int signal = prev & 0xFFFF;
211 int enddata = data & 0xFFFFFF;
212 // We should probably defer to sceGe here, no sense in implementing this stuff in every GPU
213 switch (behaviour) {
214 case 1:
215 snprintf(buffer, bufsize, "Signal with wait. signal/end: %04x %04x", signal, enddata);
216 break;
217 case 2:
218 snprintf(buffer, bufsize, "Signal without wait. signal/end: %04x %04x", signal, enddata);
219 break;
220 case 3:
221 snprintf(buffer, bufsize, "Signal with pause. signal/end: %04x %04x", signal, enddata);
222 break;
223 case 8:
224 snprintf(buffer, bufsize, "Signal with sync. signal/end: %04x %04x", signal, enddata);
225 break;
226 case 0x10:
227 snprintf(buffer, bufsize, "Signal with jump. signal/end: %04x %04x", signal, enddata);
228 break;
229 case 0x11:
230 snprintf(buffer, bufsize, "Signal with call. signal/end: %04x %04x", signal, enddata);
231 break;
232 case 0x12:
233 snprintf(buffer, bufsize, "Signal with return. signal/end: %04x %04x", signal, enddata);
234 break;
235 default:
236 snprintf(buffer, bufsize, "UNKNOWN Signal UNIMPLEMENTED %i! signal/end: %04x %04x", behaviour, signal, enddata);
237 break;
238 }
239 }
240 break;
241 case GE_CMD_FINISH:
242 if (data)
243 snprintf(buffer, bufsize, "END: data= %06x", data);
244 else
245 snprintf(buffer, bufsize, "END");
246 break;
247 default:
248 snprintf(buffer, bufsize, "END: %06x, not finished (%08x)", data, prev);
249 break;
250 }
251 break;
252
253 case GE_CMD_BJUMP:
254 {
255 u32 target = (((gstate.base & 0x00FF0000) << 8) | (op & 0xFFFFFC)) & 0x0FFFFFFF;
256 snprintf(buffer, bufsize, "BBOX_JUMP: target= %08x", target);
257 }
258 break;
259
260 case GE_CMD_BOUNDINGBOX:
261 snprintf(buffer, bufsize, "BBOX_TEST: %06x", data);
262 break;
263
264 case GE_CMD_ORIGIN:
265 snprintf(buffer, bufsize, "ORIGIN: %06x", data);
266 break;
267
268 case GE_CMD_VERTEXTYPE:
269 {
270 int len = snprintf(buffer, bufsize, "SetVertexType: ");
271 GeDescribeVertexType(op, buffer + len, bufsize - len);
272 }
273 break;
274
275 case GE_CMD_OFFSETADDR:
276 snprintf(buffer, bufsize, "OffsetAddr: %06x", data);
277 break;
278
279 case GE_CMD_REGION1:
280 {
281 int x1 = data & 0x3ff;
282 int y1 = data >> 10;
283 if (data & 0xF00000)
284 snprintf(buffer, bufsize, "Region TL: %d %d (extra %x)", x1, y1, data >> 20);
285 else
286 snprintf(buffer, bufsize, "Region TL: %d %d", x1, y1);
287 }
288 break;
289
290 case GE_CMD_REGION2:
291 {
292 int x2 = data & 0x3ff;
293 int y2 = data >> 10;
294 if (data & 0xF00000)
295 snprintf(buffer, bufsize, "Region BR: %d %d (extra %x)", x2, y2, data >> 20);
296 else
297 snprintf(buffer, bufsize, "Region BR: %d %d", x2, y2);
298 }
299 break;
300
301 case GE_CMD_DEPTHCLAMPENABLE:
302 snprintf(buffer, bufsize, "Depth clamp enable: %i", data);
303 break;
304
305 case GE_CMD_CULLFACEENABLE:
306 snprintf(buffer, bufsize, "CullFace enable: %i", data);
307 break;
308
309 case GE_CMD_TEXTUREMAPENABLE:
310 snprintf(buffer, bufsize, "Texture map enable: %i", data);
311 break;
312
313 case GE_CMD_LIGHTINGENABLE:
314 snprintf(buffer, bufsize, "Lighting enable: %i", data);
315 break;
316
317 case GE_CMD_FOGENABLE:
318 snprintf(buffer, bufsize, "Fog enable: %i", data);
319 break;
320
321 case GE_CMD_DITHERENABLE:
322 snprintf(buffer, bufsize, "Dither enable: %i", data);
323 break;
324
325 case GE_CMD_OFFSETX:
326 snprintf(buffer, bufsize, "Offset X: %i", data);
327 break;
328
329 case GE_CMD_OFFSETY:
330 snprintf(buffer, bufsize, "Offset Y: %i", data);
331 break;
332
333 case GE_CMD_TEXSCALEU:
334 snprintf(buffer, bufsize, "Texture U scale: %f", getFloat24(data));
335 break;
336
337 case GE_CMD_TEXSCALEV:
338 snprintf(buffer, bufsize, "Texture V scale: %f", getFloat24(data));
339 break;
340
341 case GE_CMD_TEXOFFSETU:
342 snprintf(buffer, bufsize, "Texture U offset: %f", getFloat24(data));
343 break;
344
345 case GE_CMD_TEXOFFSETV:
346 snprintf(buffer, bufsize, "Texture V offset: %f", getFloat24(data));
347 break;
348
349 case GE_CMD_SCISSOR1:
350 {
351 int x1 = data & 0x3ff;
352 int y1 = data >> 10;
353 if (data & 0xF00000)
354 snprintf(buffer, bufsize, "Scissor TL: %i, %i (extra %x)", x1, y1, data >> 20);
355 else
356 snprintf(buffer, bufsize, "Scissor TL: %i, %i", x1, y1);
357 }
358 break;
359 case GE_CMD_SCISSOR2:
360 {
361 int x2 = data & 0x3ff;
362 int y2 = data >> 10;
363 if (data & 0xF00000)
364 snprintf(buffer, bufsize, "Scissor BR: %i, %i (extra %x)", x2, y2, data >> 20);
365 else
366 snprintf(buffer, bufsize, "Scissor BR: %i, %i", x2, y2);
367 }
368 break;
369
370 case GE_CMD_MINZ:
371 {
372 float zMin = getFloat24(data) / 65535.f;
373 snprintf(buffer, bufsize, "MinZ: %f", zMin);
374 }
375 break;
376
377 case GE_CMD_MAXZ:
378 {
379 float zMax = getFloat24(data) / 65535.f;
380 snprintf(buffer, bufsize, "MaxZ: %f", zMax);
381 }
382 break;
383
384 case GE_CMD_FRAMEBUFPTR:
385 {
386 snprintf(buffer, bufsize, "FramebufPtr: %08x", data);
387 }
388 break;
389
390 case GE_CMD_FRAMEBUFWIDTH:
391 {
392 snprintf(buffer, bufsize, "FramebufWidth: %x, address high %02x", data & 0xFFFF, data >> 16);
393 }
394 break;
395
396 case GE_CMD_FRAMEBUFPIXFORMAT:
397 snprintf(buffer, bufsize, "FramebufPixelFormat: %i", data);
398 break;
399
400 case GE_CMD_TEXADDR0:
401 case GE_CMD_TEXADDR1:
402 case GE_CMD_TEXADDR2:
403 case GE_CMD_TEXADDR3:
404 case GE_CMD_TEXADDR4:
405 case GE_CMD_TEXADDR5:
406 case GE_CMD_TEXADDR6:
407 case GE_CMD_TEXADDR7:
408 snprintf(buffer, bufsize, "Texture address %i: %06x", cmd-GE_CMD_TEXADDR0, data);
409 break;
410
411 case GE_CMD_TEXBUFWIDTH0:
412 case GE_CMD_TEXBUFWIDTH1:
413 case GE_CMD_TEXBUFWIDTH2:
414 case GE_CMD_TEXBUFWIDTH3:
415 case GE_CMD_TEXBUFWIDTH4:
416 case GE_CMD_TEXBUFWIDTH5:
417 case GE_CMD_TEXBUFWIDTH6:
418 case GE_CMD_TEXBUFWIDTH7:
419 snprintf(buffer, bufsize, "Texture BUFWIDTH %i: %06x", cmd-GE_CMD_TEXBUFWIDTH0, data);
420 break;
421
422 case GE_CMD_CLUTADDR:
423 snprintf(buffer, bufsize, "CLUT base addr: %06x", data);
424 break;
425
426 case GE_CMD_CLUTADDRUPPER:
427 snprintf(buffer, bufsize, "CLUT addr upper %08x", data);
428 break;
429
430 case GE_CMD_LOADCLUT:
431 // This could be used to "dirty" textures with clut.
432 if (data)
433 snprintf(buffer, bufsize, "Clut load: %08x, %d bytes, %06x", gstate.getClutAddress(), (data & 0x3F) << 5, data & 0xFFFFC0);
434 else
435 snprintf(buffer, bufsize, "Clut load");
436 break;
437
438 case GE_CMD_TEXMAPMODE:
439 snprintf(buffer, bufsize, "Tex map mode: %06x", data);
440 break;
441
442 case GE_CMD_TEXSHADELS:
443 snprintf(buffer, bufsize, "Tex shade light sources: %06x", data);
444 break;
445
446 case GE_CMD_CLUTFORMAT:
447 {
448 const char *clutformats[] = {
449 "BGR 5650",
450 "ABGR 1555",
451 "ABGR 4444",
452 "ABGR 8888",
453 };
454 snprintf(buffer, bufsize, "Clut format: %06x (%s)", data, clutformats[data & 3]);
455 }
456 break;
457
458 case GE_CMD_TRANSFERSRC:
459 {
460 if (data & 0xF)
461 snprintf(buffer, bufsize, "Block transfer src: %06x (extra: %x)", data & ~0xF, data & 0xF);
462 else
463 snprintf(buffer, bufsize, "Block transfer src: %06x", data);
464 // Nothing to do, the next one prints
465 }
466 break;
467
468 case GE_CMD_TRANSFERSRCW:
469 {
470 u32 xferSrc = (gstate.transfersrc & 0x00FFFFFF) | ((data & 0xFF0000) << 8);
471 u32 xferSrcW = data & 0x3FF;
472 if (data & ~0xFF03FF)
473 snprintf(buffer, bufsize, "Block transfer src: %08x W: %i (extra %x)", xferSrc, xferSrcW, data);
474 else
475 snprintf(buffer, bufsize, "Block transfer src: %08x W: %i", xferSrc, xferSrcW);
476 break;
477 }
478
479 case GE_CMD_TRANSFERDST:
480 {
481 // Nothing to do, the next one prints
482 if (data & 0xF)
483 snprintf(buffer, bufsize, "Block transfer dst: %06x (extra: %x)", data & ~0xF, data & 0xF);
484 else
485 snprintf(buffer, bufsize, "Block transfer dst: %06x", data);
486 }
487 break;
488
489 case GE_CMD_TRANSFERDSTW:
490 {
491 u32 xferDst = (gstate.transferdst & 0x00FFFFFF) | ((data & 0xFF0000) << 8);
492 u32 xferDstW = data & 0x3FF;
493 if (data & ~0xFF03FF)
494 snprintf(buffer, bufsize, "Block transfer dest: %08x W: %i (extra %x)", xferDst, xferDstW, data);
495 else
496 snprintf(buffer, bufsize, "Block transfer dest: %08x W: %i", xferDst, xferDstW);
497 break;
498 }
499
500 case GE_CMD_TRANSFERSRCPOS:
501 {
502 u32 x = (data & 1023);
503 u32 y = ((data>>10) & 1023);
504 if (data & 0xF00000)
505 snprintf(buffer, bufsize, "Block transfer src rect TL: %i, %i (extra %x)", x, y, data >> 20);
506 else
507 snprintf(buffer, bufsize, "Block transfer src rect TL: %i, %i", x, y);
508 break;
509 }
510
511 case GE_CMD_TRANSFERDSTPOS:
512 {
513 u32 x = (data & 1023);
514 u32 y = ((data>>10) & 1023);
515 if (data & 0xF00000)
516 snprintf(buffer, bufsize, "Block transfer dest rect TL: %i, %i (extra %x)", x, y, data >> 20);
517 else
518 snprintf(buffer, bufsize, "Block transfer dest rect TL: %i, %i", x, y);
519 break;
520 }
521
522 case GE_CMD_TRANSFERSIZE:
523 {
524 u32 w = (data & 1023)+1;
525 u32 h = ((data>>10) & 1023)+1;
526 if (data & 0xF00000)
527 snprintf(buffer, bufsize, "Block transfer rect size: %i x %i (extra %x)", w, h, data >> 20);
528 else
529 snprintf(buffer, bufsize, "Block transfer rect size: %i x %i", w, h);
530 break;
531 }
532
533 case GE_CMD_TRANSFERSTART:
534 if (data & ~1)
535 snprintf(buffer, bufsize, "Block transfer start: %d (extra %x)", data & 1, data & ~1);
536 else
537 snprintf(buffer, bufsize, "Block transfer start: %d", data);
538 break;
539
540 case GE_CMD_TEXSIZE0:
541 case GE_CMD_TEXSIZE1:
542 case GE_CMD_TEXSIZE2:
543 case GE_CMD_TEXSIZE3:
544 case GE_CMD_TEXSIZE4:
545 case GE_CMD_TEXSIZE5:
546 case GE_CMD_TEXSIZE6:
547 case GE_CMD_TEXSIZE7:
548 {
549 int w = 1 << (data & 0xf);
550 int h = 1 << ((data>>8) & 0xf);
551 snprintf(buffer, bufsize, "Texture size %i: %06x, width : %d, height : %d", cmd - GE_CMD_TEXSIZE0, data, w, h);
552 }
553 break;
554
555 case GE_CMD_ZBUFPTR:
556 {
557 snprintf(buffer, bufsize, "Zbuf ptr: %06x", data);
558 }
559 break;
560
561 case GE_CMD_ZBUFWIDTH:
562 snprintf(buffer, bufsize, "Zbuf width: %06x", data);
563 break;
564
565 case GE_CMD_AMBIENTCOLOR:
566 snprintf(buffer, bufsize, "Ambient color: %06x", data);
567 break;
568
569 case GE_CMD_AMBIENTALPHA:
570 snprintf(buffer, bufsize, "Ambient alpha: %06x", data);
571 break;
572
573 case GE_CMD_MATERIALAMBIENT:
574 snprintf(buffer, bufsize, "Material ambient color: %06x", data);
575 break;
576
577 case GE_CMD_MATERIALDIFFUSE:
578 snprintf(buffer, bufsize, "Material diffuse color: %06x", data);
579 break;
580
581 case GE_CMD_MATERIALEMISSIVE:
582 snprintf(buffer, bufsize, "Material emissive color: %06x", data);
583 break;
584
585 case GE_CMD_MATERIALSPECULAR:
586 snprintf(buffer, bufsize, "Material specular color: %06x", data);
587 break;
588
589 case GE_CMD_MATERIALALPHA:
590 snprintf(buffer, bufsize, "Material alpha color: %06x", data);
591 break;
592
593 case GE_CMD_MATERIALSPECULARCOEF:
594 snprintf(buffer, bufsize, "Material specular coef: %f", getFloat24(data));
595 break;
596
597 case GE_CMD_SHADEMODE:
598 if (data & ~1)
599 snprintf(buffer, bufsize, "Shade: %06x (%s, extra %x)", data, data ? "gouraud" : "flat", data);
600 else
601 snprintf(buffer, bufsize, "Shade: %06x (%s)", data, data ? "gouraud" : "flat");
602 break;
603
604 case GE_CMD_LIGHTMODE:
605 if (data & ~1)
606 snprintf(buffer, bufsize, "Lightmode: %06x (%s, extra %x)", data, data ? "separate spec" : "single color", data);
607 else
608 snprintf(buffer, bufsize, "Lightmode: %06x (%s)", data, data ? "separate spec" : "single color");
609 break;
610
611 case GE_CMD_LIGHTTYPE0:
612 case GE_CMD_LIGHTTYPE1:
613 case GE_CMD_LIGHTTYPE2:
614 case GE_CMD_LIGHTTYPE3:
615 snprintf(buffer, bufsize, "Light %i type: %06x", cmd-GE_CMD_LIGHTTYPE0, data);
616 break;
617
618 case GE_CMD_LX0:case GE_CMD_LY0:case GE_CMD_LZ0:
619 case GE_CMD_LX1:case GE_CMD_LY1:case GE_CMD_LZ1:
620 case GE_CMD_LX2:case GE_CMD_LY2:case GE_CMD_LZ2:
621 case GE_CMD_LX3:case GE_CMD_LY3:case GE_CMD_LZ3:
622 {
623 int n = cmd - GE_CMD_LX0;
624 int l = n / 3;
625 int c = n % 3;
626 float val = getFloat24(data);
627 snprintf(buffer, bufsize, "Light %i %c pos: %f", l, c+'X', val);
628 }
629 break;
630
631 case GE_CMD_LDX0:case GE_CMD_LDY0:case GE_CMD_LDZ0:
632 case GE_CMD_LDX1:case GE_CMD_LDY1:case GE_CMD_LDZ1:
633 case GE_CMD_LDX2:case GE_CMD_LDY2:case GE_CMD_LDZ2:
634 case GE_CMD_LDX3:case GE_CMD_LDY3:case GE_CMD_LDZ3:
635 {
636 int n = cmd - GE_CMD_LDX0;
637 int l = n / 3;
638 int c = n % 3;
639 float val = getFloat24(data);
640 snprintf(buffer, bufsize, "Light %i %c dir: %f", l, c+'X', val);
641 }
642 break;
643
644 case GE_CMD_LKA0:case GE_CMD_LKB0:case GE_CMD_LKC0:
645 case GE_CMD_LKA1:case GE_CMD_LKB1:case GE_CMD_LKC1:
646 case GE_CMD_LKA2:case GE_CMD_LKB2:case GE_CMD_LKC2:
647 case GE_CMD_LKA3:case GE_CMD_LKB3:case GE_CMD_LKC3:
648 {
649 int n = cmd - GE_CMD_LKA0;
650 int l = n / 3;
651 int c = n % 3;
652 float val = getFloat24(data);
653 snprintf(buffer, bufsize, "Light %i %c att: %f", l, c+'X', val);
654 }
655 break;
656
657 case GE_CMD_LAC0:case GE_CMD_LAC1:case GE_CMD_LAC2:case GE_CMD_LAC3:
658 case GE_CMD_LDC0:case GE_CMD_LDC1:case GE_CMD_LDC2:case GE_CMD_LDC3:
659 case GE_CMD_LSC0:case GE_CMD_LSC1:case GE_CMD_LSC2:case GE_CMD_LSC3:
660 {
661 float r = (float)(data & 0xff)/255.0f;
662 float g = (float)((data>>8) & 0xff)/255.0f;
663 float b = (float)(data>>16)/255.0f;
664
665 int l = (cmd - GE_CMD_LAC0) / 3;
666 int t = (cmd - GE_CMD_LAC0) % 3;
667 snprintf(buffer, bufsize, "Light %i color %i: %f %f %f", l, t, r, g, b);
668 }
669 break;
670
671 case GE_CMD_VIEWPORTXSCALE:
672 case GE_CMD_VIEWPORTYSCALE:
673 case GE_CMD_VIEWPORTXCENTER:
674 case GE_CMD_VIEWPORTYCENTER:
675 snprintf(buffer, bufsize, "Viewport param %i: %f", cmd-GE_CMD_VIEWPORTXSCALE, getFloat24(data));
676 break;
677 case GE_CMD_VIEWPORTZSCALE:
678 {
679 float zScale = getFloat24(data) / 65535.f;
680 snprintf(buffer, bufsize, "Viewport Z scale: %f", zScale);
681 }
682 break;
683 case GE_CMD_VIEWPORTZCENTER:
684 {
685 float zOff = getFloat24(data) / 65535.f;
686 snprintf(buffer, bufsize, "Viewport Z pos: %f", zOff);
687 }
688 break;
689
690 case GE_CMD_LIGHTENABLE0:
691 case GE_CMD_LIGHTENABLE1:
692 case GE_CMD_LIGHTENABLE2:
693 case GE_CMD_LIGHTENABLE3:
694 snprintf(buffer, bufsize, "Light %i enable: %d", cmd-GE_CMD_LIGHTENABLE0, data);
695 break;
696
697 case GE_CMD_CULL:
698 snprintf(buffer, bufsize, "Cull: %06x", data);
699 break;
700
701 case GE_CMD_PATCHDIVISION:
702 {
703 int patch_div_s = data & 0xFF;
704 int patch_div_t = (data >> 8) & 0xFF;
705 if (data & 0xFF0000)
706 snprintf(buffer, bufsize, "Patch subdivision: %i x %i (extra %x)", patch_div_s, patch_div_t, data & 0xFF0000);
707 else
708 snprintf(buffer, bufsize, "Patch subdivision: %i x %i", patch_div_s, patch_div_t);
709 }
710 break;
711
712 case GE_CMD_PATCHPRIMITIVE:
713 snprintf(buffer, bufsize, "Patch Primitive: %d", data);
714 break;
715
716 case GE_CMD_PATCHFACING:
717 snprintf(buffer, bufsize, "Patch Facing: %d", data);
718 break;
719
720 case GE_CMD_REVERSENORMAL:
721 snprintf(buffer, bufsize, "Reverse normal: %d", data);
722 break;
723
724 case GE_CMD_MATERIALUPDATE:
725 snprintf(buffer, bufsize, "Material update: %d", data);
726 break;
727
728
729 //////////////////////////////////////////////////////////////////
730 // CLEARING
731 //////////////////////////////////////////////////////////////////
732 case GE_CMD_CLEARMODE:
733 {
734 const char *clearModes[] = {
735 "on",
736 "on, color",
737 "on, alpha/stencil",
738 "on, color, alpha/stencil",
739 "on, depth",
740 "on, color, depth",
741 "on, alpha/stencil, depth",
742 "on, color, alpha/stencil, depth",
743 };
744
745 const char *mode;
746 if (data & 1)
747 mode = clearModes[(data >> 8) & 7];
748 else
749 mode = "off";
750 snprintf(buffer, bufsize, "Clear mode: %06x (%s)", data, mode);
751 }
752 break;
753
754
755 //////////////////////////////////////////////////////////////////
756 // ALPHA BLENDING
757 //////////////////////////////////////////////////////////////////
758 case GE_CMD_ALPHABLENDENABLE:
759 snprintf(buffer, bufsize, "Alpha blend enable: %d", data);
760 break;
761
762 case GE_CMD_BLENDMODE:
763 {
764 const char *blendModes[] = {
765 "add",
766 "subtract",
767 "reverse subtract",
768 "min",
769 "max",
770 "abs subtract",
771 "unsupported1",
772 "unsupported2",
773 };
774 const char *blendFactorsA[16] = {
775 "dst",
776 "1.0 - dst",
777 "src.a",
778 "1.0 - src.a",
779 "dst.a",
780 "1.0 - dst.a",
781 "2.0 * src.a",
782 "1.0 - 2.0 * src.a",
783 "2.0 * dst.a",
784 "1.0 - 2.0 * dst.a",
785 "fixed",
786 "fixed2",
787 "fixed3",
788 "fixed4",
789 "fixed5",
790 };
791 const char *blendFactorsB[16] = {
792 "src",
793 "1.0 - src",
794 "src.a",
795 "1.0 - src.a",
796 "dst.a",
797 "1.0 - dst.a",
798 "2.0 * src.a",
799 "1.0 - 2.0 * src.a",
800 "2.0 * dst.a",
801 "1.0 - 2.0 * dst.a",
802 "fixed",
803 "fixed2",
804 "fixed3",
805 "fixed4",
806 "fixed5",
807 };
808
809 const char *blendFactorA = blendFactorsA[(data >> 0) & 0xF];
810 const char *blendFactorB = blendFactorsB[(data >> 4) & 0xF];
811 const char *blendMode = blendModes[(data >> 8) & 0x7];
812
813 if (data & ~0xFF0007FF)
814 snprintf(buffer, bufsize, "Blend mode: %s %s, %s (extra: %06x)", blendMode, blendFactorA, blendFactorB, data & ~0xFF0007FF);
815 else
816 snprintf(buffer, bufsize, "Blend mode: %s %s, %s", blendMode, blendFactorA, blendFactorB);
817 }
818 break;
819
820 case GE_CMD_BLENDFIXEDA:
821 snprintf(buffer, bufsize, "Blend fix A: %06x", data);
822 break;
823
824 case GE_CMD_BLENDFIXEDB:
825 snprintf(buffer, bufsize, "Blend fix B: %06x", data);
826 break;
827
828 case GE_CMD_ALPHATESTENABLE:
829 snprintf(buffer, bufsize, "Alpha test enable: %d", data);
830 break;
831
832 case GE_CMD_ALPHATEST:
833 {
834 const char *alphaTestFuncs[] = { " NEVER ", " ALWAYS ", " == ", " != ", " < ", " <= ", " > ", " >= " };
835 snprintf(buffer, bufsize, "Alpha test settings: %06x ((c & %02x)%s%02x)", data, (data >> 16) & 0xFF, alphaTestFuncs[data & 7], (data >> 8) & 0xFF);
836 }
837 break;
838
839 case GE_CMD_ANTIALIASENABLE:
840 snprintf(buffer, bufsize, "Antialias enable: %d", data);
841 break;
842
843 case GE_CMD_PATCHCULLENABLE:
844 snprintf(buffer, bufsize, "Patch cull enable: %d", data);
845 break;
846
847 case GE_CMD_COLORTESTENABLE:
848 snprintf(buffer, bufsize, "Color test enable: %d", data);
849 break;
850
851 case GE_CMD_LOGICOPENABLE:
852 snprintf(buffer, bufsize, "Logic op enable: %d", data);
853 break;
854
855 case GE_CMD_TEXFUNC:
856 {
857 const char *texfuncs[] = {
858 "modulate",
859 "decal",
860 "blend",
861 "replace",
862 "add",
863 "unsupported1",
864 "unsupported2",
865 "unsupported3",
866 };
867 if (data & ~0x10107)
868 snprintf(buffer, bufsize, "TexFunc %i %s %s%s (extra %x)", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7], data & 0x10000 ? " color double" : "", data);
869 else
870 snprintf(buffer, bufsize, "TexFunc %i %s %s%s", data & 7, data & 0x100 ? "RGBA" : "RGB", texfuncs[data & 7], data & 0x10000 ? " color double" : "");
871 }
872 break;
873
874 case GE_CMD_TEXFILTER:
875 {
876 int min = data & 7;
877 int mag = (data >> 8) & 1;
878 if (data & ~0x107)
879 snprintf(buffer, bufsize, "TexFilter min: %i mag: %i (extra %x)", min, mag, data);
880 else
881 snprintf(buffer, bufsize, "TexFilter min: %i mag: %i", min, mag);
882 }
883 break;
884
885 case GE_CMD_TEXENVCOLOR:
886 snprintf(buffer, bufsize, "TexEnvColor %06x", data);
887 break;
888
889 case GE_CMD_TEXMODE:
890 snprintf(buffer, bufsize, "TexMode %06x (%s, %d levels, %s)", data, data & 1 ? "swizzle" : "no swizzle", (data >> 16) & 7, (data >> 8) & 1 ? "separate cluts" : "shared clut");
891 break;
892
893 case GE_CMD_TEXFORMAT:
894 {
895 const char *texformats[] = {
896 "5650",
897 "5551",
898 "4444",
899 "8888",
900 "CLUT4",
901 "CLUT8",
902 "CLUT16",
903 "CLUT32",
904 "DXT1",
905 "DXT3",
906 "DXT5",
907 "unsupported1",
908 "unsupported2",
909 "unsupported3",
910 "unsupported4",
911 "unsupported5",
912 };
913 snprintf(buffer, bufsize, "TexFormat %06x (%s)", data, texformats[data & 0xF]);
914 }
915 break;
916
917 case GE_CMD_TEXFLUSH:
918 if (data)
919 snprintf(buffer, bufsize, "TexFlush: %x", data);
920 else
921 snprintf(buffer, bufsize, "TexFlush");
922 break;
923
924 case GE_CMD_TEXSYNC:
925 if (data)
926 snprintf(buffer, bufsize, "TexSync: %x", data);
927 else
928 snprintf(buffer, bufsize, "TexSync");
929 break;
930
931 case GE_CMD_TEXWRAP:
932 if (data & ~0x0101)
933 snprintf(buffer, bufsize, "TexWrap %s s, %s t (extra %x)", data & 1 ? "clamp" : "wrap", data & 0x100 ? "clamp" : "wrap", data);
934 else
935 snprintf(buffer, bufsize, "TexWrap %s s, %s t", data & 1 ? "clamp" : "wrap", data & 0x100 ? "clamp" : "wrap");
936 break;
937
938 case GE_CMD_TEXLEVEL:
939 if (data & ~0xFF0003)
940 snprintf(buffer, bufsize, "TexLevel mode: %i Offset: %i (extra %x)", data&3, data >> 16, data);
941 else
942 snprintf(buffer, bufsize, "TexLevel mode: %i Offset: %i", data&3, data >> 16);
943 break;
944
945 case GE_CMD_FOG1:
946 snprintf(buffer, bufsize, "Fog1 %f", getFloat24(data));
947 break;
948
949 case GE_CMD_FOG2:
950 snprintf(buffer, bufsize, "Fog2 %f", getFloat24(data));
951 break;
952
953 case GE_CMD_FOGCOLOR:
954 snprintf(buffer, bufsize, "FogColor %06x", data);
955 break;
956
957 case GE_CMD_TEXLODSLOPE:
958 snprintf(buffer, bufsize, "TexLodSlope %06x", data);
959 break;
960
961 //////////////////////////////////////////////////////////////////
962 // Z/STENCIL TESTING
963 //////////////////////////////////////////////////////////////////
964
965 case GE_CMD_ZTESTENABLE:
966 if (data & ~1)
967 snprintf(buffer, bufsize, "Z test enable: %d (extra %x)", data & 1, data);
968 else
969 snprintf(buffer, bufsize, "Z test enable: %d", data & 1);
970 break;
971
972 case GE_CMD_STENCILOP:
973 {
974 const char *stencilOps[] = { "KEEP", "ZERO", "REPLACE", "INVERT", "INCREMENT", "DECREMENT", "unsupported1", "unsupported2" };
975 snprintf(buffer, bufsize, "Stencil op: fail=%s, pass/depthfail=%s, pass=%s", stencilOps[data & 7], stencilOps[(data >> 8) & 7], stencilOps[(data >> 16) & 7]);
976 }
977 break;
978
979 case GE_CMD_STENCILTEST:
980 {
981 const char *zTestFuncs[] = { "NEVER", "ALWAYS", " == ", " != ", " < ", " <= ", " > ", " >= " };
982 snprintf(buffer, bufsize, "Stencil test: %06x (%02x %s (c & %02x))", data, (data >> 8) & 0xFF, zTestFuncs[data & 7], (data >> 16) & 0xFF);
983 }
984 break;
985
986 case GE_CMD_STENCILTESTENABLE:
987 snprintf(buffer, bufsize, "Stencil test enable: %d", data);
988 break;
989
990 case GE_CMD_ZTEST:
991 {
992 const char *zTestFuncs[] = { "NEVER", "ALWAYS", " == ", " != ", " < ", " <= ", " > ", " >= " };
993 snprintf(buffer, bufsize, "Z test mode: %i (%s)", data, zTestFuncs[data & 7]);
994 }
995 break;
996
997 case GE_CMD_MORPHWEIGHT0:
998 case GE_CMD_MORPHWEIGHT1:
999 case GE_CMD_MORPHWEIGHT2:
1000 case GE_CMD_MORPHWEIGHT3:
1001 case GE_CMD_MORPHWEIGHT4:
1002 case GE_CMD_MORPHWEIGHT5:
1003 case GE_CMD_MORPHWEIGHT6:
1004 case GE_CMD_MORPHWEIGHT7:
1005 {
1006 int index = cmd - GE_CMD_MORPHWEIGHT0;
1007 float weight = getFloat24(data);
1008 snprintf(buffer, bufsize, "MorphWeight %i = %f", index, weight);
1009 }
1010 break;
1011
1012 case GE_CMD_DITH0:
1013 case GE_CMD_DITH1:
1014 case GE_CMD_DITH2:
1015 case GE_CMD_DITH3:
1016 snprintf(buffer, bufsize, "DitherMatrix %i = %06x",cmd-GE_CMD_DITH0,data);
1017 break;
1018
1019 case GE_CMD_LOGICOP:
1020 {
1021 const char *logicOps[] = {
1022 "clear",
1023 "and",
1024 "reverse and",
1025 "copy",
1026 "inverted and",
1027 "noop",
1028 "xor",
1029 "or",
1030 "negated or",
1031 "equivalence",
1032 "inverted",
1033 "reverse or",
1034 "inverted copy",
1035 "inverted or",
1036 "negated and",
1037 "set",
1038 };
1039 snprintf(buffer, bufsize, "LogicOp: %06x (%s)", data, logicOps[data & 0xF]);
1040 }
1041 break;
1042
1043 case GE_CMD_ZWRITEDISABLE:
1044 snprintf(buffer, bufsize, "ZMask: %06x", data);
1045 break;
1046
1047 case GE_CMD_COLORTEST:
1048 {
1049 const char *colorTests[] = {"NEVER", "ALWAYS", " == ", " != "};
1050 snprintf(buffer, bufsize, "ColorTest: %06x (ref%s(c & cmask))", data, colorTests[data & 3]);
1051 }
1052 break;
1053
1054 case GE_CMD_COLORREF:
1055 snprintf(buffer, bufsize, "ColorRef: %06x", data);
1056 break;
1057
1058 case GE_CMD_COLORTESTMASK:
1059 snprintf(buffer, bufsize, "ColorTestMask: %06x", data);
1060 break;
1061
1062 case GE_CMD_MASKRGB:
1063 snprintf(buffer, bufsize, "MaskRGB: %06x", data);
1064 break;
1065
1066 case GE_CMD_MASKALPHA:
1067 snprintf(buffer, bufsize, "MaskAlpha: %06x", data);
1068 break;
1069
1070 case GE_CMD_WORLDMATRIXNUMBER:
1071 if (data & ~0xF)
1072 snprintf(buffer, bufsize, "World # %i (extra %x)", data & 0xF, data);
1073 else
1074 snprintf(buffer, bufsize, "World # %i", data & 0xF);
1075 break;
1076
1077 case GE_CMD_WORLDMATRIXDATA:
1078 snprintf(buffer, bufsize, "World data # %f", getFloat24(data));
1079 break;
1080
1081 case GE_CMD_VIEWMATRIXNUMBER:
1082 if (data & ~0xF)
1083 snprintf(buffer, bufsize, "VIEW # %i (extra %x)", data & 0xF, data);
1084 else
1085 snprintf(buffer, bufsize, "VIEW # %i", data & 0xF);
1086 break;
1087
1088 case GE_CMD_VIEWMATRIXDATA:
1089 snprintf(buffer, bufsize, "VIEW data # %f", getFloat24(data));
1090 break;
1091
1092 case GE_CMD_PROJMATRIXNUMBER:
1093 if (data & ~0xF)
1094 snprintf(buffer, bufsize, "PROJECTION # %i (extra %x)", data & 0xF, data);
1095 else
1096 snprintf(buffer, bufsize, "PROJECTION # %i", data & 0xF);
1097 break;
1098
1099 case GE_CMD_PROJMATRIXDATA:
1100 snprintf(buffer, bufsize, "PROJECTION matrix data # %f", getFloat24(data));
1101 break;
1102
1103 case GE_CMD_TGENMATRIXNUMBER:
1104 if (data & ~0xF)
1105 snprintf(buffer, bufsize, "TGEN # %i (extra %x)", data & 0xF, data);
1106 else
1107 snprintf(buffer, bufsize, "TGEN # %i", data & 0xF);
1108 break;
1109
1110 case GE_CMD_TGENMATRIXDATA:
1111 snprintf(buffer, bufsize, "TGEN data # %f", getFloat24(data));
1112 break;
1113
1114 case GE_CMD_BONEMATRIXNUMBER:
1115 if (data & ~0x7F)
1116 snprintf(buffer, bufsize, "BONE #%i (extra %x)", data & 0x7F, data);
1117 else
1118 snprintf(buffer, bufsize, "BONE #%i", data & 0x7F);
1119 break;
1120
1121 case GE_CMD_BONEMATRIXDATA:
1122 snprintf(buffer, bufsize, "BONE data #%i %f", gstate.boneMatrixNumber & 0x7f, getFloat24(data));
1123 break;
1124
1125 default:
1126 snprintf(buffer, bufsize, "Unknown: %08x", op);
1127 break;
1128 }
1129 }
1130
1131