tgsi: Parse and dump predicates.
[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 CHR('[');
215 SID(src->Dimension.Index);
216 CHR(']');
217 }
218 if (src->Register.Indirect) {
219 CHR( '[' );
220 ENM( src->Indirect.File, file_names );
221 CHR( '[' );
222 SID( src->Indirect.Index );
223 TXT( "]." );
224 ENM( src->Indirect.SwizzleX, swizzle_names );
225 if (src->Register.Index != 0) {
226 if (src->Register.Index > 0)
227 CHR( '+' );
228 SID( src->Register.Index );
229 }
230 CHR( ']' );
231 } else {
232 CHR( '[' );
233 SID( src->Register.Index );
234 CHR( ']' );
235 }
236 }
237
238 static void
239 _dump_register_ind(
240 struct dump_ctx *ctx,
241 uint file,
242 int index,
243 uint ind_file,
244 int ind_index,
245 uint ind_swizzle )
246 {
247 ENM( file, file_names );
248 CHR( '[' );
249 ENM( ind_file, file_names );
250 CHR( '[' );
251 SID( ind_index );
252 TXT( "]." );
253 ENM( ind_swizzle, swizzle_names );
254 if (index != 0) {
255 if (index > 0)
256 CHR( '+' );
257 SID( index );
258 }
259 CHR( ']' );
260 }
261
262 static void
263 _dump_writemask(
264 struct dump_ctx *ctx,
265 uint writemask )
266 {
267 if (writemask != TGSI_WRITEMASK_XYZW) {
268 CHR( '.' );
269 if (writemask & TGSI_WRITEMASK_X)
270 CHR( 'x' );
271 if (writemask & TGSI_WRITEMASK_Y)
272 CHR( 'y' );
273 if (writemask & TGSI_WRITEMASK_Z)
274 CHR( 'z' );
275 if (writemask & TGSI_WRITEMASK_W)
276 CHR( 'w' );
277 }
278 }
279
280 static boolean
281 iter_declaration(
282 struct tgsi_iterate_context *iter,
283 struct tgsi_full_declaration *decl )
284 {
285 struct dump_ctx *ctx = (struct dump_ctx *)iter;
286
287 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
288 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
289
290 TXT( "DCL " );
291
292 ENM(decl->Declaration.File, file_names);
293
294 /* all geometry shader inputs are two dimensional */
295 if (decl->Declaration.File == TGSI_FILE_INPUT &&
296 iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
297 TXT("[]");
298 }
299
300 if (decl->Declaration.Dimension) {
301 CHR('[');
302 SID(decl->Dim.Index2D);
303 CHR(']');
304 }
305
306 CHR('[');
307 SID(decl->Range.First);
308 if (decl->Range.First != decl->Range.Last) {
309 TXT("..");
310 SID(decl->Range.Last);
311 }
312 CHR(']');
313
314 _dump_writemask(
315 ctx,
316 decl->Declaration.UsageMask );
317
318 if (decl->Declaration.Semantic) {
319 TXT( ", " );
320 ENM( decl->Semantic.Name, semantic_names );
321 if (decl->Semantic.Index != 0 ||
322 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
323 CHR( '[' );
324 UID( decl->Semantic.Index );
325 CHR( ']' );
326 }
327 }
328
329 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
330 decl->Declaration.File == TGSI_FILE_INPUT)
331 {
332 TXT( ", " );
333 ENM( decl->Declaration.Interpolate, interpolate_names );
334 }
335
336 if (decl->Declaration.Centroid) {
337 TXT( ", CENTROID" );
338 }
339
340 if (decl->Declaration.Invariant) {
341 TXT( ", INVARIANT" );
342 }
343
344 if (decl->Declaration.CylindricalWrap) {
345 TXT(", CYLWRAP_");
346 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
347 CHR('X');
348 }
349 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
350 CHR('Y');
351 }
352 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
353 CHR('Z');
354 }
355 if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
356 CHR('W');
357 }
358 }
359
360 EOL();
361
362 return TRUE;
363 }
364
365 void
366 tgsi_dump_declaration(
367 const struct tgsi_full_declaration *decl )
368 {
369 struct dump_ctx ctx;
370
371 ctx.printf = dump_ctx_printf;
372
373 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
374 }
375
376 static boolean
377 iter_property(
378 struct tgsi_iterate_context *iter,
379 struct tgsi_full_property *prop )
380 {
381 int i;
382 struct dump_ctx *ctx = (struct dump_ctx *)iter;
383
384 assert(Elements(property_names) == TGSI_PROPERTY_COUNT);
385
386 TXT( "PROPERTY " );
387 ENM(prop->Property.PropertyName, property_names);
388
389 if (prop->Property.NrTokens > 1)
390 TXT(" ");
391
392 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
393 switch (prop->Property.PropertyName) {
394 case TGSI_PROPERTY_GS_INPUT_PRIM:
395 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
396 ENM(prop->u[i].Data, primitive_names);
397 break;
398 case TGSI_PROPERTY_FS_COORD_ORIGIN:
399 ENM(prop->u[i].Data, fs_coord_origin_names);
400 break;
401 case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
402 ENM(prop->u[i].Data, fs_coord_pixel_center_names);
403 break;
404 default:
405 SID( prop->u[i].Data );
406 break;
407 }
408 if (i < prop->Property.NrTokens - 2)
409 TXT( ", " );
410 }
411 EOL();
412
413 return TRUE;
414 }
415
416 void tgsi_dump_property(
417 const struct tgsi_full_property *prop )
418 {
419 struct dump_ctx ctx;
420
421 ctx.printf = dump_ctx_printf;
422
423 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
424 }
425
426 static boolean
427 iter_immediate(
428 struct tgsi_iterate_context *iter,
429 struct tgsi_full_immediate *imm )
430 {
431 struct dump_ctx *ctx = (struct dump_ctx *) iter;
432
433 uint i;
434
435 TXT( "IMM " );
436 ENM( imm->Immediate.DataType, immediate_type_names );
437
438 TXT( " { " );
439
440 assert( imm->Immediate.NrTokens <= 4 + 1 );
441 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) {
442 switch (imm->Immediate.DataType) {
443 case TGSI_IMM_FLOAT32:
444 FLT( imm->u[i].Float );
445 break;
446 case TGSI_IMM_UINT32:
447 UID(imm->u[i].Uint);
448 break;
449 case TGSI_IMM_INT32:
450 SID(imm->u[i].Int);
451 break;
452 default:
453 assert( 0 );
454 }
455
456 if (i < imm->Immediate.NrTokens - 2)
457 TXT( ", " );
458 }
459 TXT( " }" );
460
461 EOL();
462
463 return TRUE;
464 }
465
466 void
467 tgsi_dump_immediate(
468 const struct tgsi_full_immediate *imm )
469 {
470 struct dump_ctx ctx;
471
472 ctx.printf = dump_ctx_printf;
473
474 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
475 }
476
477 static boolean
478 iter_instruction(
479 struct tgsi_iterate_context *iter,
480 struct tgsi_full_instruction *inst )
481 {
482 struct dump_ctx *ctx = (struct dump_ctx *) iter;
483 uint instno = ctx->instno++;
484 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
485 uint i;
486 boolean first_reg = TRUE;
487
488 INSTID( instno );
489 TXT( ": " );
490
491 ctx->indent -= info->pre_dedent;
492 for(i = 0; (int)i < ctx->indent; ++i)
493 TXT( " " );
494 ctx->indent += info->post_indent;
495
496 if (inst->Instruction.Predicate) {
497 CHR( '(' );
498
499 if (inst->Predicate.Negate)
500 CHR( '!' );
501
502 TXT( "PRED[" );
503 SID( inst->Predicate.Index );
504 CHR( ']' );
505
506 if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
507 inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
508 inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
509 inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
510 CHR( '.' );
511 ENM( inst->Predicate.SwizzleX, swizzle_names );
512 ENM( inst->Predicate.SwizzleY, swizzle_names );
513 ENM( inst->Predicate.SwizzleZ, swizzle_names );
514 ENM( inst->Predicate.SwizzleW, swizzle_names );
515 }
516
517 TXT( ") " );
518 }
519
520 TXT( info->mnemonic );
521
522 switch (inst->Instruction.Saturate) {
523 case TGSI_SAT_NONE:
524 break;
525 case TGSI_SAT_ZERO_ONE:
526 TXT( "_SAT" );
527 break;
528 case TGSI_SAT_MINUS_PLUS_ONE:
529 TXT( "_SATNV" );
530 break;
531 default:
532 assert( 0 );
533 }
534
535 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
536 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
537
538 if (!first_reg)
539 CHR( ',' );
540 CHR( ' ' );
541
542 if (dst->Register.Indirect) {
543 _dump_register_ind(
544 ctx,
545 dst->Register.File,
546 dst->Register.Index,
547 dst->Indirect.File,
548 dst->Indirect.Index,
549 dst->Indirect.SwizzleX );
550 }
551 else {
552 _dump_register_dst(
553 ctx,
554 dst->Register.File,
555 dst->Register.Index );
556 }
557 _dump_writemask( ctx, dst->Register.WriteMask );
558
559 first_reg = FALSE;
560 }
561
562 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
563 const struct tgsi_full_src_register *src = &inst->Src[i];
564
565 if (!first_reg)
566 CHR( ',' );
567 CHR( ' ' );
568
569 if (src->Register.Negate)
570 CHR( '-' );
571 if (src->Register.Absolute)
572 CHR( '|' );
573
574 _dump_register_src(ctx, src);
575
576 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
577 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
578 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
579 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
580 CHR( '.' );
581 ENM( src->Register.SwizzleX, swizzle_names );
582 ENM( src->Register.SwizzleY, swizzle_names );
583 ENM( src->Register.SwizzleZ, swizzle_names );
584 ENM( src->Register.SwizzleW, swizzle_names );
585 }
586
587 if (src->Register.Absolute)
588 CHR( '|' );
589
590 first_reg = FALSE;
591 }
592
593 if (inst->Instruction.Texture) {
594 TXT( ", " );
595 ENM( inst->Texture.Texture, texture_names );
596 }
597
598 switch (inst->Instruction.Opcode) {
599 case TGSI_OPCODE_IF:
600 case TGSI_OPCODE_ELSE:
601 case TGSI_OPCODE_BGNLOOP:
602 case TGSI_OPCODE_ENDLOOP:
603 case TGSI_OPCODE_CAL:
604 TXT( " :" );
605 UID( inst->Label.Label );
606 break;
607 }
608
609 /* update indentation */
610 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
611 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
612 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
613 ctx->indentation += indent_spaces;
614 }
615
616 EOL();
617
618 return TRUE;
619 }
620
621 void
622 tgsi_dump_instruction(
623 const struct tgsi_full_instruction *inst,
624 uint instno )
625 {
626 struct dump_ctx ctx;
627
628 ctx.instno = instno;
629 ctx.indent = 0;
630 ctx.printf = dump_ctx_printf;
631 ctx.indentation = 0;
632
633 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
634 }
635
636 static boolean
637 prolog(
638 struct tgsi_iterate_context *iter )
639 {
640 struct dump_ctx *ctx = (struct dump_ctx *) iter;
641 ENM( iter->processor.Processor, processor_type_names );
642 EOL();
643 return TRUE;
644 }
645
646 void
647 tgsi_dump(
648 const struct tgsi_token *tokens,
649 uint flags )
650 {
651 struct dump_ctx ctx;
652
653 ctx.iter.prolog = prolog;
654 ctx.iter.iterate_instruction = iter_instruction;
655 ctx.iter.iterate_declaration = iter_declaration;
656 ctx.iter.iterate_immediate = iter_immediate;
657 ctx.iter.iterate_property = iter_property;
658 ctx.iter.epilog = NULL;
659
660 ctx.instno = 0;
661 ctx.indent = 0;
662 ctx.printf = dump_ctx_printf;
663 ctx.indentation = 0;
664
665 tgsi_iterate_shader( tokens, &ctx.iter );
666 }
667
668 struct str_dump_ctx
669 {
670 struct dump_ctx base;
671 char *str;
672 char *ptr;
673 int left;
674 };
675
676 static void
677 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
678 {
679 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
680
681 if(sctx->left > 1) {
682 int written;
683 va_list ap;
684 va_start(ap, format);
685 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
686 va_end(ap);
687
688 /* Some complicated logic needed to handle the return value of
689 * vsnprintf:
690 */
691 if (written > 0) {
692 written = MIN2(sctx->left, written);
693 sctx->ptr += written;
694 sctx->left -= written;
695 }
696 }
697 }
698
699 void
700 tgsi_dump_str(
701 const struct tgsi_token *tokens,
702 uint flags,
703 char *str,
704 size_t size)
705 {
706 struct str_dump_ctx ctx;
707
708 ctx.base.iter.prolog = prolog;
709 ctx.base.iter.iterate_instruction = iter_instruction;
710 ctx.base.iter.iterate_declaration = iter_declaration;
711 ctx.base.iter.iterate_immediate = iter_immediate;
712 ctx.base.iter.iterate_property = iter_property;
713 ctx.base.iter.epilog = NULL;
714
715 ctx.base.instno = 0;
716 ctx.base.indent = 0;
717 ctx.base.printf = &str_dump_ctx_printf;
718 ctx.base.indentation = 0;
719
720 ctx.str = str;
721 ctx.str[0] = 0;
722 ctx.ptr = str;
723 ctx.left = (int)size;
724
725 tgsi_iterate_shader( tokens, &ctx.base.iter );
726 }