de6d4419464b7de3ad551e1d8319a9ddebf4fd33
[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 int indent;
47
48 uint indentation;
49
50 void (*printf)(struct dump_ctx *ctx, const char *format, ...);
51 };
52
53 static void
54 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
55 {
56 va_list ap;
57 (void)ctx;
58 va_start(ap, format);
59 _debug_vprintf(format, ap);
60 va_end(ap);
61 }
62
63 static void
64 dump_enum(
65 struct dump_ctx *ctx,
66 uint e,
67 const char **enums,
68 uint enum_count )
69 {
70 if (e >= enum_count)
71 ctx->printf( ctx, "%u", e );
72 else
73 ctx->printf( ctx, "%s", enums[e] );
74 }
75
76 #define EOL() ctx->printf( ctx, "\n" )
77 #define TXT(S) ctx->printf( ctx, "%s", S )
78 #define CHR(C) ctx->printf( ctx, "%c", C )
79 #define UIX(I) ctx->printf( ctx, "0x%x", I )
80 #define UID(I) ctx->printf( ctx, "%u", I )
81 #define INSTID(I) ctx->printf( ctx, "% 3u", I )
82 #define SID(I) ctx->printf( ctx, "%d", I )
83 #define FLT(F) ctx->printf( ctx, "%10.4f", F )
84 #define ENM(E,ENUMS) dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) )
85
86 static const char *processor_type_names[] =
87 {
88 "FRAG",
89 "VERT",
90 "GEOM"
91 };
92
93 static const char *file_names[TGSI_FILE_COUNT] =
94 {
95 "NULL",
96 "CONST",
97 "IN",
98 "OUT",
99 "TEMP",
100 "SAMP",
101 "ADDR",
102 "IMM",
103 "PRED",
104 "SV"
105 };
106
107 static const char *interpolate_names[] =
108 {
109 "CONSTANT",
110 "LINEAR",
111 "PERSPECTIVE"
112 };
113
114 static const char *semantic_names[] =
115 {
116 "POSITION",
117 "COLOR",
118 "BCOLOR",
119 "FOG",
120 "PSIZE",
121 "GENERIC",
122 "NORMAL",
123 "FACE",
124 "EDGEFLAG",
125 "PRIM_ID",
126 "INSTANCEID"
127 };
128
129 static const char *immediate_type_names[] =
130 {
131 "FLT32",
132 "UINT32",
133 "INT32"
134 };
135
136 static const char *swizzle_names[] =
137 {
138 "x",
139 "y",
140 "z",
141 "w"
142 };
143
144 static const char *texture_names[] =
145 {
146 "UNKNOWN",
147 "1D",
148 "2D",
149 "3D",
150 "CUBE",
151 "RECT",
152 "SHADOW1D",
153 "SHADOW2D",
154 "SHADOWRECT"
155 };
156
157 static const char *property_names[] =
158 {
159 "GS_INPUT_PRIMITIVE",
160 "GS_OUTPUT_PRIMITIVE",
161 "GS_MAX_OUTPUT_VERTICES",
162 "FS_COORD_ORIGIN",
163 "FS_COORD_PIXEL_CENTER"
164 };
165
166 static const char *primitive_names[] =
167 {
168 "POINTS",
169 "LINES",
170 "LINE_LOOP",
171 "LINE_STRIP",
172 "TRIANGLES",
173 "TRIANGLE_STRIP",
174 "TRIANGLE_FAN",
175 "QUADS",
176 "QUAD_STRIP",
177 "POLYGON"
178 };
179
180 static const char *fs_coord_origin_names[] =
181 {
182 "UPPER_LEFT",
183 "LOWER_LEFT"
184 };
185
186 static const char *fs_coord_pixel_center_names[] =
187 {
188 "HALF_INTEGER",
189 "INTEGER"
190 };
191
192
193 static void
194 _dump_register_dst(
195 struct dump_ctx *ctx,
196 uint file,
197 int index)
198 {
199 ENM( file, file_names );
200
201 CHR( '[' );
202 SID( index );
203 CHR( ']' );
204 }
205
206
207 static void
208 _dump_register_src(
209 struct dump_ctx *ctx,
210 const struct tgsi_full_src_register *src )
211 {
212 ENM(src->Register.File, file_names);
213 if (src->Register.Dimension) {
214 if (src->Dimension.Indirect) {
215 CHR( '[' );
216 ENM( src->DimIndirect.File, file_names );
217 CHR( '[' );
218 SID( src->DimIndirect.Index );
219 TXT( "]." );
220 ENM( src->DimIndirect.SwizzleX, swizzle_names );
221 if (src->Dimension.Index != 0) {
222 if (src->Dimension.Index > 0)
223 CHR( '+' );
224 SID( src->Dimension.Index );
225 }
226 CHR( ']' );
227 } else {
228 CHR('[');
229 SID(src->Dimension.Index);
230 CHR(']');
231 }
232 }
233 if (src->Register.Indirect) {
234 CHR( '[' );
235 ENM( src->Indirect.File, file_names );
236 CHR( '[' );
237 SID( src->Indirect.Index );
238 TXT( "]." );
239 ENM( src->Indirect.SwizzleX, swizzle_names );
240 if (src->Register.Index != 0) {
241 if (src->Register.Index > 0)
242 CHR( '+' );
243 SID( src->Register.Index );
244 }
245 CHR( ']' );
246 } else {
247 CHR( '[' );
248 SID( src->Register.Index );
249 CHR( ']' );
250 }
251 }
252
253 static void
254 _dump_register_ind(
255 struct dump_ctx *ctx,
256 uint file,
257 int index,
258 uint ind_file,
259 int ind_index,
260 uint ind_swizzle )
261 {
262 ENM( file, file_names );
263 CHR( '[' );
264 ENM( ind_file, file_names );
265 CHR( '[' );
266 SID( ind_index );
267 TXT( "]." );
268 ENM( ind_swizzle, swizzle_names );
269 if (index != 0) {
270 if (index > 0)
271 CHR( '+' );
272 SID( index );
273 }
274 CHR( ']' );
275 }
276
277 static void
278 _dump_writemask(
279 struct dump_ctx *ctx,
280 uint writemask )
281 {
282 if (writemask != TGSI_WRITEMASK_XYZW) {
283 CHR( '.' );
284 if (writemask & TGSI_WRITEMASK_X)
285 CHR( 'x' );
286 if (writemask & TGSI_WRITEMASK_Y)
287 CHR( 'y' );
288 if (writemask & TGSI_WRITEMASK_Z)
289 CHR( 'z' );
290 if (writemask & TGSI_WRITEMASK_W)
291 CHR( 'w' );
292 }
293 }
294
295 static boolean
296 iter_declaration(
297 struct tgsi_iterate_context *iter,
298 struct tgsi_full_declaration *decl )
299 {
300 struct dump_ctx *ctx = (struct dump_ctx *)iter;
301
302 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
303 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
304
305 TXT( "DCL " );
306
307 ENM(decl->Declaration.File, file_names);
308
309 /* all geometry shader inputs are two dimensional */
310 if (decl->Declaration.File == TGSI_FILE_INPUT &&
311 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
312 TXT("[]");
313 }
314
315 if (decl->Declaration.Dimension) {
316 CHR('[');
317 SID(decl->Dim.Index2D);
318 CHR(']');
319 }
320
321 CHR('[');
322 SID(decl->Range.First);
323 if (decl->Range.First != decl->Range.Last) {
324 TXT("..");
325 SID(decl->Range.Last);
326 }
327 CHR(']');
328
329 _dump_writemask(
330 ctx,
331 decl->Declaration.UsageMask );
332
333 if (decl->Declaration.Semantic) {
334 TXT( ", " );
335 ENM( decl->Semantic.Name, semantic_names );
336 if (decl->Semantic.Index != 0 ||
337 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
338 CHR( '[' );
339 UID( decl->Semantic.Index );
340 CHR( ']' );
341 }
342 }
343
344 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
345 decl->Declaration.File == TGSI_FILE_INPUT)
346 {
347 TXT( ", " );
348 ENM( decl->Declaration.Interpolate, interpolate_names );
349 }
350
351 if (decl->Declaration.Centroid) {
352 TXT( ", CENTROID" );
353 }
354
355 if (decl->Declaration.Invariant) {
356 TXT( ", INVARIANT" );
357 }
358
359 if (decl->Declaration.CylindricalWrap) {
360 TXT(", CYLWRAP_");
361 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
362 CHR('X');
363 }
364 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
365 CHR('Y');
366 }
367 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
368 CHR('Z');
369 }
370 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
371 CHR('W');
372 }
373 }
374
375 EOL();
376
377 return TRUE;
378 }
379
380 void
381 tgsi_dump_declaration(
382 const struct tgsi_full_declaration *decl )
383 {
384 struct dump_ctx ctx;
385
386 ctx.printf = dump_ctx_printf;
387
388 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
389 }
390
391 static boolean
392 iter_property(
393 struct tgsi_iterate_context *iter,
394 struct tgsi_full_property *prop )
395 {
396 int i;
397 struct dump_ctx *ctx = (struct dump_ctx *)iter;
398
399 assert(Elements(property_names) == TGSI_PROPERTY_COUNT);
400
401 TXT( "PROPERTY " );
402 ENM(prop->Property.PropertyName, property_names);
403
404 if (prop->Property.NrTokens > 1)
405 TXT(" ");
406
407 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
408 switch (prop->Property.PropertyName) {
409 case TGSI_PROPERTY_GS_INPUT_PRIM:
410 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
411 ENM(prop->u[i].Data, primitive_names);
412 break;
413 case TGSI_PROPERTY_FS_COORD_ORIGIN:
414 ENM(prop->u[i].Data, fs_coord_origin_names);
415 break;
416 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
417 ENM(prop->u[i].Data, fs_coord_pixel_center_names);
418 break;
419 default:
420 SID( prop->u[i].Data );
421 break;
422 }
423 if (i < prop->Property.NrTokens - 2)
424 TXT( ", " );
425 }
426 EOL();
427
428 return TRUE;
429 }
430
431 void tgsi_dump_property(
432 const struct tgsi_full_property *prop )
433 {
434 struct dump_ctx ctx;
435
436 ctx.printf = dump_ctx_printf;
437
438 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
439 }
440
441 static boolean
442 iter_immediate(
443 struct tgsi_iterate_context *iter,
444 struct tgsi_full_immediate *imm )
445 {
446 struct dump_ctx *ctx = (struct dump_ctx *) iter;
447
448 uint i;
449
450 TXT( "IMM " );
451 ENM( imm->Immediate.DataType, immediate_type_names );
452
453 TXT( " { " );
454
455 assert( imm->Immediate.NrTokens <= 4 + 1 );
456 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) {
457 switch (imm->Immediate.DataType) {
458 case TGSI_IMM_FLOAT32:
459 FLT( imm->u[i].Float );
460 break;
461 case TGSI_IMM_UINT32:
462 UID(imm->u[i].Uint);
463 break;
464 case TGSI_IMM_INT32:
465 SID(imm->u[i].Int);
466 break;
467 default:
468 assert( 0 );
469 }
470
471 if (i < imm->Immediate.NrTokens - 2)
472 TXT( ", " );
473 }
474 TXT( " }" );
475
476 EOL();
477
478 return TRUE;
479 }
480
481 void
482 tgsi_dump_immediate(
483 const struct tgsi_full_immediate *imm )
484 {
485 struct dump_ctx ctx;
486
487 ctx.printf = dump_ctx_printf;
488
489 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
490 }
491
492 static boolean
493 iter_instruction(
494 struct tgsi_iterate_context *iter,
495 struct tgsi_full_instruction *inst )
496 {
497 struct dump_ctx *ctx = (struct dump_ctx *) iter;
498 uint instno = ctx->instno++;
499 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
500 uint i;
501 boolean first_reg = TRUE;
502
503 INSTID( instno );
504 TXT( ": " );
505
506 ctx->indent -= info->pre_dedent;
507 for(i = 0; (int)i < ctx->indent; ++i)
508 TXT( " " );
509 ctx->indent += info->post_indent;
510
511 if (inst->Instruction.Predicate) {
512 CHR( '(' );
513
514 if (inst->Predicate.Negate)
515 CHR( '!' );
516
517 TXT( "PRED[" );
518 SID( inst->Predicate.Index );
519 CHR( ']' );
520
521 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
522 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
523 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
524 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
525 CHR( '.' );
526 ENM( inst->Predicate.SwizzleX, swizzle_names );
527 ENM( inst->Predicate.SwizzleY, swizzle_names );
528 ENM( inst->Predicate.SwizzleZ, swizzle_names );
529 ENM( inst->Predicate.SwizzleW, swizzle_names );
530 }
531
532 TXT( ") " );
533 }
534
535 TXT( info->mnemonic );
536
537 switch (inst->Instruction.Saturate) {
538 case TGSI_SAT_NONE:
539 break;
540 case TGSI_SAT_ZERO_ONE:
541 TXT( "_SAT" );
542 break;
543 case TGSI_SAT_MINUS_PLUS_ONE:
544 TXT( "_SATNV" );
545 break;
546 default:
547 assert( 0 );
548 }
549
550 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
551 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
552
553 if (!first_reg)
554 CHR( ',' );
555 CHR( ' ' );
556
557 if (dst->Register.Indirect) {
558 _dump_register_ind(
559 ctx,
560 dst->Register.File,
561 dst->Register.Index,
562 dst->Indirect.File,
563 dst->Indirect.Index,
564 dst->Indirect.SwizzleX );
565 }
566 else {
567 _dump_register_dst(
568 ctx,
569 dst->Register.File,
570 dst->Register.Index );
571 }
572 _dump_writemask( ctx, dst->Register.WriteMask );
573
574 first_reg = FALSE;
575 }
576
577 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
578 const struct tgsi_full_src_register *src = &inst->Src[i];
579
580 if (!first_reg)
581 CHR( ',' );
582 CHR( ' ' );
583
584 if (src->Register.Negate)
585 CHR( '-' );
586 if (src->Register.Absolute)
587 CHR( '|' );
588
589 _dump_register_src(ctx, src);
590
591 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
592 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
593 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
594 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
595 CHR( '.' );
596 ENM( src->Register.SwizzleX, swizzle_names );
597 ENM( src->Register.SwizzleY, swizzle_names );
598 ENM( src->Register.SwizzleZ, swizzle_names );
599 ENM( src->Register.SwizzleW, swizzle_names );
600 }
601
602 if (src->Register.Absolute)
603 CHR( '|' );
604
605 first_reg = FALSE;
606 }
607
608 if (inst->Instruction.Texture) {
609 TXT( ", " );
610 ENM( inst->Texture.Texture, texture_names );
611 }
612
613 switch (inst->Instruction.Opcode) {
614 case TGSI_OPCODE_IF:
615 case TGSI_OPCODE_ELSE:
616 case TGSI_OPCODE_BGNLOOP:
617 case TGSI_OPCODE_ENDLOOP:
618 case TGSI_OPCODE_CAL:
619 TXT( " :" );
620 UID( inst->Label.Label );
621 break;
622 }
623
624 /* update indentation */
625 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
626 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
627 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
628 ctx->indentation += indent_spaces;
629 }
630
631 EOL();
632
633 return TRUE;
634 }
635
636 void
637 tgsi_dump_instruction(
638 const struct tgsi_full_instruction *inst,
639 uint instno )
640 {
641 struct dump_ctx ctx;
642
643 ctx.instno = instno;
644 ctx.indent = 0;
645 ctx.printf = dump_ctx_printf;
646 ctx.indentation = 0;
647
648 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
649 }
650
651 static boolean
652 prolog(
653 struct tgsi_iterate_context *iter )
654 {
655 struct dump_ctx *ctx = (struct dump_ctx *) iter;
656 ENM( iter->processor.Processor, processor_type_names );
657 EOL();
658 return TRUE;
659 }
660
661 void
662 tgsi_dump(
663 const struct tgsi_token *tokens,
664 uint flags )
665 {
666 struct dump_ctx ctx;
667
668 ctx.iter.prolog = prolog;
669 ctx.iter.iterate_instruction = iter_instruction;
670 ctx.iter.iterate_declaration = iter_declaration;
671 ctx.iter.iterate_immediate = iter_immediate;
672 ctx.iter.iterate_property = iter_property;
673 ctx.iter.epilog = NULL;
674
675 ctx.instno = 0;
676 ctx.indent = 0;
677 ctx.printf = dump_ctx_printf;
678 ctx.indentation = 0;
679
680 tgsi_iterate_shader( tokens, &ctx.iter );
681 }
682
683 struct str_dump_ctx
684 {
685 struct dump_ctx base;
686 char *str;
687 char *ptr;
688 int left;
689 };
690
691 static void
692 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
693 {
694 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
695
696 if(sctx->left > 1) {
697 int written;
698 va_list ap;
699 va_start(ap, format);
700 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
701 va_end(ap);
702
703 /* Some complicated logic needed to handle the return value of
704 * vsnprintf:
705 */
706 if (written > 0) {
707 written = MIN2(sctx->left, written);
708 sctx->ptr += written;
709 sctx->left -= written;
710 }
711 }
712 }
713
714 void
715 tgsi_dump_str(
716 const struct tgsi_token *tokens,
717 uint flags,
718 char *str,
719 size_t size)
720 {
721 struct str_dump_ctx ctx;
722
723 ctx.base.iter.prolog = prolog;
724 ctx.base.iter.iterate_instruction = iter_instruction;
725 ctx.base.iter.iterate_declaration = iter_declaration;
726 ctx.base.iter.iterate_immediate = iter_immediate;
727 ctx.base.iter.iterate_property = iter_property;
728 ctx.base.iter.epilog = NULL;
729
730 ctx.base.instno = 0;
731 ctx.base.indent = 0;
732 ctx.base.printf = &str_dump_ctx_printf;
733 ctx.base.indentation = 0;
734
735 ctx.str = str;
736 ctx.str[0] = 0;
737 ctx.ptr = str;
738 ctx.left = (int)size;
739
740 tgsi_iterate_shader( tokens, &ctx.base.iter );
741 }