• 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 "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
dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)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
dump_enum(struct dump_ctx * ctx,uint e,const char ** enums,uint enum_count)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
_dump_register_src(struct dump_ctx * ctx,const struct tgsi_full_src_register * src)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
_dump_register_dst(struct dump_ctx * ctx,const struct tgsi_full_dst_register * dst)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
_dump_writemask(struct dump_ctx * ctx,uint writemask)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
dump_imm_data(struct tgsi_iterate_context * iter,union tgsi_immediate_data * data,unsigned num_tokens,unsigned data_type)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
iter_declaration(struct tgsi_iterate_context * iter,struct tgsi_full_declaration * decl)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
tgsi_dump_declaration(const struct tgsi_full_declaration * decl)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
iter_property(struct tgsi_iterate_context * iter,struct tgsi_full_property * prop)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 
tgsi_dump_property(const struct tgsi_full_property * prop)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
iter_immediate(struct tgsi_iterate_context * iter,struct tgsi_full_immediate * imm)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
tgsi_dump_immediate(const struct tgsi_full_immediate * imm)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
iter_instruction(struct tgsi_iterate_context * iter,struct tgsi_full_instruction * inst)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    if (inst->Instruction.Label) {
689       switch (inst->Instruction.Opcode) {
690       case TGSI_OPCODE_IF:
691       case TGSI_OPCODE_UIF:
692       case TGSI_OPCODE_ELSE:
693       case TGSI_OPCODE_BGNLOOP:
694       case TGSI_OPCODE_ENDLOOP:
695       case TGSI_OPCODE_CAL:
696       case TGSI_OPCODE_BGNSUB:
697          TXT( " :" );
698          UID( inst->Label.Label );
699          break;
700       }
701    }
702 
703    /* update indentation */
704    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
705        inst->Instruction.Opcode == TGSI_OPCODE_UIF ||
706        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
707        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
708       ctx->indentation += indent_spaces;
709    }
710 
711    EOL();
712 
713    return TRUE;
714 }
715 
716 void
tgsi_dump_instruction(const struct tgsi_full_instruction * inst,uint instno)717 tgsi_dump_instruction(
718    const struct tgsi_full_instruction *inst,
719    uint instno )
720 {
721    struct dump_ctx ctx;
722    memset(&ctx, 0, sizeof(ctx));
723 
724    ctx.instno = instno;
725    ctx.immno = instno;
726    ctx.indent = 0;
727    ctx.dump_printf = dump_ctx_printf;
728    ctx.indentation = 0;
729    ctx.file = NULL;
730 
731    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
732 }
733 
734 static boolean
prolog(struct tgsi_iterate_context * iter)735 prolog(
736    struct tgsi_iterate_context *iter )
737 {
738    struct dump_ctx *ctx = (struct dump_ctx *) iter;
739    ENM( iter->processor.Processor, tgsi_processor_type_names );
740    EOL();
741    return TRUE;
742 }
743 
744 static void
init_dump_ctx(struct dump_ctx * ctx,uint flags)745 init_dump_ctx(struct dump_ctx *ctx, uint flags)
746 {
747    memset(ctx, 0, sizeof(*ctx));
748 
749    ctx->iter.prolog = prolog;
750    ctx->iter.iterate_instruction = iter_instruction;
751    ctx->iter.iterate_declaration = iter_declaration;
752    ctx->iter.iterate_immediate = iter_immediate;
753    ctx->iter.iterate_property = iter_property;
754 
755    if (flags & TGSI_DUMP_FLOAT_AS_HEX)
756       ctx->dump_float_as_hex = TRUE;
757 }
758 
759 void
tgsi_dump_to_file(const struct tgsi_token * tokens,uint flags,FILE * file)760 tgsi_dump_to_file(const struct tgsi_token *tokens, uint flags, FILE *file)
761 {
762    struct dump_ctx ctx;
763    memset(&ctx, 0, sizeof(ctx));
764 
765    init_dump_ctx(&ctx, flags);
766 
767    ctx.dump_printf = dump_ctx_printf;
768    ctx.file = file;
769 
770    tgsi_iterate_shader( tokens, &ctx.iter );
771 }
772 
773 void
tgsi_dump(const struct tgsi_token * tokens,uint flags)774 tgsi_dump(const struct tgsi_token *tokens, uint flags)
775 {
776    tgsi_dump_to_file(tokens, flags, NULL);
777 }
778 
779 struct str_dump_ctx
780 {
781    struct dump_ctx base;
782    char *str;
783    char *ptr;
784    int left;
785    bool nospace;
786 };
787 
788 static void
str_dump_ctx_printf(struct dump_ctx * ctx,const char * format,...)789 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
790 {
791    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
792 
793    if (!sctx->nospace) {
794       int written;
795       va_list ap;
796       va_start(ap, format);
797       written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
798       va_end(ap);
799 
800       /* Some complicated logic needed to handle the return value of
801        * vsnprintf:
802        */
803       if (written > 0) {
804          if (written >= sctx->left) {
805             sctx->nospace = true;
806             written = sctx->left;
807          }
808          sctx->ptr += written;
809          sctx->left -= written;
810       }
811    }
812 }
813 
814 bool
tgsi_dump_str(const struct tgsi_token * tokens,uint flags,char * str,size_t size)815 tgsi_dump_str(
816    const struct tgsi_token *tokens,
817    uint flags,
818    char *str,
819    size_t size)
820 {
821    struct str_dump_ctx ctx;
822    memset(&ctx, 0, sizeof(ctx));
823 
824    init_dump_ctx(&ctx.base, flags);
825 
826    ctx.base.dump_printf = &str_dump_ctx_printf;
827 
828    ctx.str = str;
829    ctx.str[0] = 0;
830    ctx.ptr = str;
831    ctx.left = (int)size;
832    ctx.nospace = false;
833 
834    tgsi_iterate_shader( tokens, &ctx.base.iter );
835 
836    return !ctx.nospace;
837 }
838 
839 void
tgsi_dump_instruction_str(const struct tgsi_full_instruction * inst,uint instno,char * str,size_t size)840 tgsi_dump_instruction_str(
841    const struct tgsi_full_instruction *inst,
842    uint instno,
843    char *str,
844    size_t size)
845 {
846    struct str_dump_ctx ctx;
847    memset(&ctx, 0, sizeof(ctx));
848 
849    ctx.base.instno = instno;
850    ctx.base.immno = instno;
851    ctx.base.indent = 0;
852    ctx.base.dump_printf = &str_dump_ctx_printf;
853    ctx.base.indentation = 0;
854    ctx.base.file = NULL;
855 
856    ctx.str = str;
857    ctx.str[0] = 0;
858    ctx.ptr = str;
859    ctx.left = (int)size;
860    ctx.nospace = false;
861 
862    iter_instruction( &ctx.base.iter, (struct tgsi_full_instruction *)inst );
863 }
864