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