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