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