xref: /aosp_15_r20/external/virglrenderer/src/gallium/auxiliary/tgsi/tgsi_dump.c (revision bbecb9d118dfdb95f99bd754f8fa9be01f189df3)
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 == TGSI_PROCESSOR_GEOMETRY ||
317         (!patch &&
318          (iter->processor.Processor == TGSI_PROCESSOR_TESS_CTRL ||
319           iter->processor.Processor == TGSI_PROCESSOR_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 == TGSI_PROCESSOR_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 
369    if (decl->Declaration.File == TGSI_FILE_IMAGE) {
370       TXT(", ");
371       ENM(decl->Image.Resource, tgsi_texture_names);
372       TXT(", ");
373       TXT(util_format_name(decl->Image.Format));
374       if (decl->Image.Writable)
375          TXT(", WR");
376       if (decl->Image.Raw)
377          TXT(", RAW");
378    }
379 
380    if (decl->Declaration.File == TGSI_FILE_BUFFER) {
381       if (decl->Declaration.Atomic)
382          TXT(", ATOMIC");
383    }
384 
385    if (decl->Declaration.File == TGSI_FILE_MEMORY) {
386       switch (decl->Declaration.MemType) {
387       /* Note: ,GLOBAL is optional / the default */
388       case TGSI_MEMORY_TYPE_GLOBAL:  TXT(", GLOBAL");  break;
389       case TGSI_MEMORY_TYPE_SHARED:  TXT(", SHARED");  break;
390       case TGSI_MEMORY_TYPE_PRIVATE: TXT(", PRIVATE"); break;
391       case TGSI_MEMORY_TYPE_INPUT:   TXT(", INPUT");   break;
392       }
393    }
394 
395    if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
396       TXT(", ");
397       ENM(decl->SamplerView.Resource, tgsi_texture_names);
398       TXT(", ");
399       if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) &&
400           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) &&
401           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) {
402          ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names);
403       } else {
404          ENM(decl->SamplerView.ReturnTypeX, tgsi_return_type_names);
405          TXT(", ");
406          ENM(decl->SamplerView.ReturnTypeY, tgsi_return_type_names);
407          TXT(", ");
408          ENM(decl->SamplerView.ReturnTypeZ, tgsi_return_type_names);
409          TXT(", ");
410          ENM(decl->SamplerView.ReturnTypeW, tgsi_return_type_names);
411       }
412    }
413 
414    if (decl->Declaration.Interpolate) {
415       if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
416           decl->Declaration.File == TGSI_FILE_INPUT)
417       {
418          TXT( ", " );
419          ENM( decl->Interp.Interpolate, tgsi_interpolate_names );
420       }
421 
422       if (decl->Interp.Location != TGSI_INTERPOLATE_LOC_CENTER) {
423          TXT( ", " );
424          ENM( decl->Interp.Location, tgsi_interpolate_locations );
425       }
426 
427       if (decl->Interp.CylindricalWrap) {
428          TXT(", CYLWRAP_");
429          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
430             CHR('X');
431          }
432          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
433             CHR('Y');
434          }
435          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
436             CHR('Z');
437          }
438          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
439             CHR('W');
440          }
441       }
442    }
443 
444    if (decl->Declaration.Invariant) {
445       TXT( ", INVARIANT" );
446    }
447 
448    EOL();
449 
450    return TRUE;
451 }
452 
453 void
tgsi_dump_declaration(const struct tgsi_full_declaration * decl)454 tgsi_dump_declaration(
455    const struct tgsi_full_declaration *decl )
456 {
457    struct dump_ctx ctx;
458 
459    ctx.dump_printf = dump_ctx_printf;
460 
461    iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
462 }
463 
464 static boolean
iter_property(struct tgsi_iterate_context * iter,struct tgsi_full_property * prop)465 iter_property(
466    struct tgsi_iterate_context *iter,
467    struct tgsi_full_property *prop )
468 {
469    int i;
470    struct dump_ctx *ctx = (struct dump_ctx *)iter;
471 
472    TXT( "PROPERTY " );
473    ENM(prop->Property.PropertyName, tgsi_property_names);
474 
475    if (prop->Property.NrTokens > 1)
476       TXT(" ");
477 
478    for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
479       switch (prop->Property.PropertyName) {
480       case TGSI_PROPERTY_GS_INPUT_PRIM:
481       case TGSI_PROPERTY_GS_OUTPUT_PRIM:
482          ENM(prop->u[i].Data, tgsi_primitive_names);
483          break;
484       case TGSI_PROPERTY_FS_COORD_ORIGIN:
485          ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
486          break;
487       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
488          ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
489          break;
490       default:
491          SID( prop->u[i].Data );
492          break;
493       }
494       if (i < prop->Property.NrTokens - 2)
495          TXT( ", " );
496    }
497    EOL();
498 
499    return TRUE;
500 }
501 
tgsi_dump_property(const struct tgsi_full_property * prop)502 void tgsi_dump_property(
503    const struct tgsi_full_property *prop )
504 {
505    struct dump_ctx ctx;
506 
507    ctx.dump_printf = dump_ctx_printf;
508 
509    iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
510 }
511 
512 static boolean
iter_immediate(struct tgsi_iterate_context * iter,struct tgsi_full_immediate * imm)513 iter_immediate(
514    struct tgsi_iterate_context *iter,
515    struct tgsi_full_immediate *imm )
516 {
517    struct dump_ctx *ctx = (struct dump_ctx *) iter;
518 
519    TXT( "IMM[" );
520    SID( ctx->immno++ );
521    TXT( "] " );
522    ENM( imm->Immediate.DataType, tgsi_immediate_type_names );
523 
524    dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
525                  imm->Immediate.DataType);
526 
527    EOL();
528 
529    return TRUE;
530 }
531 
532 void
tgsi_dump_immediate(const struct tgsi_full_immediate * imm)533 tgsi_dump_immediate(
534    const struct tgsi_full_immediate *imm )
535 {
536    struct dump_ctx ctx;
537 
538    ctx.dump_printf = dump_ctx_printf;
539 
540    iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
541 }
542 
543 static boolean
iter_instruction(struct tgsi_iterate_context * iter,struct tgsi_full_instruction * inst)544 iter_instruction(
545    struct tgsi_iterate_context *iter,
546    struct tgsi_full_instruction *inst )
547 {
548    struct dump_ctx *ctx = (struct dump_ctx *) iter;
549    uint instno = ctx->instno++;
550    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
551    uint i;
552    boolean first_reg = TRUE;
553 
554    INSTID( instno );
555    TXT( ": " );
556 
557    ctx->indent -= info->pre_dedent;
558    for(i = 0; (int)i < ctx->indent; ++i)
559       TXT( "  " );
560    ctx->indent += info->post_indent;
561 
562    TXT( info->mnemonic );
563 
564    if (inst->Instruction.Saturate) {
565       TXT( "_SAT" );
566    }
567 
568    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
569       const struct tgsi_full_dst_register *dst = &inst->Dst[i];
570 
571       if (!first_reg)
572          CHR( ',' );
573       CHR( ' ' );
574 
575       _dump_register_dst( ctx, dst );
576       _dump_writemask( ctx, dst->Register.WriteMask );
577 
578       first_reg = FALSE;
579    }
580 
581    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
582       const struct tgsi_full_src_register *src = &inst->Src[i];
583 
584       if (!first_reg)
585          CHR( ',' );
586       CHR( ' ' );
587 
588       if (src->Register.Negate)
589          CHR( '-' );
590       if (src->Register.Absolute)
591          CHR( '|' );
592 
593       _dump_register_src(ctx, src);
594 
595       if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
596           src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
597           src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
598           src->Register.SwizzleW != TGSI_SWIZZLE_W) {
599          CHR( '.' );
600          ENM( src->Register.SwizzleX, tgsi_swizzle_names );
601          ENM( src->Register.SwizzleY, tgsi_swizzle_names );
602          ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
603          ENM( src->Register.SwizzleW, tgsi_swizzle_names );
604       }
605 
606       if (src->Register.Absolute)
607          CHR( '|' );
608 
609       first_reg = FALSE;
610    }
611 
612    if (inst->Instruction.Texture) {
613       if (!(inst->Instruction.Opcode >= TGSI_OPCODE_SAMPLE &&
614             inst->Instruction.Opcode <= TGSI_OPCODE_GATHER4)) {
615          TXT( ", " );
616          ENM( inst->Texture.Texture, tgsi_texture_names );
617       }
618       for (i = 0; i < inst->Texture.NumOffsets; i++) {
619          TXT( ", " );
620          TXT(tgsi_file_name(inst->TexOffsets[i].File));
621          CHR( '[' );
622          SID( inst->TexOffsets[i].Index );
623          CHR( ']' );
624          CHR( '.' );
625          ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names);
626          ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names);
627          ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names);
628       }
629    }
630 
631    if (inst->Instruction.Memory) {
632       uint32_t qualifier = inst->Memory.Qualifier;
633       while (qualifier) {
634          int bit = ffs(qualifier) - 1;
635          qualifier &= ~(1U << bit);
636          TXT(", ");
637          ENM(bit, tgsi_memory_names);
638       }
639       if (inst->Memory.Texture) {
640          TXT( ", " );
641          ENM( inst->Memory.Texture, tgsi_texture_names );
642       }
643       if (inst->Memory.Format) {
644          TXT( ", " );
645          TXT( util_format_name(inst->Memory.Format) );
646       }
647    }
648 
649    if (inst->Instruction.Label) {
650       switch (inst->Instruction.Opcode) {
651       case TGSI_OPCODE_IF:
652       case TGSI_OPCODE_UIF:
653       case TGSI_OPCODE_ELSE:
654       case TGSI_OPCODE_BGNLOOP:
655       case TGSI_OPCODE_ENDLOOP:
656       case TGSI_OPCODE_CAL:
657       case TGSI_OPCODE_BGNSUB:
658          TXT( " :" );
659          UID( inst->Label.Label );
660          break;
661       }
662    }
663 
664    /* update indentation */
665    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
666        inst->Instruction.Opcode == TGSI_OPCODE_UIF ||
667        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
668        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
669       ctx->indentation += indent_spaces;
670    }
671 
672    EOL();
673 
674    return TRUE;
675 }
676 
677 void
tgsi_dump_instruction(const struct tgsi_full_instruction * inst,uint instno)678 tgsi_dump_instruction(
679    const struct tgsi_full_instruction *inst,
680    uint instno )
681 {
682    struct dump_ctx ctx;
683 
684    ctx.instno = instno;
685    ctx.immno = instno;
686    ctx.indent = 0;
687    ctx.dump_printf = dump_ctx_printf;
688    ctx.indentation = 0;
689    ctx.file = NULL;
690 
691    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
692 }
693 
694 static boolean
prolog(struct tgsi_iterate_context * iter)695 prolog(
696    struct tgsi_iterate_context *iter )
697 {
698    struct dump_ctx *ctx = (struct dump_ctx *) iter;
699    ENM( iter->processor.Processor, tgsi_processor_type_names );
700    EOL();
701    return TRUE;
702 }
703 
704 void
tgsi_dump_to_file(const struct tgsi_token * tokens,uint flags,FILE * file)705 tgsi_dump_to_file(const struct tgsi_token *tokens, uint flags, FILE *file)
706 {
707    struct dump_ctx ctx;
708 
709    ctx.iter.prolog = prolog;
710    ctx.iter.iterate_instruction = iter_instruction;
711    ctx.iter.iterate_declaration = iter_declaration;
712    ctx.iter.iterate_immediate = iter_immediate;
713    ctx.iter.iterate_property = iter_property;
714    ctx.iter.epilog = NULL;
715 
716    ctx.instno = 0;
717    ctx.immno = 0;
718    ctx.indent = 0;
719    ctx.dump_printf = dump_ctx_printf;
720    ctx.indentation = 0;
721    ctx.file = file;
722 
723    if (flags & TGSI_DUMP_FLOAT_AS_HEX)
724       ctx.dump_float_as_hex = TRUE;
725    else
726       ctx.dump_float_as_hex = FALSE;
727 
728    tgsi_iterate_shader( tokens, &ctx.iter );
729 }
730 
731 void
tgsi_dump(const struct tgsi_token * tokens,uint flags)732 tgsi_dump(const struct tgsi_token *tokens, uint flags)
733 {
734    tgsi_dump_to_file(tokens, flags, NULL);
735 }
736 
737 struct str_dump_ctx
738 {
739    struct dump_ctx base;
740    char *str;
741    char *ptr;
742    int left;
743    bool nospace;
744 };
745 
746 static void
str_dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)747 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
748 {
749    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
750 
751    if(sctx->left > 1) {
752       int written;
753       va_list ap;
754       va_start(ap, format);
755       written = vsnprintf(sctx->ptr, sctx->left, format, ap);
756       va_end(ap);
757 
758       /* Some complicated logic needed to handle the return value of
759        * vsnprintf:
760        */
761       if (written > 0) {
762          written = MIN2(sctx->left, written);
763          sctx->ptr += written;
764          sctx->left -= written;
765       }
766    } else
767       sctx->nospace = true;
768 }
769 
770 bool
tgsi_dump_str(const struct tgsi_token * tokens,uint flags,char * str,size_t size)771 tgsi_dump_str(
772    const struct tgsi_token *tokens,
773    uint flags,
774    char *str,
775    size_t size)
776 {
777    struct str_dump_ctx ctx;
778 
779    ctx.base.iter.prolog = prolog;
780    ctx.base.iter.iterate_instruction = iter_instruction;
781    ctx.base.iter.iterate_declaration = iter_declaration;
782    ctx.base.iter.iterate_immediate = iter_immediate;
783    ctx.base.iter.iterate_property = iter_property;
784    ctx.base.iter.epilog = NULL;
785 
786    ctx.base.instno = 0;
787    ctx.base.immno = 0;
788    ctx.base.indent = 0;
789    ctx.base.dump_printf = &str_dump_ctx_printf;
790    ctx.base.indentation = 0;
791    ctx.base.file = NULL;
792 
793    ctx.str = str;
794    ctx.str[0] = 0;
795    ctx.ptr = str;
796    ctx.left = (int)size;
797    ctx.nospace = false;
798 
799    if (flags & TGSI_DUMP_FLOAT_AS_HEX)
800       ctx.base.dump_float_as_hex = TRUE;
801    else
802       ctx.base.dump_float_as_hex = FALSE;
803 
804    tgsi_iterate_shader( tokens, &ctx.base.iter );
805 
806    return !ctx.nospace;
807 }
808 
809 void
tgsi_dump_instruction_str(const struct tgsi_full_instruction * inst,uint instno,char * str,size_t size)810 tgsi_dump_instruction_str(
811    const struct tgsi_full_instruction *inst,
812    uint instno,
813    char *str,
814    size_t size)
815 {
816    struct str_dump_ctx ctx;
817 
818    ctx.base.instno = instno;
819    ctx.base.immno = instno;
820    ctx.base.indent = 0;
821    ctx.base.dump_printf = &str_dump_ctx_printf;
822    ctx.base.indentation = 0;
823    ctx.base.file = NULL;
824 
825    ctx.str = str;
826    ctx.str[0] = 0;
827    ctx.ptr = str;
828    ctx.left = (int)size;
829    ctx.nospace = false;
830 
831    iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst );
832 }
833