Merge commit 'origin/gallium-draw-retval'
[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 "LOOP",
104 "PRED",
105 "SV"
106 };
107
108 static const char *interpolate_names[] =
109 {
110 "CONSTANT",
111 "LINEAR",
112 "PERSPECTIVE"
113 };
114
115 static const char *semantic_names[] =
116 {
117 "POSITION",
118 "COLOR",
119 "BCOLOR",
120 "FOG",
121 "PSIZE",
122 "GENERIC",
123 "NORMAL",
124 "FACE",
125 "EDGEFLAG",
126 "PRIM_ID"
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 };
163
164 static const char *primitive_names[] =
165 {
166 "POINTS",
167 "LINES",
168 "LINE_LOOP",
169 "LINE_STRIP",
170 "TRIANGLES",
171 "TRIANGLE_STRIP",
172 "TRIANGLE_FAN",
173 "QUADS",
174 "QUAD_STRIP",
175 "POLYGON"
176 };
177
178
179 static void
180 _dump_register_decl(
181 struct dump_ctx *ctx,
182 uint file,
183 int first,
184 int last )
185 {
186 ENM( file, file_names );
187
188 /* all geometry shader inputs are two dimensional */
189 if (file == TGSI_FILE_INPUT &&
190 ctx->iter.processor.Processor == TGSI_PROCESSOR_GEOMETRY)
191 TXT("[]");
192
193 CHR( '[' );
194 SID( first );
195 if (first != last) {
196 TXT( ".." );
197 SID( last );
198 }
199 CHR( ']' );
200 }
201
202 static void
203 _dump_register_dst(
204 struct dump_ctx *ctx,
205 uint file,
206 int index)
207 {
208 ENM( file, file_names );
209
210 CHR( '[' );
211 SID( index );
212 CHR( ']' );
213 }
214
215
216 static void
217 _dump_register_src(
218 struct dump_ctx *ctx,
219 const struct tgsi_full_src_register *src )
220 {
221 if (src->Register.Indirect) {
222 ENM( src->Register.File, file_names );
223 CHR( '[' );
224 ENM( src->Indirect.File, file_names );
225 CHR( '[' );
226 SID( src->Indirect.Index );
227 TXT( "]." );
228 ENM( src->Indirect.SwizzleX, swizzle_names );
229 if (src->Register.Index != 0) {
230 if (src->Register.Index > 0)
231 CHR( '+' );
232 SID( src->Register.Index );
233 }
234 CHR( ']' );
235 } else {
236 ENM( src->Register.File, file_names );
237 CHR( '[' );
238 SID( src->Register.Index );
239 CHR( ']' );
240 }
241 if (src->Register.Dimension) {
242 CHR( '[' );
243 SID( src->Dimension.Index );
244 CHR( ']' );
245 }
246 }
247
248 static void
249 _dump_register_ind(
250 struct dump_ctx *ctx,
251 uint file,
252 int index,
253 uint ind_file,
254 int ind_index,
255 uint ind_swizzle )
256 {
257 ENM( file, file_names );
258 CHR( '[' );
259 ENM( ind_file, file_names );
260 CHR( '[' );
261 SID( ind_index );
262 TXT( "]." );
263 ENM( ind_swizzle, swizzle_names );
264 if (index != 0) {
265 if (index > 0)
266 CHR( '+' );
267 SID( index );
268 }
269 CHR( ']' );
270 }
271
272 static void
273 _dump_writemask(
274 struct dump_ctx *ctx,
275 uint writemask )
276 {
277 if (writemask != TGSI_WRITEMASK_XYZW) {
278 CHR( '.' );
279 if (writemask & TGSI_WRITEMASK_X)
280 CHR( 'x' );
281 if (writemask & TGSI_WRITEMASK_Y)
282 CHR( 'y' );
283 if (writemask & TGSI_WRITEMASK_Z)
284 CHR( 'z' );
285 if (writemask & TGSI_WRITEMASK_W)
286 CHR( 'w' );
287 }
288 }
289
290 static boolean
291 iter_declaration(
292 struct tgsi_iterate_context *iter,
293 struct tgsi_full_declaration *decl )
294 {
295 struct dump_ctx *ctx = (struct dump_ctx *)iter;
296
297 assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
298 assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
299
300 TXT( "DCL " );
301
302 _dump_register_decl(
303 ctx,
304 decl->Declaration.File,
305 decl->Range.First,
306 decl->Range.Last );
307 _dump_writemask(
308 ctx,
309 decl->Declaration.UsageMask );
310
311 if (decl->Declaration.Semantic) {
312 TXT( ", " );
313 ENM( decl->Semantic.Name, semantic_names );
314 if (decl->Semantic.Index != 0 ||
315 decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
316 CHR( '[' );
317 UID( decl->Semantic.Index );
318 CHR( ']' );
319 }
320 }
321
322 if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
323 decl->Declaration.File == TGSI_FILE_INPUT)
324 {
325 TXT( ", " );
326 ENM( decl->Declaration.Interpolate, interpolate_names );
327 }
328
329 if (decl->Declaration.Centroid) {
330 TXT( ", CENTROID" );
331 }
332
333 if (decl->Declaration.Invariant) {
334 TXT( ", INVARIANT" );
335 }
336
337 EOL();
338
339 return TRUE;
340 }
341
342 void
343 tgsi_dump_declaration(
344 const struct tgsi_full_declaration *decl )
345 {
346 struct dump_ctx ctx;
347
348 ctx.printf = dump_ctx_printf;
349
350 iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
351 }
352
353 static boolean
354 iter_property(
355 struct tgsi_iterate_context *iter,
356 struct tgsi_full_property *prop )
357 {
358 int i;
359 struct dump_ctx *ctx = (struct dump_ctx *)iter;
360
361 assert(Elements(property_names) == TGSI_PROPERTY_COUNT);
362
363 TXT( "PROPERTY " );
364 ENM(prop->Property.PropertyName, property_names);
365
366 if (prop->Property.NrTokens > 1)
367 TXT(" ");
368
369 for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
370 switch (prop->Property.PropertyName) {
371 case TGSI_PROPERTY_GS_INPUT_PRIM:
372 case TGSI_PROPERTY_GS_OUTPUT_PRIM:
373 ENM(prop->u[i].Data, primitive_names);
374 break;
375 default:
376 SID( prop->u[i].Data );
377 break;
378 }
379 if (i < prop->Property.NrTokens - 2)
380 TXT( ", " );
381 }
382 EOL();
383
384 return TRUE;
385 }
386
387 void tgsi_dump_property(
388 const struct tgsi_full_property *prop )
389 {
390 struct dump_ctx ctx;
391
392 ctx.printf = dump_ctx_printf;
393
394 iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
395 }
396
397 static boolean
398 iter_immediate(
399 struct tgsi_iterate_context *iter,
400 struct tgsi_full_immediate *imm )
401 {
402 struct dump_ctx *ctx = (struct dump_ctx *) iter;
403
404 uint i;
405
406 TXT( "IMM " );
407 ENM( imm->Immediate.DataType, immediate_type_names );
408
409 TXT( " { " );
410
411 assert( imm->Immediate.NrTokens <= 4 + 1 );
412 for (i = 0; i < imm->Immediate.NrTokens - 1; i++) {
413 switch (imm->Immediate.DataType) {
414 case TGSI_IMM_FLOAT32:
415 FLT( imm->u[i].Float );
416 break;
417 case TGSI_IMM_UINT32:
418 UID(imm->u[i].Uint);
419 break;
420 case TGSI_IMM_INT32:
421 SID(imm->u[i].Int);
422 break;
423 default:
424 assert( 0 );
425 }
426
427 if (i < imm->Immediate.NrTokens - 2)
428 TXT( ", " );
429 }
430 TXT( " }" );
431
432 EOL();
433
434 return TRUE;
435 }
436
437 void
438 tgsi_dump_immediate(
439 const struct tgsi_full_immediate *imm )
440 {
441 struct dump_ctx ctx;
442
443 ctx.printf = dump_ctx_printf;
444
445 iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
446 }
447
448 static boolean
449 iter_instruction(
450 struct tgsi_iterate_context *iter,
451 struct tgsi_full_instruction *inst )
452 {
453 struct dump_ctx *ctx = (struct dump_ctx *) iter;
454 uint instno = ctx->instno++;
455 const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
456 uint i;
457 boolean first_reg = TRUE;
458
459 INSTID( instno );
460 TXT( ": " );
461
462 ctx->indent -= info->pre_dedent;
463 for(i = 0; (int)i < ctx->indent; ++i)
464 TXT( " " );
465 ctx->indent += info->post_indent;
466
467 TXT( info->mnemonic );
468
469 switch (inst->Instruction.Saturate) {
470 case TGSI_SAT_NONE:
471 break;
472 case TGSI_SAT_ZERO_ONE:
473 TXT( "_SAT" );
474 break;
475 case TGSI_SAT_MINUS_PLUS_ONE:
476 TXT( "_SATNV" );
477 break;
478 default:
479 assert( 0 );
480 }
481
482 for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
483 const struct tgsi_full_dst_register *dst = &inst->Dst[i];
484
485 if (!first_reg)
486 CHR( ',' );
487 CHR( ' ' );
488
489 if (dst->Register.Indirect) {
490 _dump_register_ind(
491 ctx,
492 dst->Register.File,
493 dst->Register.Index,
494 dst->Indirect.File,
495 dst->Indirect.Index,
496 dst->Indirect.SwizzleX );
497 }
498 else {
499 _dump_register_dst(
500 ctx,
501 dst->Register.File,
502 dst->Register.Index );
503 }
504 _dump_writemask( ctx, dst->Register.WriteMask );
505
506 first_reg = FALSE;
507 }
508
509 for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
510 const struct tgsi_full_src_register *src = &inst->Src[i];
511
512 if (!first_reg)
513 CHR( ',' );
514 CHR( ' ' );
515
516 if (src->Register.Negate)
517 CHR( '-' );
518 if (src->Register.Absolute)
519 CHR( '|' );
520
521 _dump_register_src(ctx, src);
522
523 if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
524 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
525 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
526 src->Register.SwizzleW != TGSI_SWIZZLE_W) {
527 CHR( '.' );
528 ENM( src->Register.SwizzleX, swizzle_names );
529 ENM( src->Register.SwizzleY, swizzle_names );
530 ENM( src->Register.SwizzleZ, swizzle_names );
531 ENM( src->Register.SwizzleW, swizzle_names );
532 }
533
534 if (src->Register.Absolute)
535 CHR( '|' );
536
537 first_reg = FALSE;
538 }
539
540 if (inst->Instruction.Texture) {
541 TXT( ", " );
542 ENM( inst->Texture.Texture, texture_names );
543 }
544
545 switch (inst->Instruction.Opcode) {
546 case TGSI_OPCODE_IF:
547 case TGSI_OPCODE_ELSE:
548 case TGSI_OPCODE_BGNLOOP:
549 case TGSI_OPCODE_ENDLOOP:
550 case TGSI_OPCODE_CAL:
551 TXT( " :" );
552 UID( inst->Label.Label );
553 break;
554 }
555
556 /* update indentation */
557 if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
558 inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
559 inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR ||
560 inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
561 ctx->indentation += indent_spaces;
562 }
563
564 EOL();
565
566 return TRUE;
567 }
568
569 void
570 tgsi_dump_instruction(
571 const struct tgsi_full_instruction *inst,
572 uint instno )
573 {
574 struct dump_ctx ctx;
575
576 ctx.instno = instno;
577 ctx.indent = 0;
578 ctx.printf = dump_ctx_printf;
579 ctx.indentation = 0;
580
581 iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
582 }
583
584 static boolean
585 prolog(
586 struct tgsi_iterate_context *iter )
587 {
588 struct dump_ctx *ctx = (struct dump_ctx *) iter;
589 ENM( iter->processor.Processor, processor_type_names );
590 EOL();
591 return TRUE;
592 }
593
594 void
595 tgsi_dump(
596 const struct tgsi_token *tokens,
597 uint flags )
598 {
599 struct dump_ctx ctx;
600
601 ctx.iter.prolog = prolog;
602 ctx.iter.iterate_instruction = iter_instruction;
603 ctx.iter.iterate_declaration = iter_declaration;
604 ctx.iter.iterate_immediate = iter_immediate;
605 ctx.iter.iterate_property = iter_property;
606 ctx.iter.epilog = NULL;
607
608 ctx.instno = 0;
609 ctx.indent = 0;
610 ctx.printf = dump_ctx_printf;
611 ctx.indentation = 0;
612
613 tgsi_iterate_shader( tokens, &ctx.iter );
614 }
615
616 struct str_dump_ctx
617 {
618 struct dump_ctx base;
619 char *str;
620 char *ptr;
621 int left;
622 };
623
624 static void
625 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
626 {
627 struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
628
629 if(sctx->left > 1) {
630 int written;
631 va_list ap;
632 va_start(ap, format);
633 written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
634 va_end(ap);
635
636 /* Some complicated logic needed to handle the return value of
637 * vsnprintf:
638 */
639 if (written > 0) {
640 written = MIN2(sctx->left, written);
641 sctx->ptr += written;
642 sctx->left -= written;
643 }
644 }
645 }
646
647 void
648 tgsi_dump_str(
649 const struct tgsi_token *tokens,
650 uint flags,
651 char *str,
652 size_t size)
653 {
654 struct str_dump_ctx ctx;
655
656 ctx.base.iter.prolog = prolog;
657 ctx.base.iter.iterate_instruction = iter_instruction;
658 ctx.base.iter.iterate_declaration = iter_declaration;
659 ctx.base.iter.iterate_immediate = iter_immediate;
660 ctx.base.iter.iterate_property = iter_property;
661 ctx.base.iter.epilog = NULL;
662
663 ctx.base.instno = 0;
664 ctx.base.indent = 0;
665 ctx.base.printf = &str_dump_ctx_printf;
666 ctx.base.indentation = 0;
667
668 ctx.str = str;
669 ctx.str[0] = 0;
670 ctx.ptr = str;
671 ctx.left = (int)size;
672
673 tgsi_iterate_shader( tokens, &ctx.base.iter );
674 }