xref: /aosp_15_r20/external/mesa3d/src/gallium/auxiliary/tgsi/tgsi_dump.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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    bool dump_float_as_hex;
50 
51    unsigned instno;
52    unsigned immno;
53    int indent;
54 
55    unsigned 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,unsigned e,const char ** enums,unsigned enum_count)75 dump_enum(
76    struct dump_ctx *ctx,
77    unsigned e,
78    const char **enums,
79    unsigned 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,unsigned writemask)223 _dump_writemask(
224    struct dump_ctx *ctx,
225    unsigned 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 bool
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    bool 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 static bool
iter_property(struct tgsi_iterate_context * iter,struct tgsi_full_property * prop)451 iter_property(
452    struct tgsi_iterate_context *iter,
453    struct tgsi_full_property *prop )
454 {
455    int i;
456    struct dump_ctx *ctx = (struct dump_ctx *)iter;
457 
458    TXT( "PROPERTY " );
459    ENM(prop->Property.PropertyName, tgsi_property_names);
460 
461    if (prop->Property.NrTokens > 1)
462       TXT(" ");
463 
464    for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
465       switch (prop->Property.PropertyName) {
466       case TGSI_PROPERTY_GS_INPUT_PRIM:
467       case TGSI_PROPERTY_GS_OUTPUT_PRIM:
468          ENM(prop->u[i].Data, tgsi_primitive_names);
469          break;
470       case TGSI_PROPERTY_FS_COORD_ORIGIN:
471          ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
472          break;
473       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
474          ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
475          break;
476       case TGSI_PROPERTY_NEXT_SHADER:
477          ENM(prop->u[i].Data, tgsi_processor_type_names);
478          break;
479       default:
480          SID( prop->u[i].Data );
481          break;
482       }
483       if (i < prop->Property.NrTokens - 2)
484          TXT( ", " );
485    }
486    EOL();
487 
488    return true;
489 }
490 
491 static bool
iter_immediate(struct tgsi_iterate_context * iter,struct tgsi_full_immediate * imm)492 iter_immediate(
493    struct tgsi_iterate_context *iter,
494    struct tgsi_full_immediate *imm )
495 {
496    struct dump_ctx *ctx = (struct dump_ctx *) iter;
497 
498    TXT( "IMM[" );
499    SID( ctx->immno++ );
500    TXT( "] " );
501    ENM( imm->Immediate.DataType, tgsi_immediate_type_names );
502 
503    dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
504                  imm->Immediate.DataType);
505 
506    EOL();
507 
508    return true;
509 }
510 
511 static bool
iter_instruction(struct tgsi_iterate_context * iter,struct tgsi_full_instruction * inst)512 iter_instruction(
513    struct tgsi_iterate_context *iter,
514    struct tgsi_full_instruction *inst )
515 {
516    struct dump_ctx *ctx = (struct dump_ctx *) iter;
517    unsigned instno = ctx->instno++;
518    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
519    unsigned i;
520    bool first_reg = true;
521 
522    INSTID( instno );
523    TXT( ": " );
524 
525    ctx->indent -= info->pre_dedent;
526    for(i = 0; (int)i < ctx->indent; ++i)
527       TXT( "  " );
528    ctx->indent += info->post_indent;
529 
530    TXT( tgsi_get_opcode_name(inst->Instruction.Opcode) );
531 
532    if (inst->Instruction.Saturate) {
533       TXT( "_SAT" );
534    }
535 
536    if (inst->Instruction.Precise) {
537       TXT( "_PRECISE" );
538    }
539 
540    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
541       const struct tgsi_full_dst_register *dst = &inst->Dst[i];
542 
543       if (!first_reg)
544          CHR( ',' );
545       CHR( ' ' );
546 
547       _dump_register_dst( ctx, dst );
548       _dump_writemask( ctx, dst->Register.WriteMask );
549 
550       first_reg = false;
551    }
552 
553    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
554       const struct tgsi_full_src_register *src = &inst->Src[i];
555 
556       if (!first_reg)
557          CHR( ',' );
558       CHR( ' ' );
559 
560       if (src->Register.Negate)
561          CHR( '-' );
562       if (src->Register.Absolute)
563          CHR( '|' );
564 
565       _dump_register_src(ctx, src);
566 
567       if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
568           src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
569           src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
570           src->Register.SwizzleW != TGSI_SWIZZLE_W) {
571          CHR( '.' );
572          ENM( src->Register.SwizzleX, tgsi_swizzle_names );
573          ENM( src->Register.SwizzleY, tgsi_swizzle_names );
574          ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
575          ENM( src->Register.SwizzleW, tgsi_swizzle_names );
576       }
577 
578       if (src->Register.Absolute)
579          CHR( '|' );
580 
581       first_reg = false;
582    }
583 
584    if (inst->Instruction.Texture) {
585       if (!(inst->Instruction.Opcode >= TGSI_OPCODE_SAMPLE &&
586             inst->Instruction.Opcode <= TGSI_OPCODE_GATHER4)) {
587          TXT( ", " );
588          ENM( inst->Texture.Texture, tgsi_texture_names );
589       }
590       for (i = 0; i < inst->Texture.NumOffsets; i++) {
591          TXT( ", " );
592          TXT(tgsi_file_name(inst->TexOffsets[i].File));
593          CHR( '[' );
594          SID( inst->TexOffsets[i].Index );
595          CHR( ']' );
596          CHR( '.' );
597          ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names);
598          ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names);
599          ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names);
600       }
601    }
602 
603    if (inst->Instruction.Memory) {
604       uint32_t qualifier = inst->Memory.Qualifier;
605       while (qualifier) {
606          int bit = ffs(qualifier) - 1;
607          qualifier &= ~(1U << bit);
608          TXT(", ");
609          ENM(bit, tgsi_memory_names);
610       }
611       if (inst->Memory.Texture) {
612          TXT( ", " );
613          ENM( inst->Memory.Texture, tgsi_texture_names );
614       }
615       if (inst->Memory.Format) {
616          TXT( ", " );
617          TXT( util_format_name(inst->Memory.Format) );
618       }
619    }
620 
621    if (inst->Instruction.Label) {
622       switch (inst->Instruction.Opcode) {
623       case TGSI_OPCODE_IF:
624       case TGSI_OPCODE_UIF:
625       case TGSI_OPCODE_ELSE:
626       case TGSI_OPCODE_BGNLOOP:
627       case TGSI_OPCODE_ENDLOOP:
628       case TGSI_OPCODE_CAL:
629       case TGSI_OPCODE_BGNSUB:
630          TXT( " :" );
631          UID( inst->Label.Label );
632          break;
633       }
634    }
635 
636    /* update indentation */
637    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
638        inst->Instruction.Opcode == TGSI_OPCODE_UIF ||
639        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
640        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
641       ctx->indentation += indent_spaces;
642    }
643 
644    EOL();
645 
646    return true;
647 }
648 
649 void
tgsi_dump_instruction(const struct tgsi_full_instruction * inst,unsigned instno)650 tgsi_dump_instruction(
651    const struct tgsi_full_instruction *inst,
652    unsigned instno )
653 {
654    struct dump_ctx ctx;
655    memset(&ctx, 0, sizeof(ctx));
656 
657    ctx.instno = instno;
658    ctx.immno = instno;
659    ctx.indent = 0;
660    ctx.dump_printf = dump_ctx_printf;
661    ctx.indentation = 0;
662    ctx.file = NULL;
663 
664    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
665 }
666 
667 static bool
prolog(struct tgsi_iterate_context * iter)668 prolog(
669    struct tgsi_iterate_context *iter )
670 {
671    struct dump_ctx *ctx = (struct dump_ctx *) iter;
672    ENM( iter->processor.Processor, tgsi_processor_type_names );
673    EOL();
674    return true;
675 }
676 
677 static void
init_dump_ctx(struct dump_ctx * ctx,unsigned flags)678 init_dump_ctx(struct dump_ctx *ctx, unsigned flags)
679 {
680    memset(ctx, 0, sizeof(*ctx));
681 
682    ctx->iter.prolog = prolog;
683    ctx->iter.iterate_instruction = iter_instruction;
684    ctx->iter.iterate_declaration = iter_declaration;
685    ctx->iter.iterate_immediate = iter_immediate;
686    ctx->iter.iterate_property = iter_property;
687 
688    if (flags & TGSI_DUMP_FLOAT_AS_HEX)
689       ctx->dump_float_as_hex = true;
690 }
691 
692 void
tgsi_dump_to_file(const struct tgsi_token * tokens,unsigned flags,FILE * file)693 tgsi_dump_to_file(const struct tgsi_token *tokens, unsigned flags, FILE *file)
694 {
695    struct dump_ctx ctx;
696    memset(&ctx, 0, sizeof(ctx));
697 
698    init_dump_ctx(&ctx, flags);
699 
700    ctx.dump_printf = dump_ctx_printf;
701    ctx.file = file;
702 
703    tgsi_iterate_shader( tokens, &ctx.iter );
704 }
705 
706 void
tgsi_dump(const struct tgsi_token * tokens,unsigned flags)707 tgsi_dump(const struct tgsi_token *tokens, unsigned flags)
708 {
709    tgsi_dump_to_file(tokens, flags, NULL);
710 }
711 
712 struct str_dump_ctx
713 {
714    struct dump_ctx base;
715    char *str;
716    char *ptr;
717    int left;
718    bool nospace;
719 };
720 
721 static void
str_dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)722 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
723 {
724    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
725 
726    if (!sctx->nospace) {
727       int written;
728       va_list ap;
729       va_start(ap, format);
730       written = vsnprintf(sctx->ptr, sctx->left, format, ap);
731       va_end(ap);
732 
733       /* Some complicated logic needed to handle the return value of
734        * vsnprintf:
735        */
736       if (written > 0) {
737          if (written >= sctx->left) {
738             sctx->nospace = true;
739             written = sctx->left;
740          }
741          sctx->ptr += written;
742          sctx->left -= written;
743       }
744    }
745 }
746 
747 bool
tgsi_dump_str(const struct tgsi_token * tokens,unsigned flags,char * str,size_t size)748 tgsi_dump_str(
749    const struct tgsi_token *tokens,
750    unsigned flags,
751    char *str,
752    size_t size)
753 {
754    struct str_dump_ctx ctx;
755    memset(&ctx, 0, sizeof(ctx));
756 
757    init_dump_ctx(&ctx.base, flags);
758 
759    ctx.base.dump_printf = &str_dump_ctx_printf;
760 
761    ctx.str = str;
762    ctx.str[0] = 0;
763    ctx.ptr = str;
764    ctx.left = (int)size;
765    ctx.nospace = false;
766 
767    tgsi_iterate_shader( tokens, &ctx.base.iter );
768 
769    return !ctx.nospace;
770 }
771 
772 void
tgsi_dump_instruction_str(const struct tgsi_full_instruction * inst,unsigned instno,char * str,size_t size)773 tgsi_dump_instruction_str(
774    const struct tgsi_full_instruction *inst,
775    unsigned instno,
776    char *str,
777    size_t size)
778 {
779    struct str_dump_ctx ctx;
780    memset(&ctx, 0, sizeof(ctx));
781 
782    ctx.base.instno = instno;
783    ctx.base.immno = instno;
784    ctx.base.indent = 0;
785    ctx.base.dump_printf = &str_dump_ctx_printf;
786    ctx.base.indentation = 0;
787    ctx.base.file = NULL;
788 
789    ctx.str = str;
790    ctx.str[0] = 0;
791    ctx.ptr = str;
792    ctx.left = (int)size;
793    ctx.nospace = false;
794 
795    iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst );
796 }
797