Tizen 2.0 Release
[profile/ivi/osmesa.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 const char *
94 tgsi_file_names[TGSI_FILE_COUNT] =
95 {
96    "NULL",
97    "CONST",
98    "IN",
99    "OUT",
100    "TEMP",
101    "SAMP",
102    "ADDR",
103    "IMM",
104    "PRED",
105    "SV",
106    "IMMX",
107    "TEMPX",
108    "RES"
109 };
110
111 static const char *interpolate_names[] =
112 {
113    "CONSTANT",
114    "LINEAR",
115    "PERSPECTIVE"
116 };
117
118 static const char *semantic_names[] =
119 {
120    "POSITION",
121    "COLOR",
122    "BCOLOR",
123    "FOG",
124    "PSIZE",
125    "GENERIC",
126    "NORMAL",
127    "FACE",
128    "EDGEFLAG",
129    "PRIM_ID",
130    "INSTANCEID",
131    "STENCIL"
132 };
133
134 static const char *immediate_type_names[] =
135 {
136    "FLT32",
137    "UINT32",
138    "INT32"
139 };
140
141 const char *
142 tgsi_swizzle_names[4] =
143 {
144    "x",
145    "y",
146    "z",
147    "w"
148 };
149
150 const char *
151 tgsi_texture_names[TGSI_TEXTURE_COUNT] =
152 {
153    "UNKNOWN",
154    "1D",
155    "2D",
156    "3D",
157    "CUBE",
158    "RECT",
159    "SHADOW1D",
160    "SHADOW2D",
161    "SHADOWRECT",
162    "1DARRAY",
163    "2DARRAY"
164 };
165
166 const char *tgsi_property_names[TGSI_PROPERTY_COUNT] =
167 {
168    "GS_INPUT_PRIMITIVE",
169    "GS_OUTPUT_PRIMITIVE",
170    "GS_MAX_OUTPUT_VERTICES",
171    "FS_COORD_ORIGIN",
172    "FS_COORD_PIXEL_CENTER",
173    "FS_COLOR0_WRITES_ALL_CBUFS",
174 };
175
176 static const char *tgsi_type_names[] =
177 {
178    "UNORM",
179    "SNORM",
180    "SINT",
181    "UINT",
182    "FLOAT"
183 };
184
185 const char *tgsi_primitive_names[PIPE_PRIM_MAX] =
186 {
187    "POINTS",
188    "LINES",
189    "LINE_LOOP",
190    "LINE_STRIP",
191    "TRIANGLES",
192    "TRIANGLE_STRIP",
193    "TRIANGLE_FAN",
194    "QUADS",
195    "QUAD_STRIP",
196    "POLYGON",
197    "LINES_ADJACENCY",
198    "LINE_STRIP_ADJACENCY",
199    "TRIANGLES_ADJACENCY",
200    "TRIANGLE_STRIP_ADJACENCY"
201 };
202
203 const char *tgsi_fs_coord_origin_names[2] =
204 {
205    "UPPER_LEFT",
206    "LOWER_LEFT"
207 };
208
209 const char *tgsi_fs_coord_pixel_center_names[2] =
210 {
211    "HALF_INTEGER",
212    "INTEGER"
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    ENM(src->Register.File, tgsi_file_names);
222    if (src->Register.Dimension) {
223       if (src->Dimension.Indirect) {
224          CHR( '[' );
225          ENM( src->DimIndirect.File, tgsi_file_names );
226          CHR( '[' );
227          SID( src->DimIndirect.Index );
228          TXT( "]." );
229          ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
230          if (src->Dimension.Index != 0) {
231             if (src->Dimension.Index > 0)
232                CHR( '+' );
233             SID( src->Dimension.Index );
234          }
235          CHR( ']' );
236       } else {
237          CHR('[');
238          SID(src->Dimension.Index);
239          CHR(']');
240       }
241    }
242    if (src->Register.Indirect) {
243       CHR( '[' );
244       ENM( src->Indirect.File, tgsi_file_names );
245       CHR( '[' );
246       SID( src->Indirect.Index );
247       TXT( "]." );
248       ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
249       if (src->Register.Index != 0) {
250          if (src->Register.Index > 0)
251             CHR( '+' );
252          SID( src->Register.Index );
253       }
254       CHR( ']' );
255    } else {
256       CHR( '[' );
257       SID( src->Register.Index );
258       CHR( ']' );
259    }
260 }
261
262
263 static void
264 _dump_register_dst(
265    struct dump_ctx *ctx,
266    const struct tgsi_full_dst_register *dst )
267 {
268    ENM(dst->Register.File, tgsi_file_names);
269    if (dst->Register.Dimension) {
270       if (dst->Dimension.Indirect) {
271          CHR( '[' );
272          ENM( dst->DimIndirect.File, tgsi_file_names );
273          CHR( '[' );
274          SID( dst->DimIndirect.Index );
275          TXT( "]." );
276          ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
277          if (dst->Dimension.Index != 0) {
278             if (dst->Dimension.Index > 0)
279                CHR( '+' );
280             SID( dst->Dimension.Index );
281          }
282          CHR( ']' );
283       } else {
284          CHR('[');
285          SID(dst->Dimension.Index);
286          CHR(']');
287       }
288    }
289    if (dst->Register.Indirect) {
290       CHR( '[' );
291       ENM( dst->Indirect.File, tgsi_file_names );
292       CHR( '[' );
293       SID( dst->Indirect.Index );
294       TXT( "]." );
295       ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
296       if (dst->Register.Index != 0) {
297          if (dst->Register.Index > 0)
298             CHR( '+' );
299          SID( dst->Register.Index );
300       }
301       CHR( ']' );
302    } else {
303       CHR( '[' );
304       SID( dst->Register.Index );
305       CHR( ']' );
306    }
307 }
308 static void
309 _dump_writemask(
310    struct dump_ctx *ctx,
311    uint writemask )
312 {
313    if (writemask != TGSI_WRITEMASK_XYZW) {
314       CHR( '.' );
315       if (writemask & TGSI_WRITEMASK_X)
316          CHR( 'x' );
317       if (writemask & TGSI_WRITEMASK_Y)
318          CHR( 'y' );
319       if (writemask & TGSI_WRITEMASK_Z)
320          CHR( 'z' );
321       if (writemask & TGSI_WRITEMASK_W)
322          CHR( 'w' );
323    }
324 }
325
326 static void
327 dump_imm_data(struct tgsi_iterate_context *iter,
328               union tgsi_immediate_data *data,
329               unsigned num_tokens,
330               unsigned data_type)
331 {
332    struct dump_ctx *ctx = (struct dump_ctx *)iter;
333    unsigned i ;
334
335    TXT( " {" );
336
337    assert( num_tokens <= 4 );
338    for (i = 0; i < num_tokens; i++) {
339       switch (data_type) {
340       case TGSI_IMM_FLOAT32:
341          FLT( data[i].Float );
342          break;
343       case TGSI_IMM_UINT32:
344          UID(data[i].Uint);
345          break;
346       case TGSI_IMM_INT32:
347          SID(data[i].Int);
348          break;
349       default:
350          assert( 0 );
351       }
352
353       if (i < num_tokens - 1)
354          TXT( ", " );
355    }
356    TXT( "}" );
357 }
358
359 static boolean
360 iter_declaration(
361    struct tgsi_iterate_context *iter,
362    struct tgsi_full_declaration *decl )
363 {
364    struct dump_ctx *ctx = (struct dump_ctx *)iter;
365
366    assert(Elements(semantic_names) == TGSI_SEMANTIC_COUNT);
367    assert(Elements(interpolate_names) == TGSI_INTERPOLATE_COUNT);
368
369    TXT( "DCL " );
370
371    ENM(decl->Declaration.File, tgsi_file_names);
372
373    /* all geometry shader inputs are two dimensional */
374    if (decl->Declaration.File == TGSI_FILE_INPUT &&
375        iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
376       TXT("[]");
377    }
378
379    if (decl->Declaration.Dimension) {
380       CHR('[');
381       SID(decl->Dim.Index2D);
382       CHR(']');
383    }
384
385    CHR('[');
386    SID(decl->Range.First);
387    if (decl->Range.First != decl->Range.Last) {
388       TXT("..");
389       SID(decl->Range.Last);
390    }
391    CHR(']');
392
393    _dump_writemask(
394       ctx,
395       decl->Declaration.UsageMask );
396
397    if (decl->Declaration.Semantic) {
398       TXT( ", " );
399       ENM( decl->Semantic.Name, semantic_names );
400       if (decl->Semantic.Index != 0 ||
401           decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
402          CHR( '[' );
403          UID( decl->Semantic.Index );
404          CHR( ']' );
405       }
406    }
407
408    if (decl->Declaration.File == TGSI_FILE_RESOURCE) {
409       TXT(", ");
410       ENM(decl->Resource.Resource, tgsi_texture_names);
411       TXT(", ");
412       if ((decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeY) &&
413           (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeZ) &&
414           (decl->Resource.ReturnTypeX == decl->Resource.ReturnTypeW)) {
415          ENM(decl->Resource.ReturnTypeX, tgsi_type_names);
416       } else {
417          ENM(decl->Resource.ReturnTypeX, tgsi_type_names);
418          TXT(", ");
419          ENM(decl->Resource.ReturnTypeY, tgsi_type_names);
420          TXT(", ");
421          ENM(decl->Resource.ReturnTypeZ, tgsi_type_names);
422          TXT(", ");
423          ENM(decl->Resource.ReturnTypeW, tgsi_type_names);
424       }
425
426    }
427
428    if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
429        decl->Declaration.File == TGSI_FILE_INPUT)
430    {
431       TXT( ", " );
432       ENM( decl->Declaration.Interpolate, interpolate_names );
433    }
434
435    if (decl->Declaration.Centroid) {
436       TXT( ", CENTROID" );
437    }
438
439    if (decl->Declaration.Invariant) {
440       TXT( ", INVARIANT" );
441    }
442
443    if (decl->Declaration.CylindricalWrap) {
444       TXT(", CYLWRAP_");
445       if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
446          CHR('X');
447       }
448       if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
449          CHR('Y');
450       }
451       if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
452          CHR('Z');
453       }
454       if (decl->Declaration.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
455          CHR('W');
456       }
457    }
458
459    if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) {
460       unsigned i;
461       char range_indent[4];
462
463       TXT(" {");
464
465       if (decl->Range.Last < 10)
466          range_indent[0] = '\0';
467       else if (decl->Range.Last < 100) {
468          range_indent[0] = ' ';
469          range_indent[1] = '\0';
470       } else if (decl->Range.Last < 1000) {
471          range_indent[0] = ' ';
472          range_indent[1] = ' ';
473          range_indent[2] = '\0';
474       } else {
475          range_indent[0] = ' ';
476          range_indent[1] = ' ';
477          range_indent[2] = ' ';
478          range_indent[3] = '\0';
479       }
480
481       dump_imm_data(iter, decl->ImmediateData.u,
482                     4, TGSI_IMM_FLOAT32);
483       for(i = 1; i <= decl->Range.Last; ++i) {
484          /* indent by strlen of:
485           *   "DCL IMMX[0..1] {" */
486          CHR('\n');
487          TXT( "                " );
488          TXT( range_indent );
489          dump_imm_data(iter, decl->ImmediateData.u + i,
490                        4, TGSI_IMM_FLOAT32);
491       }
492
493       TXT(" }");
494    }
495
496    EOL();
497
498    return TRUE;
499 }
500
501 void
502 tgsi_dump_declaration(
503    const struct tgsi_full_declaration *decl )
504 {
505    struct dump_ctx ctx;
506
507    ctx.printf = dump_ctx_printf;
508
509    iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
510 }
511
512 static boolean
513 iter_property(
514    struct tgsi_iterate_context *iter,
515    struct tgsi_full_property *prop )
516 {
517    int i;
518    struct dump_ctx *ctx = (struct dump_ctx *)iter;
519
520    assert(Elements(tgsi_property_names) == TGSI_PROPERTY_COUNT);
521
522    TXT( "PROPERTY " );
523    ENM(prop->Property.PropertyName, tgsi_property_names);
524
525    if (prop->Property.NrTokens > 1)
526       TXT(" ");
527
528    for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
529       switch (prop->Property.PropertyName) {
530       case TGSI_PROPERTY_GS_INPUT_PRIM:
531       case TGSI_PROPERTY_GS_OUTPUT_PRIM:
532          ENM(prop->u[i].Data, tgsi_primitive_names);
533          break;
534       case TGSI_PROPERTY_FS_COORD_ORIGIN:
535          ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
536          break;
537       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
538          ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
539          break;
540       default:
541          SID( prop->u[i].Data );
542          break;
543       }
544       if (i < prop->Property.NrTokens - 2)
545          TXT( ", " );
546    }
547    EOL();
548
549    return TRUE;
550 }
551
552 void tgsi_dump_property(
553    const struct tgsi_full_property *prop )
554 {
555    struct dump_ctx ctx;
556
557    ctx.printf = dump_ctx_printf;
558
559    iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
560 }
561
562 static boolean
563 iter_immediate(
564    struct tgsi_iterate_context *iter,
565    struct tgsi_full_immediate *imm )
566 {
567    struct dump_ctx *ctx = (struct dump_ctx *) iter;
568
569    TXT( "IMM " );
570    ENM( imm->Immediate.DataType, immediate_type_names );
571
572    dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
573                  imm->Immediate.DataType);
574
575    EOL();
576
577    return TRUE;
578 }
579
580 void
581 tgsi_dump_immediate(
582    const struct tgsi_full_immediate *imm )
583 {
584    struct dump_ctx ctx;
585
586    ctx.printf = dump_ctx_printf;
587
588    iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
589 }
590
591 static boolean
592 iter_instruction(
593    struct tgsi_iterate_context *iter,
594    struct tgsi_full_instruction *inst )
595 {
596    struct dump_ctx *ctx = (struct dump_ctx *) iter;
597    uint instno = ctx->instno++;
598    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
599    uint i;
600    boolean first_reg = TRUE;
601
602    INSTID( instno );
603    TXT( ": " );
604
605    ctx->indent -= info->pre_dedent;
606    for(i = 0; (int)i < ctx->indent; ++i)
607       TXT( "  " );
608    ctx->indent += info->post_indent;
609
610    if (inst->Instruction.Predicate) {
611       CHR( '(' );
612
613       if (inst->Predicate.Negate)
614          CHR( '!' );
615
616       TXT( "PRED[" );
617       SID( inst->Predicate.Index );
618       CHR( ']' );
619
620       if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
621           inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
622           inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
623           inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
624          CHR( '.' );
625          ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
626          ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
627          ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
628          ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
629       }
630
631       TXT( ") " );
632    }
633
634    TXT( info->mnemonic );
635
636    switch (inst->Instruction.Saturate) {
637    case TGSI_SAT_NONE:
638       break;
639    case TGSI_SAT_ZERO_ONE:
640       TXT( "_SAT" );
641       break;
642    case TGSI_SAT_MINUS_PLUS_ONE:
643       TXT( "_SATNV" );
644       break;
645    default:
646       assert( 0 );
647    }
648
649    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
650       const struct tgsi_full_dst_register *dst = &inst->Dst[i];
651
652       if (!first_reg)
653          CHR( ',' );
654       CHR( ' ' );
655
656       _dump_register_dst( ctx, dst );
657       _dump_writemask( ctx, dst->Register.WriteMask );
658
659       first_reg = FALSE;
660    }
661
662    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
663       const struct tgsi_full_src_register *src = &inst->Src[i];
664
665       if (!first_reg)
666          CHR( ',' );
667       CHR( ' ' );
668
669       if (src->Register.Negate)
670          CHR( '-' );
671       if (src->Register.Absolute)
672          CHR( '|' );
673
674       _dump_register_src(ctx, src);
675
676       if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
677           src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
678           src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
679           src->Register.SwizzleW != TGSI_SWIZZLE_W) {
680          CHR( '.' );
681          ENM( src->Register.SwizzleX, tgsi_swizzle_names );
682          ENM( src->Register.SwizzleY, tgsi_swizzle_names );
683          ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
684          ENM( src->Register.SwizzleW, tgsi_swizzle_names );
685       }
686
687       if (src->Register.Absolute)
688          CHR( '|' );
689
690       first_reg = FALSE;
691    }
692
693    if (inst->Instruction.Texture) {
694       TXT( ", " );
695       ENM( inst->Texture.Texture, tgsi_texture_names );
696    }
697
698    switch (inst->Instruction.Opcode) {
699    case TGSI_OPCODE_IF:
700    case TGSI_OPCODE_ELSE:
701    case TGSI_OPCODE_BGNLOOP:
702    case TGSI_OPCODE_ENDLOOP:
703    case TGSI_OPCODE_CAL:
704       TXT( " :" );
705       UID( inst->Label.Label );
706       break;
707    }
708
709    /* update indentation */
710    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
711        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
712        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
713       ctx->indentation += indent_spaces;
714    }
715
716    EOL();
717
718    return TRUE;
719 }
720
721 void
722 tgsi_dump_instruction(
723    const struct tgsi_full_instruction *inst,
724    uint instno )
725 {
726    struct dump_ctx ctx;
727
728    ctx.instno = instno;
729    ctx.indent = 0;
730    ctx.printf = dump_ctx_printf;
731    ctx.indentation = 0;
732
733    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
734 }
735
736 static boolean
737 prolog(
738    struct tgsi_iterate_context *iter )
739 {
740    struct dump_ctx *ctx = (struct dump_ctx *) iter;
741    ENM( iter->processor.Processor, processor_type_names );
742    EOL();
743    return TRUE;
744 }
745
746 void
747 tgsi_dump(
748    const struct tgsi_token *tokens,
749    uint flags )
750 {
751    struct dump_ctx ctx;
752
753    ctx.iter.prolog = prolog;
754    ctx.iter.iterate_instruction = iter_instruction;
755    ctx.iter.iterate_declaration = iter_declaration;
756    ctx.iter.iterate_immediate = iter_immediate;
757    ctx.iter.iterate_property = iter_property;
758    ctx.iter.epilog = NULL;
759
760    ctx.instno = 0;
761    ctx.indent = 0;
762    ctx.printf = dump_ctx_printf;
763    ctx.indentation = 0;
764
765    tgsi_iterate_shader( tokens, &ctx.iter );
766 }
767
768 struct str_dump_ctx
769 {
770    struct dump_ctx base;
771    char *str;
772    char *ptr;
773    int left;
774 };
775
776 static void
777 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
778 {
779    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
780    
781    if(sctx->left > 1) {
782       int written;
783       va_list ap;
784       va_start(ap, format);
785       written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
786       va_end(ap);
787
788       /* Some complicated logic needed to handle the return value of
789        * vsnprintf:
790        */
791       if (written > 0) {
792          written = MIN2(sctx->left, written);
793          sctx->ptr += written;
794          sctx->left -= written;
795       }
796    }
797 }
798
799 void
800 tgsi_dump_str(
801    const struct tgsi_token *tokens,
802    uint flags,
803    char *str,
804    size_t size)
805 {
806    struct str_dump_ctx ctx;
807
808    ctx.base.iter.prolog = prolog;
809    ctx.base.iter.iterate_instruction = iter_instruction;
810    ctx.base.iter.iterate_declaration = iter_declaration;
811    ctx.base.iter.iterate_immediate = iter_immediate;
812    ctx.base.iter.iterate_property = iter_property;
813    ctx.base.iter.epilog = NULL;
814
815    ctx.base.instno = 0;
816    ctx.base.indent = 0;
817    ctx.base.printf = &str_dump_ctx_printf;
818    ctx.base.indentation = 0;
819
820    ctx.str = str;
821    ctx.str[0] = 0;
822    ctx.ptr = str;
823    ctx.left = (int)size;
824
825    tgsi_iterate_shader( tokens, &ctx.base.iter );
826 }