tgsi_dump.c revision ba1ca28cc62fed71c77902b95ae4ed36c6bf25f8
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 */
38static const int indent_spaces = 3;
39
40
41struct 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
53static void
54dump_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
63static void
64dump_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
86static const char *processor_type_names[] =
87{
88   "FRAG",
89   "VERT",
90   "GEOM"
91};
92
93static 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};
106
107static const char *interpolate_names[] =
108{
109   "CONSTANT",
110   "LINEAR",
111   "PERSPECTIVE"
112};
113
114static const char *semantic_names[] =
115{
116   "POSITION",
117   "COLOR",
118   "BCOLOR",
119   "FOG",
120   "PSIZE",
121   "GENERIC",
122   "NORMAL",
123   "FACE"
124};
125
126static const char *immediate_type_names[] =
127{
128   "FLT32"
129};
130
131static const char *swizzle_names[] =
132{
133   "x",
134   "y",
135   "z",
136   "w"
137};
138
139static const char *texture_names[] =
140{
141   "UNKNOWN",
142   "1D",
143   "2D",
144   "3D",
145   "CUBE",
146   "RECT",
147   "SHADOW1D",
148   "SHADOW2D",
149   "SHADOWRECT"
150};
151
152
153static void
154_dump_register(
155   struct dump_ctx *ctx,
156   uint file,
157   int first,
158   int last )
159{
160   ENM( file, file_names );
161   CHR( '[' );
162   SID( first );
163   if (first != last) {
164      TXT( ".." );
165      SID( last );
166   }
167   CHR( ']' );
168}
169
170static void
171_dump_register_ind(
172   struct dump_ctx *ctx,
173   uint file,
174   int index,
175   uint ind_file,
176   int ind_index,
177   uint ind_swizzle )
178{
179   ENM( file, file_names );
180   CHR( '[' );
181   ENM( ind_file, file_names );
182   CHR( '[' );
183   SID( ind_index );
184   TXT( "]." );
185   ENM( ind_swizzle, swizzle_names );
186   if (index != 0) {
187      if (index > 0)
188         CHR( '+' );
189      SID( index );
190   }
191   CHR( ']' );
192}
193
194static void
195_dump_writemask(
196   struct dump_ctx *ctx,
197   uint writemask )
198{
199   if (writemask != TGSI_WRITEMASK_XYZW) {
200      CHR( '.' );
201      if (writemask & TGSI_WRITEMASK_X)
202         CHR( 'x' );
203      if (writemask & TGSI_WRITEMASK_Y)
204         CHR( 'y' );
205      if (writemask & TGSI_WRITEMASK_Z)
206         CHR( 'z' );
207      if (writemask & TGSI_WRITEMASK_W)
208         CHR( 'w' );
209   }
210}
211
212static boolean
213iter_declaration(
214   struct tgsi_iterate_context *iter,
215   struct tgsi_full_declaration *decl )
216{
217   struct dump_ctx *ctx = (struct dump_ctx *)iter;
218
219   assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
220   assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
221
222   TXT( "DCL " );
223
224   _dump_register(
225      ctx,
226      decl->Declaration.File,
227      decl->DeclarationRange.First,
228      decl->DeclarationRange.Last );
229   _dump_writemask(
230      ctx,
231      decl->Declaration.UsageMask );
232
233   if (decl->Declaration.Semantic) {
234      TXT( ", " );
235      ENM( decl->Semantic.SemanticName, semantic_names );
236      if (decl->Semantic.SemanticIndex != 0 ||
237          decl->Semantic.SemanticName == TGSI_SEMANTIC_GENERIC) {
238         CHR( '[' );
239         UID( decl->Semantic.SemanticIndex );
240         CHR( ']' );
241      }
242   }
243
244   if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
245       decl->Declaration.File == TGSI_FILE_INPUT)
246   {
247      TXT( ", " );
248      ENM( decl->Declaration.Interpolate, interpolate_names );
249   }
250
251   if (decl->Declaration.Centroid) {
252      TXT( ", CENTROID" );
253   }
254
255   if (decl->Declaration.Invariant) {
256      TXT( ", INVARIANT" );
257   }
258
259   EOL();
260
261   return TRUE;
262}
263
264void
265tgsi_dump_declaration(
266   const struct tgsi_full_declaration *decl )
267{
268   struct dump_ctx ctx;
269
270   ctx.printf = dump_ctx_printf;
271
272   iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
273}
274
275static boolean
276iter_immediate(
277   struct tgsi_iterate_context *iter,
278   struct tgsi_full_immediate *imm )
279{
280   struct dump_ctx *ctx = (struct dump_ctx *) iter;
281
282   uint i;
283
284   TXT( "IMM " );
285   ENM( imm->Immediate.DataType, immediate_type_names );
286
287   TXT( " { " );
288
289   assert( imm->Immediate.NrTokens <= 4 + 1 );
290   for (i = 0; i < imm->Immediate.NrTokens - 1; i++) {
291      switch (imm->Immediate.DataType) {
292      case TGSI_IMM_FLOAT32:
293         FLT( imm->u[i].Float );
294         break;
295      default:
296         assert( 0 );
297      }
298
299      if (i < imm->Immediate.NrTokens - 2)
300         TXT( ", " );
301   }
302   TXT( " }" );
303
304   EOL();
305
306   return TRUE;
307}
308
309void
310tgsi_dump_immediate(
311   const struct tgsi_full_immediate *imm )
312{
313   struct dump_ctx ctx;
314
315   ctx.printf = dump_ctx_printf;
316
317   iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
318}
319
320static boolean
321iter_instruction(
322   struct tgsi_iterate_context *iter,
323   struct tgsi_full_instruction *inst )
324{
325   struct dump_ctx *ctx = (struct dump_ctx *) iter;
326   uint instno = ctx->instno++;
327   const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
328   uint i;
329   boolean first_reg = TRUE;
330
331   INSTID( instno );
332   TXT( ": " );
333
334   ctx->indent -= info->pre_dedent;
335   for(i = 0; (int)i < ctx->indent; ++i)
336      TXT( "  " );
337   ctx->indent += info->post_indent;
338
339   TXT( info->mnemonic );
340
341   switch (inst->Instruction.Saturate) {
342   case TGSI_SAT_NONE:
343      break;
344   case TGSI_SAT_ZERO_ONE:
345      TXT( "_SAT" );
346      break;
347   case TGSI_SAT_MINUS_PLUS_ONE:
348      TXT( "_SATNV" );
349      break;
350   default:
351      assert( 0 );
352   }
353
354   for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
355      const struct tgsi_full_dst_register *dst = &inst->FullDstRegisters[i];
356
357      if (!first_reg)
358         CHR( ',' );
359      CHR( ' ' );
360
361      if (dst->DstRegister.Indirect) {
362         _dump_register_ind(
363            ctx,
364            dst->DstRegister.File,
365            dst->DstRegister.Index,
366            dst->DstRegisterInd.File,
367            dst->DstRegisterInd.Index,
368            dst->DstRegisterInd.SwizzleX );
369      }
370      else {
371         _dump_register(
372            ctx,
373            dst->DstRegister.File,
374            dst->DstRegister.Index,
375            dst->DstRegister.Index );
376      }
377      _dump_writemask( ctx, dst->DstRegister.WriteMask );
378
379      first_reg = FALSE;
380   }
381
382   for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
383      const struct tgsi_full_src_register *src = &inst->FullSrcRegisters[i];
384
385      if (!first_reg)
386         CHR( ',' );
387      CHR( ' ' );
388
389      if (src->SrcRegister.Negate)
390         TXT( "-(" );
391      if (src->SrcRegister.Absolute)
392         CHR( '|' );
393
394      if (src->SrcRegister.Indirect) {
395         _dump_register_ind(
396            ctx,
397            src->SrcRegister.File,
398            src->SrcRegister.Index,
399            src->SrcRegisterInd.File,
400            src->SrcRegisterInd.Index,
401            src->SrcRegisterInd.SwizzleX );
402      }
403      else {
404         _dump_register(
405            ctx,
406            src->SrcRegister.File,
407            src->SrcRegister.Index,
408            src->SrcRegister.Index );
409      }
410
411      if (src->SrcRegister.SwizzleX != TGSI_SWIZZLE_X ||
412          src->SrcRegister.SwizzleY != TGSI_SWIZZLE_Y ||
413          src->SrcRegister.SwizzleZ != TGSI_SWIZZLE_Z ||
414          src->SrcRegister.SwizzleW != TGSI_SWIZZLE_W) {
415         CHR( '.' );
416         ENM( src->SrcRegister.SwizzleX, swizzle_names );
417         ENM( src->SrcRegister.SwizzleY, swizzle_names );
418         ENM( src->SrcRegister.SwizzleZ, swizzle_names );
419         ENM( src->SrcRegister.SwizzleW, swizzle_names );
420      }
421
422      if (src->SrcRegister.Absolute)
423         CHR( '|' );
424      if (src->SrcRegister.Negate)
425         CHR( ')' );
426
427      first_reg = FALSE;
428   }
429
430   if (inst->Instruction.Texture) {
431      TXT( ", " );
432      ENM( inst->InstructionTexture.Texture, texture_names );
433   }
434
435   switch (inst->Instruction.Opcode) {
436   case TGSI_OPCODE_IF:
437   case TGSI_OPCODE_ELSE:
438   case TGSI_OPCODE_BGNLOOP:
439   case TGSI_OPCODE_ENDLOOP:
440   case TGSI_OPCODE_CAL:
441      TXT( " :" );
442      UID( inst->InstructionLabel.Label );
443      break;
444   }
445
446   /* update indentation */
447   if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
448       inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
449       inst->Instruction.Opcode == TGSI_OPCODE_BGNFOR ||
450       inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
451      ctx->indentation += indent_spaces;
452   }
453
454   EOL();
455
456   return TRUE;
457}
458
459void
460tgsi_dump_instruction(
461   const struct tgsi_full_instruction *inst,
462   uint instno )
463{
464   struct dump_ctx ctx;
465
466   ctx.instno = instno;
467   ctx.indent = 0;
468   ctx.printf = dump_ctx_printf;
469   ctx.indentation = 0;
470
471   iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
472}
473
474static boolean
475prolog(
476   struct tgsi_iterate_context *iter )
477{
478   struct dump_ctx *ctx = (struct dump_ctx *) iter;
479   ENM( iter->processor.Processor, processor_type_names );
480   UID( iter->version.MajorVersion );
481   CHR( '.' );
482   UID( iter->version.MinorVersion );
483   EOL();
484   return TRUE;
485}
486
487void
488tgsi_dump(
489   const struct tgsi_token *tokens,
490   uint flags )
491{
492   struct dump_ctx ctx;
493
494   ctx.iter.prolog = prolog;
495   ctx.iter.iterate_instruction = iter_instruction;
496   ctx.iter.iterate_declaration = iter_declaration;
497   ctx.iter.iterate_immediate = iter_immediate;
498   ctx.iter.epilog = NULL;
499
500   ctx.instno = 0;
501   ctx.indent = 0;
502   ctx.printf = dump_ctx_printf;
503   ctx.indentation = 0;
504
505   tgsi_iterate_shader( tokens, &ctx.iter );
506}
507
508struct str_dump_ctx
509{
510   struct dump_ctx base;
511   char *str;
512   char *ptr;
513   int left;
514};
515
516static void
517str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
518{
519   struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
520
521   if(sctx->left > 1) {
522      int written;
523      va_list ap;
524      va_start(ap, format);
525      written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
526      va_end(ap);
527
528      /* Some complicated logic needed to handle the return value of
529       * vsnprintf:
530       */
531      if (written > 0) {
532         written = MIN2(sctx->left, written);
533         sctx->ptr += written;
534         sctx->left -= written;
535      }
536   }
537}
538
539void
540tgsi_dump_str(
541   const struct tgsi_token *tokens,
542   uint flags,
543   char *str,
544   size_t size)
545{
546   struct str_dump_ctx ctx;
547
548   ctx.base.iter.prolog = prolog;
549   ctx.base.iter.iterate_instruction = iter_instruction;
550   ctx.base.iter.iterate_declaration = iter_declaration;
551   ctx.base.iter.iterate_immediate = iter_immediate;
552   ctx.base.iter.epilog = NULL;
553
554   ctx.base.instno = 0;
555   ctx.base.indent = 0;
556   ctx.base.printf = &str_dump_ctx_printf;
557   ctx.base.indentation = 0;
558
559   ctx.str = str;
560   ctx.str[0] = 0;
561   ctx.ptr = str;
562   ctx.left = (int)size;
563
564   tgsi_iterate_shader( tokens, &ctx.base.iter );
565}
566