Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / auxiliary / tgsi / tgsi_dump.c
1 /**************************************************************************
2 *
3 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * 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, sub license, 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 portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "util/u_debug.h"
29 #include "util/u_string.h"
30 #include "util/u_math.h"
31 #include "util/u_memory.h"
32 #include "tgsi_dump.h"
33 #include "tgsi_info.h"
34 #include "tgsi_iterate.h"
35
36
37 /** Number of spaces to indent for IF/LOOP/etc */
38 static const int indent_spaces = 3;
39
40
41 struct dump_ctx
42 {
43 struct tgsi_iterate_context iter;
44
45 uint instno;
46
47 uint indentation;
48
49 void (*printf)(struct dump_ctx *ctx, const char *format, ...);
50 };
51
52 static void
53 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
54 {
55 va_list ap;
56 (void)ctx;
57 va_start(ap, format);
58 debug_vprintf(format, ap);
59 va_end(ap);
60 }
61
62 static void
63 dump_enum(
64 struct dump_ctx *ctx,
65 uint e,
66 const char **enums,
67 uint enum_count )
68 {
69 if (e >= enum_count)
70 ctx->printf( ctx, "%u", e );
71 else
72 ctx->printf( ctx, "%s", enums[e] );
73 }
74
75 #define EOL() ctx->printf( ctx, "\n" )
76 #define TXT(S) ctx->printf( ctx, "%s", S )
77 #define CHR(C) ctx->printf( ctx, "%c", C )
78 #define UIX(I) ctx->printf( ctx, "0x%x", I )
79 #define UID(I) ctx->printf( ctx, "%u", I )
80 #define INSTID(I) ctx->printf( ctx, "% 3u", I )
81 #define SID(I) ctx->printf( ctx, "%d", I )
82 #define FLT(F) ctx->printf( ctx, "%10.4f", F )
83 #define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) )
84
85 static const char *processor_type_names[] =
86 {
87 "FRAG",
88 "VERT",
89 "GEOM"
90 };
91
92 static const char *file_names[TGSI_FILE_COUNT] =
93 {
94 "NULL",
95 "CONST",
96 "IN",
97 "OUT",
98 "TEMP",
99 "SAMP",
100 "ADDR",
101 "IMM",
102 "LOOP"
103 };
104
105 static const char *interpolate_names[] =
106 {
107 "CONSTANT",
108 "LINEAR",
109 "PERSPECTIVE"
110 };
111
112 static const char *semantic_names[] =
113 {
114 "POSITION",
115 "COLOR",
116 "BCOLOR",
117 "FOG",
118 "PSIZE",
119 "GENERIC",
120 "NORMAL",
121 "FACE"
122 };
123
124 static const char *immediate_type_names[] =
125 {
126 "FLT32"
127 };
128
129 static const char *swizzle_names[] =
130 {
131 "x",
132 "y",
133 "z",
134 "w"
135 };
136
137 static const char *texture_names[] =
138 {
139 "UNKNOWN",
140 "1D",
141 "2D",
142 "3D",
143 "CUBE",
144 "RECT",
145 "SHADOW1D",
146 "SHADOW2D",
147 "SHADOWRECT"
148 };
149
150 static const char *extswizzle_names[] =
151 {
152 "x",
153 "y",
154 "z",
155 "w",
156 "0",
157 "1"
158 };
159
160 static const char *modulate_names[TGSI_MODULATE_COUNT] =
161 {
162 "",
163 "_2X",
164 "_4X",
165 "_8X",
166 "_D2",
167 "_D4",
168 "_D8"
169 };
170
171 static void
172 _dump_register(
173 struct dump_ctx *ctx,
174 uint file,
175 int first,
176 int last )
177 {
178 ENM( file, file_names );
179 CHR( '[' );
180 SID( first );
181 if (first != last) {
182 TXT( ".." );
183 SID( last );
184 }
185 CHR( ']' );
186 }
187
188 static void
189 _dump_register_ind(
190 struct dump_ctx *ctx,
191 uint file,
192 int index,
193 uint ind_file,
194 int ind_index,
195 uint ind_swizzle )
196 {
197 ENM( file, file_names );
198 CHR( '[' );
199 ENM( ind_file, file_names );
200 CHR( '[' );
201 SID( ind_index );
202 TXT( "]." );
203 ENM( ind_swizzle, swizzle_names );
204 if (index != 0) {
205 if (index > 0)
206 CHR( '+' );
207 SID( index );
208 }
209 CHR( ']' );
210 }
211
212 static void
213 _dump_writemask(
214 struct dump_ctx *ctx,
215 uint writemask )
216 {
217 if (writemask != TGSI_WRITEMASK_XYZW) {
218 CHR( '.' );
219 if (writemask & TGSI_WRITEMASK_X)
220 CHR( 'x' );
221 if (writemask & TGSI_WRITEMASK_Y)
222 CHR( 'y' );
223 if (writemask & TGSI_WRITEMASK_Z)
224 CHR( 'z' );
225 if (writemask & TGSI_WRITEMASK_W)
226 CHR( 'w' );
227 }
228 }
229
230 static boolean
231 iter_declaration(
232 struct tgsi_iterate_context *iter,
233 struct tgsi_full_declaration *decl )
234 {
235 struct dump_ctx *ctx = (struct dump_ctx *)iter;
236
237 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
238 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
239
240 TXT( "DCL " );
241
242 _dump_register(
243 ctx,
244 decl->Declaration.File,
245 decl->DeclarationRange.First,
246 decl->DeclarationRange.Last );
247 _dump_writemask(
248 ctx,
249 decl->Declaration.UsageMask );
250
251 if (decl->Declaration.Semantic) {
252 TXT( ", " );
253 ENM( decl->Semantic.SemanticName, semantic_names );
254 if (decl->Semantic.SemanticIndex != 0 ||
255 decl->Semantic.SemanticName == TGSI_SEMANTIC_GENERIC) {
256 CHR( '[' );
257 UID( decl->Semantic.SemanticIndex );
258 CHR( ']' );
259 }
260 }
261
262 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
263 decl->Declaration.File == TGSI_FILE_INPUT)
264 {
265 TXT( ", " );
266 ENM( decl->Declaration.Interpolate, interpolate_names );
267 }
268
269 if (decl->Declaration.Centroid) {
270 TXT( ", CENTROID" );
271 }
272
273 if (decl->Declaration.Invariant) {
274 TXT( ", INVARIANT" );
275 }
276
277 EOL();
278
279 return TRUE;
280 }
281
282 void
283 tgsi_dump_declaration(
284 const struct tgsi_full_declaration *decl )
285 {
286 struct dump_ctx ctx;
287
288 ctx.printf = dump_ctx_printf;
289
290 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
291 }
292
293 static boolean
294 iter_immediate(
295 struct tgsi_iterate_context *iter,
296 struct tgsi_full_immediate *imm )
297 {
298 struct dump_ctx *ctx = (struct dump_ctx *) iter;
299
300 uint i;
301
302 TXT( "IMM " );
303 ENM( imm->Immediate.DataType, immediate_type_names );
304
305 TXT( " { " );
306
307 assert( imm->Immediate.NrTokens <= 4 + 1 );
308 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) {
309 switch (imm->Immediate.DataType) {
310 case TGSI_IMM_FLOAT32:
311 FLT( imm->u[i].Float );
312 break;
313 default:
314 assert( 0 );
315 }
316
317 if (i < imm->Immediate.NrTokens - 2)
318 TXT( ", " );
319 }
320 TXT( " }" );
321
322 EOL();
323
324 return TRUE;
325 }
326
327 void
328 tgsi_dump_immediate(
329 const struct tgsi_full_immediate *imm )
330 {
331 struct dump_ctx ctx;
332
333 ctx.printf = dump_ctx_printf;
334
335 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
336 }
337
338 static void
339 indent(struct dump_ctx *ctx)
340 {
341 uint i;
342 for (i = 0; i < ctx->indentation; i++)
343 TXT(" ");
344 }
345
346 static boolean
347 iter_instruction(
348 struct tgsi_iterate_context *iter,
349 struct tgsi_full_instruction *inst )
350 {
351 struct dump_ctx *ctx = (struct dump_ctx *) iter;
352 uint instno = ctx->instno++;
353
354 uint i;
355 boolean first_reg = TRUE;
356
357 INSTID( instno );
358 TXT( ": " );
359
360 /* update indentation */
361 if (inst->Instruction.Opcode == TGSI_OPCODE_ENDIF ||
362 inst->Instruction.Opcode == TGSI_OPCODE_ENDFOR ||
363 inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP) {
364 ctx->indentation -= indent_spaces;
365 }
366 indent(ctx);
367
368 TXT( tgsi_get_opcode_info( inst->Instruction.Opcode )->mnemonic );
369
370 switch (inst->Instruction.Saturate) {
371 case TGSI_SAT_NONE:
372 break;
373 case TGSI_SAT_ZERO_ONE:
374 TXT( "_SAT" );
375 break;
376 case TGSI_SAT_MINUS_PLUS_ONE:
377 TXT( "_SATNV" );
378 break;
379 default:
380 assert( 0 );
381 }
382
383 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
384 const struct tgsi_full_dst_register *dst = &inst->FullDstRegisters[i];
385
386 if (!first_reg)
387 CHR( ',' );
388 CHR( ' ' );
389
390 if (dst->DstRegister.Indirect) {
391 _dump_register_ind(
392 ctx,
393 dst->DstRegister.File,
394 dst->DstRegister.Index,
395 dst->DstRegisterInd.File,
396 dst->DstRegisterInd.Index,
397 dst->DstRegisterInd.SwizzleX );
398 }
399 else {
400 _dump_register(
401 ctx,
402 dst->DstRegister.File,
403 dst->DstRegister.Index,
404 dst->DstRegister.Index );
405 }
406 ENM( dst->DstRegisterExtModulate.Modulate, modulate_names );
407 _dump_writemask( ctx, dst->DstRegister.WriteMask );
408
409 first_reg = FALSE;
410 }
411
412 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
413 const struct tgsi_full_src_register *src = &inst->FullSrcRegisters[i];
414
415 if (!first_reg)
416 CHR( ',' );
417 CHR( ' ' );
418
419 if (src->SrcRegisterExtMod.Negate)
420 TXT( "-(" );
421 if (src->SrcRegisterExtMod.Absolute)
422 CHR( '|' );
423 if (src->SrcRegisterExtMod.Scale2X)
424 TXT( "2*(" );
425 if (src->SrcRegisterExtMod.Bias)
426 CHR( '(' );
427 if (src->SrcRegisterExtMod.Complement)
428 TXT( "1-(" );
429 if (src->SrcRegister.Negate)
430 CHR( '-' );
431
432 if (src->SrcRegister.Indirect) {
433 _dump_register_ind(
434 ctx,
435 src->SrcRegister.File,
436 src->SrcRegister.Index,
437 src->SrcRegisterInd.File,
438 src->SrcRegisterInd.Index,
439 src->SrcRegisterInd.SwizzleX );
440 }
441 else {
442 _dump_register(
443 ctx,
444 src->SrcRegister.File,
445 src->SrcRegister.Index,
446 src->SrcRegister.Index );
447 }
448
449 if (src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X ||
450 src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y ||
451 src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z ||
452 src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W) {
453 CHR( '.' );
454 ENM( src->SrcRegister.SwizzleX, swizzle_names );
455 ENM( src->SrcRegister.SwizzleY, swizzle_names );
456 ENM( src->SrcRegister.SwizzleZ, swizzle_names );
457 ENM( src->SrcRegister.SwizzleW, swizzle_names );
458 }
459 if (src->SrcRegisterExtSwz.ExtSwizzleX != TGSI_EXTSWIZZLE_X ||
460 src->SrcRegisterExtSwz.ExtSwizzleY != TGSI_EXTSWIZZLE_Y ||
461 src->SrcRegisterExtSwz.ExtSwizzleZ != TGSI_EXTSWIZZLE_Z ||
462 src->SrcRegisterExtSwz.ExtSwizzleW != TGSI_EXTSWIZZLE_W) {
463 CHR( '.' );
464 if (src->SrcRegisterExtSwz.NegateX)
465 TXT("-");
466 ENM( src->SrcRegisterExtSwz.ExtSwizzleX, extswizzle_names );
467 if (src->SrcRegisterExtSwz.NegateY)
468 TXT("-");
469 ENM( src->SrcRegisterExtSwz.ExtSwizzleY, extswizzle_names );
470 if (src->SrcRegisterExtSwz.NegateZ)
471 TXT("-");
472 ENM( src->SrcRegisterExtSwz.ExtSwizzleZ, extswizzle_names );
473 if (src->SrcRegisterExtSwz.NegateW)
474 TXT("-");
475 ENM( src->SrcRegisterExtSwz.ExtSwizzleW, extswizzle_names );
476 }
477
478 if (src->SrcRegisterExtMod.Complement)
479 CHR( ')' );
480 if (src->SrcRegisterExtMod.Bias)
481 TXT( ")-.5" );
482 if (src->SrcRegisterExtMod.Scale2X)
483 CHR( ')' );
484 if (src->SrcRegisterExtMod.Absolute)
485 CHR( '|' );
486 if (src->SrcRegisterExtMod.Negate)
487 CHR( ')' );
488
489 first_reg = FALSE;
490 }
491
492 if (inst->InstructionExtTexture.Texture != TGSI_TEXTURE_UNKNOWN) {
493 TXT( ", " );
494 ENM( inst->InstructionExtTexture.Texture, texture_names );
495 }
496
497 switch (inst->Instruction.Opcode) {
498 case TGSI_OPCODE_IF:
499 case TGSI_OPCODE_ELSE:
500 case TGSI_OPCODE_BGNLOOP:
501 case TGSI_OPCODE_ENDLOOP:
502 case TGSI_OPCODE_CAL:
503 TXT( " :" );
504 UID( inst->InstructionExtLabel.Label );
505 break;
506 }
507
508 /* update indentation */
509 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
510 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
511 inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR ||
512 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
513 ctx->indentation += indent_spaces;
514 }
515
516 EOL();
517
518 return TRUE;
519 }
520
521 void
522 tgsi_dump_instruction(
523 const struct tgsi_full_instruction *inst,
524 uint instno )
525 {
526 struct dump_ctx ctx;
527
528 ctx.instno = instno;
529 ctx.printf = dump_ctx_printf;
530 ctx.indentation = 0;
531
532 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
533 }
534
535 static boolean
536 prolog(
537 struct tgsi_iterate_context *iter )
538 {
539 struct dump_ctx *ctx = (struct dump_ctx *) iter;
540 ENM( iter->processor.Processor, processor_type_names );
541 UID( iter->version.MajorVersion );
542 CHR( '.' );
543 UID( iter->version.MinorVersion );
544 EOL();
545 return TRUE;
546 }
547
548 void
549 tgsi_dump(
550 const struct tgsi_token *tokens,
551 uint flags )
552 {
553 struct dump_ctx ctx;
554
555 ctx.iter.prolog = prolog;
556 ctx.iter.iterate_instruction = iter_instruction;
557 ctx.iter.iterate_declaration = iter_declaration;
558 ctx.iter.iterate_immediate = iter_immediate;
559 ctx.iter.epilog = NULL;
560
561 ctx.instno = 0;
562 ctx.printf = dump_ctx_printf;
563 ctx.indentation = 0;
564
565 tgsi_iterate_shader( tokens, &ctx.iter );
566 }
567
568 struct str_dump_ctx
569 {
570 struct dump_ctx base;
571 char *str;
572 char *ptr;
573 int left;
574 };
575
576 static void
577 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
578 {
579 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
580
581 if(sctx->left > 1) {
582 int written;
583 va_list ap;
584 va_start(ap, format);
585 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
586 va_end(ap);
587
588 /* Some complicated logic needed to handle the return value of
589 * vsnprintf:
590 */
591 if (written > 0) {
592 written = MIN2(sctx->left, written);
593 sctx->ptr += written;
594 sctx->left -= written;
595 }
596 }
597 }
598
599 void
600 tgsi_dump_str(
601 const struct tgsi_token *tokens,
602 uint flags,
603 char *str,
604 size_t size)
605 {
606 struct str_dump_ctx ctx;
607
608 ctx.base.iter.prolog = prolog;
609 ctx.base.iter.iterate_instruction = iter_instruction;
610 ctx.base.iter.iterate_declaration = iter_declaration;
611 ctx.base.iter.iterate_immediate = iter_immediate;
612 ctx.base.iter.epilog = NULL;
613
614 ctx.base.instno = 0;
615 ctx.base.printf = &str_dump_ctx_printf;
616 ctx.base.indentation = 0;
617
618 ctx.str = str;
619 ctx.str[0] = 0;
620 ctx.ptr = str;
621 ctx.left = (int)size;
622
623 tgsi_iterate_shader( tokens, &ctx.base.iter );
624 }