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