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