r300: more r300/r500 unification
[mesa.git] / src / mesa / drivers / dri / r300 / r500_fragprog.c
1 /*
2 * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 #include "r500_fragprog.h"
29
30 #include "radeon_nqssadce.h"
31 #include "radeon_program_alu.h"
32 #include "r300_fragprog.h"
33
34
35 static void reset_srcreg(struct prog_src_register* reg)
36 {
37 _mesa_bzero(reg, sizeof(*reg));
38 reg->Swizzle = SWIZZLE_NOOP;
39 }
40
41 static struct prog_src_register shadow_ambient(struct gl_program *program, int tmu)
42 {
43 gl_state_index fail_value_tokens[STATE_LENGTH] = {
44 STATE_INTERNAL, STATE_SHADOW_AMBIENT, 0, 0, 0
45 };
46 struct prog_src_register reg = { 0, };
47
48 fail_value_tokens[2] = tmu;
49 reg.File = PROGRAM_STATE_VAR;
50 reg.Index = _mesa_add_state_reference(program->Parameters, fail_value_tokens);
51 reg.Swizzle = SWIZZLE_WWWW;
52 return reg;
53 }
54
55 /**
56 * Transform TEX, TXP, TXB, and KIL instructions in the following way:
57 * - premultiply texture coordinates for RECT
58 * - extract operand swizzles
59 * - introduce a temporary register when write masks are needed
60 *
61 */
62 static GLboolean transform_TEX(
63 struct radeon_transform_context *t,
64 struct prog_instruction* orig_inst, void* data)
65 {
66 struct r300_fragment_program_compiler *compiler =
67 (struct r300_fragment_program_compiler*)data;
68 struct prog_instruction inst = *orig_inst;
69 struct prog_instruction* tgt;
70 GLboolean destredirect = GL_FALSE;
71
72 if (inst.Opcode != OPCODE_TEX &&
73 inst.Opcode != OPCODE_TXB &&
74 inst.Opcode != OPCODE_TXP &&
75 inst.Opcode != OPCODE_KIL)
76 return GL_FALSE;
77
78 /* ARB_shadow & EXT_shadow_funcs */
79 if (inst.Opcode != OPCODE_KIL &&
80 t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) {
81 GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func;
82
83 if (comparefunc == GL_NEVER || comparefunc == GL_ALWAYS) {
84 tgt = radeonAppendInstructions(t->Program, 1);
85
86 tgt->Opcode = OPCODE_MOV;
87 tgt->DstReg = inst.DstReg;
88 if (comparefunc == GL_ALWAYS) {
89 tgt->SrcReg[0].File = PROGRAM_BUILTIN;
90 tgt->SrcReg[0].Swizzle = SWIZZLE_1111;
91 } else {
92 tgt->SrcReg[0] = shadow_ambient(t->Program, inst.TexSrcUnit);
93 }
94 return GL_TRUE;
95 }
96
97 inst.DstReg.File = PROGRAM_TEMPORARY;
98 inst.DstReg.Index = radeonFindFreeTemporary(t);
99 inst.DstReg.WriteMask = WRITEMASK_XYZW;
100 } else if (inst.Opcode != OPCODE_KIL && inst.DstReg.File != PROGRAM_TEMPORARY) {
101 int tempreg = radeonFindFreeTemporary(t);
102
103 inst.DstReg.File = PROGRAM_TEMPORARY;
104 inst.DstReg.Index = tempreg;
105 inst.DstReg.WriteMask = WRITEMASK_XYZW;
106 destredirect = GL_TRUE;
107 }
108
109 if (inst.SrcReg[0].File != PROGRAM_TEMPORARY && inst.SrcReg[0].File != PROGRAM_INPUT) {
110 int tmpreg = radeonFindFreeTemporary(t);
111 tgt = radeonAppendInstructions(t->Program, 1);
112 tgt->Opcode = OPCODE_MOV;
113 tgt->DstReg.File = PROGRAM_TEMPORARY;
114 tgt->DstReg.Index = tmpreg;
115 tgt->SrcReg[0] = inst.SrcReg[0];
116
117 reset_srcreg(&inst.SrcReg[0]);
118 inst.SrcReg[0].File = PROGRAM_TEMPORARY;
119 inst.SrcReg[0].Index = tmpreg;
120 }
121
122 tgt = radeonAppendInstructions(t->Program, 1);
123 _mesa_copy_instructions(tgt, &inst, 1);
124
125 if (inst.Opcode != OPCODE_KIL &&
126 t->Program->ShadowSamplers & (1 << inst.TexSrcUnit)) {
127 GLuint comparefunc = GL_NEVER + compiler->fp->state.unit[inst.TexSrcUnit].texture_compare_func;
128 GLuint depthmode = compiler->fp->state.unit[inst.TexSrcUnit].depth_texture_mode;
129 int rcptemp = radeonFindFreeTemporary(t);
130 int pass, fail;
131
132 tgt = radeonAppendInstructions(t->Program, 3);
133
134 tgt[0].Opcode = OPCODE_RCP;
135 tgt[0].DstReg.File = PROGRAM_TEMPORARY;
136 tgt[0].DstReg.Index = rcptemp;
137 tgt[0].DstReg.WriteMask = WRITEMASK_W;
138 tgt[0].SrcReg[0] = inst.SrcReg[0];
139 tgt[0].SrcReg[0].Swizzle = SWIZZLE_WWWW;
140
141 tgt[1].Opcode = OPCODE_MAD;
142 tgt[1].DstReg = inst.DstReg;
143 tgt[1].DstReg.WriteMask = orig_inst->DstReg.WriteMask;
144 tgt[1].SrcReg[0] = inst.SrcReg[0];
145 tgt[1].SrcReg[0].Swizzle = SWIZZLE_ZZZZ;
146 tgt[1].SrcReg[1].File = PROGRAM_TEMPORARY;
147 tgt[1].SrcReg[1].Index = rcptemp;
148 tgt[1].SrcReg[1].Swizzle = SWIZZLE_WWWW;
149 tgt[1].SrcReg[2].File = PROGRAM_TEMPORARY;
150 tgt[1].SrcReg[2].Index = inst.DstReg.Index;
151 if (depthmode == 0) /* GL_LUMINANCE */
152 tgt[1].SrcReg[2].Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z);
153 else if (depthmode == 2) /* GL_ALPHA */
154 tgt[1].SrcReg[2].Swizzle = SWIZZLE_WWWW;
155
156 /* Recall that SrcReg[0] is tex, SrcReg[2] is r and:
157 * r < tex <=> -tex+r < 0
158 * r >= tex <=> not (-tex+r < 0 */
159 if (comparefunc == GL_LESS || comparefunc == GL_GEQUAL)
160 tgt[1].SrcReg[2].NegateBase = tgt[0].SrcReg[2].NegateBase ^ NEGATE_XYZW;
161 else
162 tgt[1].SrcReg[0].NegateBase = tgt[0].SrcReg[0].NegateBase ^ NEGATE_XYZW;
163
164 tgt[2].Opcode = OPCODE_CMP;
165 tgt[2].DstReg = orig_inst->DstReg;
166 tgt[2].SrcReg[0].File = PROGRAM_TEMPORARY;
167 tgt[2].SrcReg[0].Index = tgt[1].DstReg.Index;
168
169 if (comparefunc == GL_LESS || comparefunc == GL_GREATER) {
170 pass = 1;
171 fail = 2;
172 } else {
173 pass = 2;
174 fail = 1;
175 }
176
177 tgt[2].SrcReg[pass].File = PROGRAM_BUILTIN;
178 tgt[2].SrcReg[pass].Swizzle = SWIZZLE_1111;
179 tgt[2].SrcReg[fail] = shadow_ambient(t->Program, inst.TexSrcUnit);
180 } else if (destredirect) {
181 tgt = radeonAppendInstructions(t->Program, 1);
182
183 tgt->Opcode = OPCODE_MOV;
184 tgt->DstReg = orig_inst->DstReg;
185 tgt->SrcReg[0].File = PROGRAM_TEMPORARY;
186 tgt->SrcReg[0].Index = inst.DstReg.Index;
187 }
188
189 return GL_TRUE;
190 }
191
192
193 static void update_params(GLcontext *ctx, struct gl_fragment_program *fp)
194 {
195 /* Ask Mesa nicely to fill in ParameterValues for us */
196 if (fp->Base.Parameters)
197 _mesa_load_state_parameters(ctx, fp->Base.Parameters);
198 }
199
200
201 static void nqssadce_init(struct nqssadce_state* s)
202 {
203 s->Outputs[FRAG_RESULT_COLOR].Sourced = WRITEMASK_XYZW;
204 s->Outputs[FRAG_RESULT_DEPTH].Sourced = WRITEMASK_W;
205 }
206
207 GLboolean r500FPIsNativeSwizzle(GLuint opcode, struct prog_src_register reg)
208 {
209 GLuint relevant;
210 int i;
211
212 if (opcode == OPCODE_TEX ||
213 opcode == OPCODE_TXB ||
214 opcode == OPCODE_TXP ||
215 opcode == OPCODE_KIL) {
216 if (reg.Abs)
217 return GL_FALSE;
218
219 if (reg.NegateAbs)
220 reg.NegateBase ^= 15;
221
222 if (opcode == OPCODE_KIL) {
223 if (reg.Swizzle != SWIZZLE_NOOP)
224 return GL_FALSE;
225 } else {
226 for(i = 0; i < 4; ++i) {
227 GLuint swz = GET_SWZ(reg.Swizzle, i);
228 if (swz == SWIZZLE_NIL) {
229 reg.NegateBase &= ~(1 << i);
230 continue;
231 }
232 if (swz >= 4)
233 return GL_FALSE;
234 }
235 }
236
237 if (reg.NegateBase)
238 return GL_FALSE;
239
240 return GL_TRUE;
241 } else if (opcode == OPCODE_DDX || opcode == OPCODE_DDY) {
242 /* DDX/MDH and DDY/MDV explicitly ignore incoming swizzles;
243 * if it doesn't fit perfectly into a .xyzw case... */
244 if (reg.Swizzle == SWIZZLE_NOOP && !reg.Abs
245 && !reg.NegateBase && !reg.NegateAbs)
246 return GL_TRUE;
247
248 return GL_FALSE;
249 } else {
250 /* ALU instructions support almost everything */
251 if (reg.Abs)
252 return GL_TRUE;
253
254 relevant = 0;
255 for(i = 0; i < 3; ++i) {
256 GLuint swz = GET_SWZ(reg.Swizzle, i);
257 if (swz != SWIZZLE_NIL && swz != SWIZZLE_ZERO)
258 relevant |= 1 << i;
259 }
260 if ((reg.NegateBase & relevant) && ((reg.NegateBase & relevant) != relevant))
261 return GL_FALSE;
262
263 return GL_TRUE;
264 }
265 }
266
267 /**
268 * Implement a MOV with a potentially non-native swizzle.
269 *
270 * The only thing we *cannot* do in an ALU instruction is per-component
271 * negation. Therefore, we split the MOV into two instructions when necessary.
272 */
273 void r500FPBuildSwizzle(struct nqssadce_state *s, struct prog_dst_register dst, struct prog_src_register src)
274 {
275 struct prog_instruction *inst;
276 GLuint negatebase[2] = { 0, 0 };
277 int i;
278
279 for(i = 0; i < 4; ++i) {
280 GLuint swz = GET_SWZ(src.Swizzle, i);
281 if (swz == SWIZZLE_NIL)
282 continue;
283 negatebase[GET_BIT(src.NegateBase, i)] |= 1 << i;
284 }
285
286 _mesa_insert_instructions(s->Program, s->IP, (negatebase[0] ? 1 : 0) + (negatebase[1] ? 1 : 0));
287 inst = s->Program->Instructions + s->IP;
288
289 for(i = 0; i <= 1; ++i) {
290 if (!negatebase[i])
291 continue;
292
293 inst->Opcode = OPCODE_MOV;
294 inst->DstReg = dst;
295 inst->DstReg.WriteMask = negatebase[i];
296 inst->SrcReg[0] = src;
297 inst++;
298 s->IP++;
299 }
300 }
301
302 static GLuint build_dtm(GLuint depthmode)
303 {
304 switch(depthmode) {
305 default:
306 case GL_LUMINANCE: return 0;
307 case GL_INTENSITY: return 1;
308 case GL_ALPHA: return 2;
309 }
310 }
311
312 static GLuint build_func(GLuint comparefunc)
313 {
314 return comparefunc - GL_NEVER;
315 }
316
317
318 /**
319 * Collect all external state that is relevant for compiling the given
320 * fragment program.
321 */
322 static void build_state(
323 r300ContextPtr r300,
324 struct r300_fragment_program *fp,
325 struct r300_fragment_program_external_state *state)
326 {
327 int unit;
328
329 _mesa_bzero(state, sizeof(*state));
330
331 for(unit = 0; unit < 16; ++unit) {
332 if (fp->Base.Base.ShadowSamplers & (1 << unit)) {
333 struct gl_texture_object* tex = r300->radeon.glCtx->Texture.Unit[unit]._Current;
334
335 state->unit[unit].depth_texture_mode = build_dtm(tex->DepthMode);
336 state->unit[unit].texture_compare_func = build_func(tex->CompareFunc);
337 }
338 }
339 }
340
341 void r500TranslateFragmentShader(GLcontext *ctx, struct gl_fragment_program *fp)
342 {
343 r300ContextPtr r300 = R300_CONTEXT(ctx);
344 struct r300_fragment_program *r300_fp = (struct r300_fragment_program *)fp;
345 struct r300_fragment_program_external_state state;
346
347 build_state(r300, r300_fp, &state);
348 if (_mesa_memcmp(&r300_fp->state, &state, sizeof(state))) {
349 /* TODO: cache compiled programs */
350 r300_fp->translated = GL_FALSE;
351 _mesa_memcpy(&r300_fp->state, &state, sizeof(state));
352 }
353
354 if (!r300_fp->translated) {
355 struct r300_fragment_program_compiler compiler;
356
357 compiler.r300 = r300;
358 compiler.fp = r300_fp;
359 compiler.code = &r300_fp->code;
360 compiler.program = _mesa_clone_program(ctx, &fp->Base);
361
362 if (RADEON_DEBUG & DEBUG_PIXEL) {
363 _mesa_printf("Compiler: Initial program:\n");
364 _mesa_print_program(compiler.program);
365 }
366
367 insert_WPOS_trailer(&compiler);
368
369 struct radeon_program_transformation transformations[] = {
370 { &transform_TEX, &compiler },
371 { &radeonTransformALU, 0 },
372 { &radeonTransformDeriv, 0 },
373 { &radeonTransformTrigScale, 0 }
374 };
375 radeonLocalTransform(ctx, compiler.program, 4, transformations);
376
377 if (RADEON_DEBUG & DEBUG_PIXEL) {
378 _mesa_printf("Compiler: after native rewrite:\n");
379 _mesa_print_program(compiler.program);
380 }
381
382 struct radeon_nqssadce_descr nqssadce = {
383 .Init = &nqssadce_init,
384 .IsNativeSwizzle = &r500FPIsNativeSwizzle,
385 .BuildSwizzle = &r500FPBuildSwizzle,
386 .RewriteDepthOut = GL_TRUE
387 };
388 radeonNqssaDce(ctx, compiler.program, &nqssadce);
389
390 if (RADEON_DEBUG & DEBUG_PIXEL) {
391 _mesa_printf("Compiler: after NqSSA-DCE:\n");
392 _mesa_print_program(compiler.program);
393 }
394
395 if (!r300->vtbl.FragmentProgramEmit(&compiler))
396 r300_fp->error = GL_TRUE;
397
398 /* Subtle: Rescue any parameters that have been added during transformations */
399 _mesa_free_parameter_list(fp->Base.Parameters);
400 fp->Base.Parameters = compiler.program->Parameters;
401 compiler.program->Parameters = 0;
402
403 _mesa_reference_program(ctx, &compiler.program, NULL);
404
405 r300_fp->translated = GL_TRUE;
406
407 r300UpdateStateParameters(ctx, _NEW_PROGRAM);
408
409 if (r300_fp->error || (RADEON_DEBUG & DEBUG_PIXEL))
410 r300->vtbl.FragmentProgramDump(&r300_fp->code);
411 }
412
413 update_params(ctx, fp);
414
415 }
416
417 static char *toswiz(int swiz_val) {
418 switch(swiz_val) {
419 case 0: return "R";
420 case 1: return "G";
421 case 2: return "B";
422 case 3: return "A";
423 case 4: return "0";
424 case 5: return "1/2";
425 case 6: return "1";
426 case 7: return "U";
427 }
428 return NULL;
429 }
430
431 static char *toop(int op_val)
432 {
433 char *str = NULL;
434 switch (op_val) {
435 case 0: str = "MAD"; break;
436 case 1: str = "DP3"; break;
437 case 2: str = "DP4"; break;
438 case 3: str = "D2A"; break;
439 case 4: str = "MIN"; break;
440 case 5: str = "MAX"; break;
441 case 6: str = "Reserved"; break;
442 case 7: str = "CND"; break;
443 case 8: str = "CMP"; break;
444 case 9: str = "FRC"; break;
445 case 10: str = "SOP"; break;
446 case 11: str = "MDH"; break;
447 case 12: str = "MDV"; break;
448 }
449 return str;
450 }
451
452 static char *to_alpha_op(int op_val)
453 {
454 char *str = NULL;
455 switch (op_val) {
456 case 0: str = "MAD"; break;
457 case 1: str = "DP"; break;
458 case 2: str = "MIN"; break;
459 case 3: str = "MAX"; break;
460 case 4: str = "Reserved"; break;
461 case 5: str = "CND"; break;
462 case 6: str = "CMP"; break;
463 case 7: str = "FRC"; break;
464 case 8: str = "EX2"; break;
465 case 9: str = "LN2"; break;
466 case 10: str = "RCP"; break;
467 case 11: str = "RSQ"; break;
468 case 12: str = "SIN"; break;
469 case 13: str = "COS"; break;
470 case 14: str = "MDH"; break;
471 case 15: str = "MDV"; break;
472 }
473 return str;
474 }
475
476 static char *to_mask(int val)
477 {
478 char *str = NULL;
479 switch(val) {
480 case 0: str = "NONE"; break;
481 case 1: str = "R"; break;
482 case 2: str = "G"; break;
483 case 3: str = "RG"; break;
484 case 4: str = "B"; break;
485 case 5: str = "RB"; break;
486 case 6: str = "GB"; break;
487 case 7: str = "RGB"; break;
488 case 8: str = "A"; break;
489 case 9: str = "AR"; break;
490 case 10: str = "AG"; break;
491 case 11: str = "ARG"; break;
492 case 12: str = "AB"; break;
493 case 13: str = "ARB"; break;
494 case 14: str = "AGB"; break;
495 case 15: str = "ARGB"; break;
496 }
497 return str;
498 }
499
500 static char *to_texop(int val)
501 {
502 switch(val) {
503 case 0: return "NOP";
504 case 1: return "LD";
505 case 2: return "TEXKILL";
506 case 3: return "PROJ";
507 case 4: return "LODBIAS";
508 case 5: return "LOD";
509 case 6: return "DXDY";
510 }
511 return NULL;
512 }
513
514 void r500FragmentProgramDump(union rX00_fragment_program_code *c)
515 {
516 struct r500_fragment_program_code *code = &c->r500;
517 fprintf(stderr, "R500 Fragment Program:\n--------\n");
518
519 int n;
520 uint32_t inst;
521 uint32_t inst0;
522 char *str = NULL;
523
524 if (code->const_nr) {
525 fprintf(stderr, "--------\nConstants:\n");
526 for (n = 0; n < code->const_nr; n++) {
527 fprintf(stderr, "Constant %d: %i[%i]\n", n,
528 code->constant[n].File, code->constant[n].Index);
529 }
530 fprintf(stderr, "--------\n");
531 }
532
533 for (n = 0; n < code->inst_end+1; n++) {
534 inst0 = inst = code->inst[n].inst0;
535 fprintf(stderr,"%d\t0:CMN_INST 0x%08x:", n, inst);
536 switch(inst & 0x3) {
537 case R500_INST_TYPE_ALU: str = "ALU"; break;
538 case R500_INST_TYPE_OUT: str = "OUT"; break;
539 case R500_INST_TYPE_FC: str = "FC"; break;
540 case R500_INST_TYPE_TEX: str = "TEX"; break;
541 };
542 fprintf(stderr,"%s %s %s %s %s ", str,
543 inst & R500_INST_TEX_SEM_WAIT ? "TEX_WAIT" : "",
544 inst & R500_INST_LAST ? "LAST" : "",
545 inst & R500_INST_NOP ? "NOP" : "",
546 inst & R500_INST_ALU_WAIT ? "ALU WAIT" : "");
547 fprintf(stderr,"wmask: %s omask: %s\n", to_mask((inst >> 11) & 0xf),
548 to_mask((inst >> 15) & 0xf));
549
550 switch(inst0 & 0x3) {
551 case 0:
552 case 1:
553 fprintf(stderr,"\t1:RGB_ADDR 0x%08x:", code->inst[n].inst1);
554 inst = code->inst[n].inst1;
555
556 fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n",
557 inst & 0xff, (inst & (1<<8)) ? 'c' : 't',
558 (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't',
559 (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't',
560 (inst >> 30));
561
562 fprintf(stderr,"\t2:ALPHA_ADDR 0x%08x:", code->inst[n].inst2);
563 inst = code->inst[n].inst2;
564 fprintf(stderr,"Addr0: %d%c, Addr1: %d%c, Addr2: %d%c, srcp:%d\n",
565 inst & 0xff, (inst & (1<<8)) ? 'c' : 't',
566 (inst >> 10) & 0xff, (inst & (1<<18)) ? 'c' : 't',
567 (inst >> 20) & 0xff, (inst & (1<<28)) ? 'c' : 't',
568 (inst >> 30));
569 fprintf(stderr,"\t3 RGB_INST: 0x%08x:", code->inst[n].inst3);
570 inst = code->inst[n].inst3;
571 fprintf(stderr,"rgb_A_src:%d %s/%s/%s %d rgb_B_src:%d %s/%s/%s %d\n",
572 (inst) & 0x3, toswiz((inst >> 2) & 0x7), toswiz((inst >> 5) & 0x7), toswiz((inst >> 8) & 0x7),
573 (inst >> 11) & 0x3,
574 (inst >> 13) & 0x3, toswiz((inst >> 15) & 0x7), toswiz((inst >> 18) & 0x7), toswiz((inst >> 21) & 0x7),
575 (inst >> 24) & 0x3);
576
577
578 fprintf(stderr,"\t4 ALPHA_INST:0x%08x:", code->inst[n].inst4);
579 inst = code->inst[n].inst4;
580 fprintf(stderr,"%s dest:%d%s alp_A_src:%d %s %d alp_B_src:%d %s %d w:%d\n", to_alpha_op(inst & 0xf),
581 (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"",
582 (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), (inst >> 17) & 0x3,
583 (inst >> 19) & 0x3, toswiz((inst >> 21) & 0x7), (inst >> 24) & 0x3,
584 (inst >> 31) & 0x1);
585
586 fprintf(stderr,"\t5 RGBA_INST: 0x%08x:", code->inst[n].inst5);
587 inst = code->inst[n].inst5;
588 fprintf(stderr,"%s dest:%d%s rgb_C_src:%d %s/%s/%s %d alp_C_src:%d %s %d\n", toop(inst & 0xf),
589 (inst >> 4) & 0x7f, inst & (1<<11) ? "(rel)":"",
590 (inst >> 12) & 0x3, toswiz((inst >> 14) & 0x7), toswiz((inst >> 17) & 0x7), toswiz((inst >> 20) & 0x7),
591 (inst >> 23) & 0x3,
592 (inst >> 25) & 0x3, toswiz((inst >> 27) & 0x7), (inst >> 30) & 0x3);
593 break;
594 case 2:
595 break;
596 case 3:
597 inst = code->inst[n].inst1;
598 fprintf(stderr,"\t1:TEX_INST: 0x%08x: id: %d op:%s, %s, %s %s\n", inst, (inst >> 16) & 0xf,
599 to_texop((inst >> 22) & 0x7), (inst & (1<<25)) ? "ACQ" : "",
600 (inst & (1<<26)) ? "IGNUNC" : "", (inst & (1<<27)) ? "UNSCALED" : "SCALED");
601 inst = code->inst[n].inst2;
602 fprintf(stderr,"\t2:TEX_ADDR: 0x%08x: src: %d%s %s/%s/%s/%s dst: %d%s %s/%s/%s/%s\n", inst,
603 inst & 127, inst & (1<<7) ? "(rel)" : "",
604 toswiz((inst >> 8) & 0x3), toswiz((inst >> 10) & 0x3),
605 toswiz((inst >> 12) & 0x3), toswiz((inst >> 14) & 0x3),
606 (inst >> 16) & 127, inst & (1<<23) ? "(rel)" : "",
607 toswiz((inst >> 24) & 0x3), toswiz((inst >> 26) & 0x3),
608 toswiz((inst >> 28) & 0x3), toswiz((inst >> 30) & 0x3));
609
610 fprintf(stderr,"\t3:TEX_DXDY: 0x%08x\n", code->inst[n].inst3);
611 break;
612 }
613 fprintf(stderr,"\n");
614 }
615
616 }