OSDN Git Service

tgsi: add Stream{X,Y,Z,W} fields to tgsi_declaration_semantic
[android-x86/external-mesa.git] / src / gallium / auxiliary / tgsi / tgsi_dump.c
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 */
40 static const int indent_spaces = 3;
41
42
43 struct 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
59 static void 
60 dump_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
72 static void
73 dump_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
97 const char *
98 tgsi_swizzle_names[4] =
99 {
100    "x",
101    "y",
102    "z",
103    "w"
104 };
105
106 static 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
163 static 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 }
218 static 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
236 static void
237 dump_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_INT64: {
258          union di d;
259          d.i = data[i].Uint | (uint64_t)data[i+1].Uint << 32;
260          UID( d.i );
261          i++;
262          break;
263       }
264       case TGSI_IMM_UINT64: {
265          union di d;
266          d.ui = data[i].Uint | (uint64_t)data[i+1].Uint << 32;
267          UID( d.ui );
268          i++;
269          break;
270       }
271       case TGSI_IMM_FLOAT32:
272          if (ctx->dump_float_as_hex)
273             HFLT( data[i].Float );
274          else
275             FLT( data[i].Float );
276          break;
277       case TGSI_IMM_UINT32:
278          UID(data[i].Uint);
279          break;
280       case TGSI_IMM_INT32:
281          SID(data[i].Int);
282          break;
283       default:
284          assert( 0 );
285       }
286
287       if (i < num_tokens - 1)
288          TXT( ", " );
289    }
290    TXT( "}" );
291 }
292
293 static boolean
294 iter_declaration(
295    struct tgsi_iterate_context *iter,
296    struct tgsi_full_declaration *decl )
297 {
298    struct dump_ctx *ctx = (struct dump_ctx *)iter;
299    boolean patch = decl->Semantic.Name == TGSI_SEMANTIC_PATCH ||
300       decl->Semantic.Name == TGSI_SEMANTIC_TESSINNER ||
301       decl->Semantic.Name == TGSI_SEMANTIC_TESSOUTER ||
302       decl->Semantic.Name == TGSI_SEMANTIC_PRIMID;
303
304    TXT( "DCL " );
305
306    TXT(tgsi_file_name(decl->Declaration.File));
307
308    /* all geometry shader inputs and non-patch tessellation shader inputs are
309     * two dimensional
310     */
311    if (decl->Declaration.File == TGSI_FILE_INPUT &&
312        (iter->processor.Processor == PIPE_SHADER_GEOMETRY ||
313         (!patch &&
314          (iter->processor.Processor == PIPE_SHADER_TESS_CTRL ||
315           iter->processor.Processor == PIPE_SHADER_TESS_EVAL)))) {
316       TXT("[]");
317    }
318
319    /* all non-patch tess ctrl shader outputs are two dimensional */
320    if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
321        !patch &&
322        iter->processor.Processor == PIPE_SHADER_TESS_CTRL) {
323       TXT("[]");
324    }
325
326    if (decl->Declaration.Dimension) {
327       CHR('[');
328       SID(decl->Dim.Index2D);
329       CHR(']');
330    }
331
332    CHR('[');
333    SID(decl->Range.First);
334    if (decl->Range.First != decl->Range.Last) {
335       TXT("..");
336       SID(decl->Range.Last);
337    }
338    CHR(']');
339
340    _dump_writemask(
341       ctx,
342       decl->Declaration.UsageMask );
343
344    if (decl->Declaration.Array) {
345       TXT( ", ARRAY(" );
346       SID(decl->Array.ArrayID);
347       CHR(')');
348    }
349
350    if (decl->Declaration.Local)
351       TXT( ", LOCAL" );
352
353    if (decl->Declaration.Semantic) {
354       TXT( ", " );
355       ENM( decl->Semantic.Name, tgsi_semantic_names );
356       if (decl->Semantic.Index != 0 ||
357           decl->Semantic.Name == TGSI_SEMANTIC_TEXCOORD ||
358           decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
359          CHR( '[' );
360          UID( decl->Semantic.Index );
361          CHR( ']' );
362       }
363
364       if (decl->Semantic.StreamX != 0 || decl->Semantic.StreamY != 0 ||
365           decl->Semantic.StreamZ != 0 || decl->Semantic.StreamW != 0) {
366          TXT(", STREAM(");
367          UID(decl->Semantic.StreamX);
368          TXT(", ");
369          UID(decl->Semantic.StreamY);
370          TXT(", ");
371          UID(decl->Semantic.StreamZ);
372          TXT(", ");
373          UID(decl->Semantic.StreamW);
374          CHR(')');
375       }
376    }
377
378    if (decl->Declaration.File == TGSI_FILE_IMAGE) {
379       TXT(", ");
380       ENM(decl->Image.Resource, tgsi_texture_names);
381       TXT(", ");
382       TXT(util_format_name(decl->Image.Format));
383       if (decl->Image.Writable)
384          TXT(", WR");
385       if (decl->Image.Raw)
386          TXT(", RAW");
387    }
388
389    if (decl->Declaration.File == TGSI_FILE_BUFFER) {
390       if (decl->Declaration.Atomic)
391          TXT(", ATOMIC");
392    }
393
394    if (decl->Declaration.File == TGSI_FILE_MEMORY) {
395       switch (decl->Declaration.MemType) {
396       /* Note: ,GLOBAL is optional / the default */
397       case TGSI_MEMORY_TYPE_GLOBAL:  TXT(", GLOBAL");  break;
398       case TGSI_MEMORY_TYPE_SHARED:  TXT(", SHARED");  break;
399       case TGSI_MEMORY_TYPE_PRIVATE: TXT(", PRIVATE"); break;
400       case TGSI_MEMORY_TYPE_INPUT:   TXT(", INPUT");   break;
401       }
402    }
403
404    if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
405       TXT(", ");
406       ENM(decl->SamplerView.Resource, tgsi_texture_names);
407       TXT(", ");
408       if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) &&
409           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) &&
410           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) {
411          ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names);
412       } else {
413          ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names);
414          TXT(", ");
415          ENM(decl->SamplerView.ReturnTypeY, tgsi_return_type_names);
416          TXT(", ");
417          ENM(decl->SamplerView.ReturnTypeZ, tgsi_return_type_names);
418          TXT(", ");
419          ENM(decl->SamplerView.ReturnTypeW, tgsi_return_type_names);
420       }
421    }
422
423    if (decl->Declaration.Interpolate) {
424       if (iter->processor.Processor == PIPE_SHADER_FRAGMENT &&
425           decl->Declaration.File == TGSI_FILE_INPUT)
426       {
427          TXT( ", " );
428          ENM( decl->Interp.Interpolate, tgsi_interpolate_names );
429       }
430
431       if (decl->Interp.Location != TGSI_INTERPOLATE_LOC_CENTER) {
432          TXT( ", " );
433          ENM( decl->Interp.Location, tgsi_interpolate_locations );
434       }
435
436       if (decl->Interp.CylindricalWrap) {
437          TXT(", CYLWRAP_");
438          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
439             CHR('X');
440          }
441          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
442             CHR('Y');
443          }
444          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
445             CHR('Z');
446          }
447          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
448             CHR('W');
449          }
450       }
451    }
452
453    if (decl->Declaration.Invariant) {
454       TXT( ", INVARIANT" );
455    }
456
457    EOL();
458
459    return TRUE;
460 }
461
462 void
463 tgsi_dump_declaration(
464    const struct tgsi_full_declaration *decl )
465 {
466    struct dump_ctx ctx;
467    memset(&ctx, 0, sizeof(ctx));
468
469    ctx.dump_printf = dump_ctx_printf;
470
471    iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
472 }
473
474 static boolean
475 iter_property(
476    struct tgsi_iterate_context *iter,
477    struct tgsi_full_property *prop )
478 {
479    unsigned i;
480    struct dump_ctx *ctx = (struct dump_ctx *)iter;
481
482    TXT( "PROPERTY " );
483    ENM(prop->Property.PropertyName, tgsi_property_names);
484
485    if (prop->Property.NrTokens > 1)
486       TXT(" ");
487
488    for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
489       switch (prop->Property.PropertyName) {
490       case TGSI_PROPERTY_GS_INPUT_PRIM:
491       case TGSI_PROPERTY_GS_OUTPUT_PRIM:
492          ENM(prop->u[i].Data, tgsi_primitive_names);
493          break;
494       case TGSI_PROPERTY_FS_COORD_ORIGIN:
495          ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
496          break;
497       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
498          ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
499          break;
500       case TGSI_PROPERTY_NEXT_SHADER:
501          ENM(prop->u[i].Data, tgsi_processor_type_names);
502          break;
503       default:
504          SID( prop->u[i].Data );
505          break;
506       }
507       if (i < prop->Property.NrTokens - 2)
508          TXT( ", " );
509    }
510    EOL();
511
512    return TRUE;
513 }
514
515 void tgsi_dump_property(
516    const struct tgsi_full_property *prop )
517 {
518    struct dump_ctx ctx;
519    memset(&ctx, 0, sizeof(ctx));
520
521    ctx.dump_printf = dump_ctx_printf;
522
523    iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
524 }
525
526 static boolean
527 iter_immediate(
528    struct tgsi_iterate_context *iter,
529    struct tgsi_full_immediate *imm )
530 {
531    struct dump_ctx *ctx = (struct dump_ctx *) iter;
532
533    TXT( "IMM[" );
534    SID( ctx->immno++ );
535    TXT( "] " );
536    ENM( imm->Immediate.DataType, tgsi_immediate_type_names );
537
538    dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
539                  imm->Immediate.DataType);
540
541    EOL();
542
543    return TRUE;
544 }
545
546 void
547 tgsi_dump_immediate(
548    const struct tgsi_full_immediate *imm )
549 {
550    struct dump_ctx ctx;
551    memset(&ctx, 0, sizeof(ctx));
552
553    ctx.dump_printf = dump_ctx_printf;
554
555    iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
556 }
557
558 static boolean
559 iter_instruction(
560    struct tgsi_iterate_context *iter,
561    struct tgsi_full_instruction *inst )
562 {
563    struct dump_ctx *ctx = (struct dump_ctx *) iter;
564    uint instno = ctx->instno++;
565    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
566    uint i;
567    boolean first_reg = TRUE;
568
569    INSTID( instno );
570    TXT( ": " );
571
572    ctx->indent -= info->pre_dedent;
573    for(i = 0; (int)i < ctx->indent; ++i)
574       TXT( "  " );
575    ctx->indent += info->post_indent;
576
577    if (inst->Instruction.Predicate) {
578       CHR( '(' );
579
580       if (inst->Predicate.Negate)
581          CHR( '!' );
582
583       TXT( "PRED[" );
584       SID( inst->Predicate.Index );
585       CHR( ']' );
586
587       if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
588           inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
589           inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
590           inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
591          CHR( '.' );
592          ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
593          ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
594          ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
595          ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
596       }
597
598       TXT( ") " );
599    }
600
601    TXT( info->mnemonic );
602
603    if (inst->Instruction.Saturate) {
604       TXT( "_SAT" );
605    }
606
607    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
608       const struct tgsi_full_dst_register *dst = &inst->Dst[i];
609
610       if (!first_reg)
611          CHR( ',' );
612       CHR( ' ' );
613
614       _dump_register_dst( ctx, dst );
615       _dump_writemask( ctx, dst->Register.WriteMask );
616
617       first_reg = FALSE;
618    }
619
620    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
621       const struct tgsi_full_src_register *src = &inst->Src[i];
622
623       if (!first_reg)
624          CHR( ',' );
625       CHR( ' ' );
626
627       if (src->Register.Negate)
628          CHR( '-' );
629       if (src->Register.Absolute)
630          CHR( '|' );
631
632       _dump_register_src(ctx, src);
633
634       if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
635           src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
636           src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
637           src->Register.SwizzleW != TGSI_SWIZZLE_W) {
638          CHR( '.' );
639          ENM( src->Register.SwizzleX, tgsi_swizzle_names );
640          ENM( src->Register.SwizzleY, tgsi_swizzle_names );
641          ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
642          ENM( src->Register.SwizzleW, tgsi_swizzle_names );
643       }
644
645       if (src->Register.Absolute)
646          CHR( '|' );
647
648       first_reg = FALSE;
649    }
650
651    if (inst->Instruction.Texture) {
652       if (!(inst->Instruction.Opcode >= TGSI_OPCODE_SAMPLE &&
653             inst->Instruction.Opcode <= TGSI_OPCODE_GATHER4)) {
654          TXT( ", " );
655          ENM( inst->Texture.Texture, tgsi_texture_names );
656       }
657       for (i = 0; i < inst->Texture.NumOffsets; i++) {
658          TXT( ", " );
659          TXT(tgsi_file_name(inst->TexOffsets[i].File));
660          CHR( '[' );
661          SID( inst->TexOffsets[i].Index );
662          CHR( ']' );
663          CHR( '.' );
664          ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names);
665          ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names);
666          ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names);
667       }
668    }
669
670    if (inst->Instruction.Memory) {
671       uint32_t qualifier = inst->Memory.Qualifier;
672       while (qualifier) {
673          int bit = ffs(qualifier) - 1;
674          qualifier &= ~(1U << bit);
675          TXT(", ");
676          ENM(bit, tgsi_memory_names);
677       }
678       if (inst->Memory.Texture) {
679          TXT( ", " );
680          ENM( inst->Memory.Texture, tgsi_texture_names );
681       }
682       if (inst->Memory.Format) {
683          TXT( ", " );
684          TXT( util_format_name(inst->Memory.Format) );
685       }
686    }
687
688    switch (inst->Instruction.Opcode) {
689    case TGSI_OPCODE_IF:
690    case TGSI_OPCODE_UIF:
691    case TGSI_OPCODE_ELSE:
692    case TGSI_OPCODE_BGNLOOP:
693    case TGSI_OPCODE_ENDLOOP:
694    case TGSI_OPCODE_CAL:
695    case TGSI_OPCODE_BGNSUB:
696       TXT( " :" );
697       UID( inst->Label.Label );
698       break;
699    }
700
701    /* update indentation */
702    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
703        inst->Instruction.Opcode == TGSI_OPCODE_UIF ||
704        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
705        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
706       ctx->indentation += indent_spaces;
707    }
708
709    EOL();
710
711    return TRUE;
712 }
713
714 void
715 tgsi_dump_instruction(
716    const struct tgsi_full_instruction *inst,
717    uint instno )
718 {
719    struct dump_ctx ctx;
720    memset(&ctx, 0, sizeof(ctx));
721
722    ctx.instno = instno;
723    ctx.immno = instno;
724    ctx.indent = 0;
725    ctx.dump_printf = dump_ctx_printf;
726    ctx.indentation = 0;
727    ctx.file = NULL;
728
729    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
730 }
731
732 static boolean
733 prolog(
734    struct tgsi_iterate_context *iter )
735 {
736    struct dump_ctx *ctx = (struct dump_ctx *) iter;
737    ENM( iter->processor.Processor, tgsi_processor_type_names );
738    EOL();
739    return TRUE;
740 }
741
742 static void
743 init_dump_ctx(struct dump_ctx *ctx, uint flags)
744 {
745    memset(ctx, 0, sizeof(*ctx));
746
747    ctx->iter.prolog = prolog;
748    ctx->iter.iterate_instruction = iter_instruction;
749    ctx->iter.iterate_declaration = iter_declaration;
750    ctx->iter.iterate_immediate = iter_immediate;
751    ctx->iter.iterate_property = iter_property;
752
753    if (flags & TGSI_DUMP_FLOAT_AS_HEX)
754       ctx->dump_float_as_hex = TRUE;
755 }
756
757 void
758 tgsi_dump_to_file(const struct tgsi_token *tokens, uint flags, FILE *file)
759 {
760    struct dump_ctx ctx;
761    memset(&ctx, 0, sizeof(ctx));
762
763    init_dump_ctx(&ctx, flags);
764
765    ctx.dump_printf = dump_ctx_printf;
766    ctx.file = file;
767
768    tgsi_iterate_shader( tokens, &ctx.iter );
769 }
770
771 void
772 tgsi_dump(const struct tgsi_token *tokens, uint flags)
773 {
774    tgsi_dump_to_file(tokens, flags, NULL);
775 }
776
777 struct str_dump_ctx
778 {
779    struct dump_ctx base;
780    char *str;
781    char *ptr;
782    int left;
783    bool nospace;
784 };
785
786 static void
787 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
788 {
789    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
790    
791    if (!sctx->nospace) {
792       int written;
793       va_list ap;
794       va_start(ap, format);
795       written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
796       va_end(ap);
797
798       /* Some complicated logic needed to handle the return value of
799        * vsnprintf:
800        */
801       if (written > 0) {
802          if (written >= sctx->left) {
803             sctx->nospace = true;
804             written = sctx->left;
805          }
806          sctx->ptr += written;
807          sctx->left -= written;
808       }
809    }
810 }
811
812 bool
813 tgsi_dump_str(
814    const struct tgsi_token *tokens,
815    uint flags,
816    char *str,
817    size_t size)
818 {
819    struct str_dump_ctx ctx;
820    memset(&ctx, 0, sizeof(ctx));
821
822    init_dump_ctx(&ctx.base, flags);
823
824    ctx.base.dump_printf = &str_dump_ctx_printf;
825
826    ctx.str = str;
827    ctx.str[0] = 0;
828    ctx.ptr = str;
829    ctx.left = (int)size;
830    ctx.nospace = false;
831
832    tgsi_iterate_shader( tokens, &ctx.base.iter );
833
834    return !ctx.nospace;
835 }
836
837 void
838 tgsi_dump_instruction_str(
839    const struct tgsi_full_instruction *inst,
840    uint instno,
841    char *str,
842    size_t size)
843 {
844    struct str_dump_ctx ctx;
845    memset(&ctx, 0, sizeof(ctx));
846
847    ctx.base.instno = instno;
848    ctx.base.immno = instno;
849    ctx.base.indent = 0;
850    ctx.base.dump_printf = &str_dump_ctx_printf;
851    ctx.base.indentation = 0;
852    ctx.base.file = NULL;
853
854    ctx.str = str;
855    ctx.str[0] = 0;
856    ctx.ptr = str;
857    ctx.left = (int)size;
858    ctx.nospace = false;
859
860    iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst );
861 }