Home | History | Annotate | Download | only in tgsi
      1 /**************************************************************************
      2  *
      3  * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      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 TUNGSTEN GRAPHICS 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 "tgsi_dump.h"
     33 #include "tgsi_info.h"
     34 #include "tgsi_iterate.h"
     35 #include "tgsi_strings.h"
     36 
     37 
     38 /** Number of spaces to indent for IF/LOOP/etc */
     39 static const int indent_spaces = 3;
     40 
     41 
     42 struct dump_ctx
     43 {
     44    struct tgsi_iterate_context iter;
     45 
     46    uint instno;
     47    int indent;
     48 
     49    uint indentation;
     50 
     51    void (*dump_printf)(struct dump_ctx *ctx, const char *format, ...);
     52 };
     53 
     54 static void
     55 dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
     56 {
     57    va_list ap;
     58    (void)ctx;
     59    va_start(ap, format);
     60    _debug_vprintf(format, ap);
     61    va_end(ap);
     62 }
     63 
     64 static void
     65 dump_enum(
     66    struct dump_ctx *ctx,
     67    uint e,
     68    const char **enums,
     69    uint enum_count )
     70 {
     71    if (e >= enum_count)
     72       ctx->dump_printf( ctx, "%u", e );
     73    else
     74       ctx->dump_printf( ctx, "%s", enums[e] );
     75 }
     76 
     77 #define EOL()           ctx->dump_printf( ctx, "\n" )
     78 #define TXT(S)          ctx->dump_printf( ctx, "%s", S )
     79 #define CHR(C)          ctx->dump_printf( ctx, "%c", C )
     80 #define UIX(I)          ctx->dump_printf( ctx, "0x%x", I )
     81 #define UID(I)          ctx->dump_printf( ctx, "%u", I )
     82 #define INSTID(I)       ctx->dump_printf( ctx, "% 3u", I )
     83 #define SID(I)          ctx->dump_printf( ctx, "%d", I )
     84 #define FLT(F)          ctx->dump_printf( ctx, "%10.4f", F )
     85 #define ENM(E,ENUMS)    dump_enum( ctx, E, ENUMS, sizeof( ENUMS ) / sizeof( *ENUMS ) )
     86 
     87 const char *
     88 tgsi_swizzle_names[4] =
     89 {
     90    "x",
     91    "y",
     92    "z",
     93    "w"
     94 };
     95 
     96 static void
     97 _dump_register_src(
     98    struct dump_ctx *ctx,
     99    const struct tgsi_full_src_register *src )
    100 {
    101    ENM(src->Register.File, tgsi_file_names);
    102    if (src->Register.Dimension) {
    103       if (src->Dimension.Indirect) {
    104          CHR( '[' );
    105          ENM( src->DimIndirect.File, tgsi_file_names );
    106          CHR( '[' );
    107          SID( src->DimIndirect.Index );
    108          TXT( "]." );
    109          ENM( src->DimIndirect.SwizzleX, tgsi_swizzle_names );
    110          if (src->Dimension.Index != 0) {
    111             if (src->Dimension.Index > 0)
    112                CHR( '+' );
    113             SID( src->Dimension.Index );
    114          }
    115          CHR( ']' );
    116       } else {
    117          CHR('[');
    118          SID(src->Dimension.Index);
    119          CHR(']');
    120       }
    121    }
    122    if (src->Register.Indirect) {
    123       CHR( '[' );
    124       ENM( src->Indirect.File, tgsi_file_names );
    125       CHR( '[' );
    126       SID( src->Indirect.Index );
    127       TXT( "]." );
    128       ENM( src->Indirect.SwizzleX, tgsi_swizzle_names );
    129       if (src->Register.Index != 0) {
    130          if (src->Register.Index > 0)
    131             CHR( '+' );
    132          SID( src->Register.Index );
    133       }
    134       CHR( ']' );
    135    } else {
    136       CHR( '[' );
    137       SID( src->Register.Index );
    138       CHR( ']' );
    139    }
    140 }
    141 
    142 
    143 static void
    144 _dump_register_dst(
    145    struct dump_ctx *ctx,
    146    const struct tgsi_full_dst_register *dst )
    147 {
    148    ENM(dst->Register.File, tgsi_file_names);
    149    if (dst->Register.Dimension) {
    150       if (dst->Dimension.Indirect) {
    151          CHR( '[' );
    152          ENM( dst->DimIndirect.File, tgsi_file_names );
    153          CHR( '[' );
    154          SID( dst->DimIndirect.Index );
    155          TXT( "]." );
    156          ENM( dst->DimIndirect.SwizzleX, tgsi_swizzle_names );
    157          if (dst->Dimension.Index != 0) {
    158             if (dst->Dimension.Index > 0)
    159                CHR( '+' );
    160             SID( dst->Dimension.Index );
    161          }
    162          CHR( ']' );
    163       } else {
    164          CHR('[');
    165          SID(dst->Dimension.Index);
    166          CHR(']');
    167       }
    168    }
    169    if (dst->Register.Indirect) {
    170       CHR( '[' );
    171       ENM( dst->Indirect.File, tgsi_file_names );
    172       CHR( '[' );
    173       SID( dst->Indirect.Index );
    174       TXT( "]." );
    175       ENM( dst->Indirect.SwizzleX, tgsi_swizzle_names );
    176       if (dst->Register.Index != 0) {
    177          if (dst->Register.Index > 0)
    178             CHR( '+' );
    179          SID( dst->Register.Index );
    180       }
    181       CHR( ']' );
    182    } else {
    183       CHR( '[' );
    184       SID( dst->Register.Index );
    185       CHR( ']' );
    186    }
    187 }
    188 static void
    189 _dump_writemask(
    190    struct dump_ctx *ctx,
    191    uint writemask )
    192 {
    193    if (writemask != TGSI_WRITEMASK_XYZW) {
    194       CHR( '.' );
    195       if (writemask & TGSI_WRITEMASK_X)
    196          CHR( 'x' );
    197       if (writemask & TGSI_WRITEMASK_Y)
    198          CHR( 'y' );
    199       if (writemask & TGSI_WRITEMASK_Z)
    200          CHR( 'z' );
    201       if (writemask & TGSI_WRITEMASK_W)
    202          CHR( 'w' );
    203    }
    204 }
    205 
    206 static void
    207 dump_imm_data(struct tgsi_iterate_context *iter,
    208               union tgsi_immediate_data *data,
    209               unsigned num_tokens,
    210               unsigned data_type)
    211 {
    212    struct dump_ctx *ctx = (struct dump_ctx *)iter;
    213    unsigned i ;
    214 
    215    TXT( " {" );
    216 
    217    assert( num_tokens <= 4 );
    218    for (i = 0; i < num_tokens; i++) {
    219       switch (data_type) {
    220       case TGSI_IMM_FLOAT32:
    221          FLT( data[i].Float );
    222          break;
    223       case TGSI_IMM_UINT32:
    224          UID(data[i].Uint);
    225          break;
    226       case TGSI_IMM_INT32:
    227          SID(data[i].Int);
    228          break;
    229       default:
    230          assert( 0 );
    231       }
    232 
    233       if (i < num_tokens - 1)
    234          TXT( ", " );
    235    }
    236    TXT( "}" );
    237 }
    238 
    239 static boolean
    240 iter_declaration(
    241    struct tgsi_iterate_context *iter,
    242    struct tgsi_full_declaration *decl )
    243 {
    244    struct dump_ctx *ctx = (struct dump_ctx *)iter;
    245 
    246    TXT( "DCL " );
    247 
    248    ENM(decl->Declaration.File, tgsi_file_names);
    249 
    250    /* all geometry shader inputs are two dimensional */
    251    if (decl->Declaration.File == TGSI_FILE_INPUT &&
    252        iter->processor.Processor == TGSI_PROCESSOR_GEOMETRY) {
    253       TXT("[]");
    254    }
    255 
    256    if (decl->Declaration.Dimension) {
    257       CHR('[');
    258       SID(decl->Dim.Index2D);
    259       CHR(']');
    260    }
    261 
    262    CHR('[');
    263    SID(decl->Range.First);
    264    if (decl->Range.First != decl->Range.Last) {
    265       TXT("..");
    266       SID(decl->Range.Last);
    267    }
    268    CHR(']');
    269 
    270    _dump_writemask(
    271       ctx,
    272       decl->Declaration.UsageMask );
    273 
    274    if (decl->Declaration.Local)
    275       TXT( ", LOCAL" );
    276 
    277    if (decl->Declaration.Semantic) {
    278       TXT( ", " );
    279       ENM( decl->Semantic.Name, tgsi_semantic_names );
    280       if (decl->Semantic.Index != 0 ||
    281           decl->Semantic.Name == TGSI_SEMANTIC_GENERIC) {
    282          CHR( '[' );
    283          UID( decl->Semantic.Index );
    284          CHR( ']' );
    285       }
    286    }
    287 
    288    if (decl->Declaration.File == TGSI_FILE_RESOURCE) {
    289       TXT(", ");
    290       ENM(decl->Resource.Resource, tgsi_texture_names);
    291       if (decl->Resource.Writable)
    292          TXT(", WR");
    293       if (decl->Resource.Raw)
    294          TXT(", RAW");
    295    }
    296 
    297    if (decl->Declaration.File == TGSI_FILE_SAMPLER_VIEW) {
    298       TXT(", ");
    299       ENM(decl->SamplerView.Resource, tgsi_texture_names);
    300       TXT(", ");
    301       if ((decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeY) &&
    302           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeZ) &&
    303           (decl->SamplerView.ReturnTypeX == decl->SamplerView.ReturnTypeW)) {
    304          ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names);
    305       } else {
    306          ENM(decl->SamplerView.ReturnTypeX, tgsi_type_names);
    307          TXT(", ");
    308          ENM(decl->SamplerView.ReturnTypeY, tgsi_type_names);
    309          TXT(", ");
    310          ENM(decl->SamplerView.ReturnTypeZ, tgsi_type_names);
    311          TXT(", ");
    312          ENM(decl->SamplerView.ReturnTypeW, tgsi_type_names);
    313       }
    314    }
    315 
    316    if (decl->Declaration.Interpolate) {
    317       if (iter->processor.Processor == TGSI_PROCESSOR_FRAGMENT &&
    318           decl->Declaration.File == TGSI_FILE_INPUT)
    319       {
    320          TXT( ", " );
    321          ENM( decl->Interp.Interpolate, tgsi_interpolate_names );
    322       }
    323 
    324       if (decl->Interp.Centroid) {
    325          TXT( ", CENTROID" );
    326       }
    327 
    328       if (decl->Interp.CylindricalWrap) {
    329          TXT(", CYLWRAP_");
    330          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_X) {
    331             CHR('X');
    332          }
    333          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Y) {
    334             CHR('Y');
    335          }
    336          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_Z) {
    337             CHR('Z');
    338          }
    339          if (decl->Interp.CylindricalWrap & TGSI_CYLINDRICAL_WRAP_W) {
    340             CHR('W');
    341          }
    342       }
    343    }
    344 
    345    if (decl->Declaration.Invariant) {
    346       TXT( ", INVARIANT" );
    347    }
    348 
    349 
    350    if (decl->Declaration.File == TGSI_FILE_IMMEDIATE_ARRAY) {
    351       unsigned i;
    352       char range_indent[4];
    353 
    354       TXT(" {");
    355 
    356       if (decl->Range.Last < 10)
    357          range_indent[0] = '\0';
    358       else if (decl->Range.Last < 100) {
    359          range_indent[0] = ' ';
    360          range_indent[1] = '\0';
    361       } else if (decl->Range.Last < 1000) {
    362          range_indent[0] = ' ';
    363          range_indent[1] = ' ';
    364          range_indent[2] = '\0';
    365       } else {
    366          range_indent[0] = ' ';
    367          range_indent[1] = ' ';
    368          range_indent[2] = ' ';
    369          range_indent[3] = '\0';
    370       }
    371 
    372       dump_imm_data(iter, decl->ImmediateData.u,
    373                     4, TGSI_IMM_FLOAT32);
    374       for(i = 1; i <= decl->Range.Last; ++i) {
    375          /* indent by strlen of:
    376           *   "DCL IMMX[0..1] {" */
    377          CHR('\n');
    378          TXT( "                " );
    379          TXT( range_indent );
    380          dump_imm_data(iter, decl->ImmediateData.u + i,
    381                        4, TGSI_IMM_FLOAT32);
    382       }
    383 
    384       TXT(" }");
    385    }
    386 
    387    EOL();
    388 
    389    return TRUE;
    390 }
    391 
    392 void
    393 tgsi_dump_declaration(
    394    const struct tgsi_full_declaration *decl )
    395 {
    396    struct dump_ctx ctx;
    397 
    398    ctx.dump_printf = dump_ctx_printf;
    399 
    400    iter_declaration( &ctx.iter, (struct tgsi_full_declaration *)decl );
    401 }
    402 
    403 static boolean
    404 iter_property(
    405    struct tgsi_iterate_context *iter,
    406    struct tgsi_full_property *prop )
    407 {
    408    int i;
    409    struct dump_ctx *ctx = (struct dump_ctx *)iter;
    410 
    411    TXT( "PROPERTY " );
    412    ENM(prop->Property.PropertyName, tgsi_property_names);
    413 
    414    if (prop->Property.NrTokens > 1)
    415       TXT(" ");
    416 
    417    for (i = 0; i < prop->Property.NrTokens - 1; ++i) {
    418       switch (prop->Property.PropertyName) {
    419       case TGSI_PROPERTY_GS_INPUT_PRIM:
    420       case TGSI_PROPERTY_GS_OUTPUT_PRIM:
    421          ENM(prop->u[i].Data, tgsi_primitive_names);
    422          break;
    423       case TGSI_PROPERTY_FS_COORD_ORIGIN:
    424          ENM(prop->u[i].Data, tgsi_fs_coord_origin_names);
    425          break;
    426       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
    427          ENM(prop->u[i].Data, tgsi_fs_coord_pixel_center_names);
    428          break;
    429       default:
    430          SID( prop->u[i].Data );
    431          break;
    432       }
    433       if (i < prop->Property.NrTokens - 2)
    434          TXT( ", " );
    435    }
    436    EOL();
    437 
    438    return TRUE;
    439 }
    440 
    441 void tgsi_dump_property(
    442    const struct tgsi_full_property *prop )
    443 {
    444    struct dump_ctx ctx;
    445 
    446    ctx.dump_printf = dump_ctx_printf;
    447 
    448    iter_property( &ctx.iter, (struct tgsi_full_property *)prop );
    449 }
    450 
    451 static boolean
    452 iter_immediate(
    453    struct tgsi_iterate_context *iter,
    454    struct tgsi_full_immediate *imm )
    455 {
    456    struct dump_ctx *ctx = (struct dump_ctx *) iter;
    457 
    458    TXT( "IMM " );
    459    ENM( imm->Immediate.DataType, tgsi_immediate_type_names );
    460 
    461    dump_imm_data(iter, imm->u, imm->Immediate.NrTokens - 1,
    462                  imm->Immediate.DataType);
    463 
    464    EOL();
    465 
    466    return TRUE;
    467 }
    468 
    469 void
    470 tgsi_dump_immediate(
    471    const struct tgsi_full_immediate *imm )
    472 {
    473    struct dump_ctx ctx;
    474 
    475    ctx.dump_printf = dump_ctx_printf;
    476 
    477    iter_immediate( &ctx.iter, (struct tgsi_full_immediate *)imm );
    478 }
    479 
    480 static boolean
    481 iter_instruction(
    482    struct tgsi_iterate_context *iter,
    483    struct tgsi_full_instruction *inst )
    484 {
    485    struct dump_ctx *ctx = (struct dump_ctx *) iter;
    486    uint instno = ctx->instno++;
    487    const struct tgsi_opcode_info *info = tgsi_get_opcode_info( inst->Instruction.Opcode );
    488    uint i;
    489    boolean first_reg = TRUE;
    490 
    491    INSTID( instno );
    492    TXT( ": " );
    493 
    494    ctx->indent -= info->pre_dedent;
    495    for(i = 0; (int)i < ctx->indent; ++i)
    496       TXT( "  " );
    497    ctx->indent += info->post_indent;
    498 
    499    if (inst->Instruction.Predicate) {
    500       CHR( '(' );
    501 
    502       if (inst->Predicate.Negate)
    503          CHR( '!' );
    504 
    505       TXT( "PRED[" );
    506       SID( inst->Predicate.Index );
    507       CHR( ']' );
    508 
    509       if (inst->Predicate.SwizzleX != TGSI_SWIZZLE_X ||
    510           inst->Predicate.SwizzleY != TGSI_SWIZZLE_Y ||
    511           inst->Predicate.SwizzleZ != TGSI_SWIZZLE_Z ||
    512           inst->Predicate.SwizzleW != TGSI_SWIZZLE_W) {
    513          CHR( '.' );
    514          ENM( inst->Predicate.SwizzleX, tgsi_swizzle_names );
    515          ENM( inst->Predicate.SwizzleY, tgsi_swizzle_names );
    516          ENM( inst->Predicate.SwizzleZ, tgsi_swizzle_names );
    517          ENM( inst->Predicate.SwizzleW, tgsi_swizzle_names );
    518       }
    519 
    520       TXT( ") " );
    521    }
    522 
    523    TXT( info->mnemonic );
    524 
    525    switch (inst->Instruction.Saturate) {
    526    case TGSI_SAT_NONE:
    527       break;
    528    case TGSI_SAT_ZERO_ONE:
    529       TXT( "_SAT" );
    530       break;
    531    case TGSI_SAT_MINUS_PLUS_ONE:
    532       TXT( "_SATNV" );
    533       break;
    534    default:
    535       assert( 0 );
    536    }
    537 
    538    for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
    539       const struct tgsi_full_dst_register *dst = &inst->Dst[i];
    540 
    541       if (!first_reg)
    542          CHR( ',' );
    543       CHR( ' ' );
    544 
    545       _dump_register_dst( ctx, dst );
    546       _dump_writemask( ctx, dst->Register.WriteMask );
    547 
    548       first_reg = FALSE;
    549    }
    550 
    551    for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
    552       const struct tgsi_full_src_register *src = &inst->Src[i];
    553 
    554       if (!first_reg)
    555          CHR( ',' );
    556       CHR( ' ' );
    557 
    558       if (src->Register.Negate)
    559          CHR( '-' );
    560       if (src->Register.Absolute)
    561          CHR( '|' );
    562 
    563       _dump_register_src(ctx, src);
    564 
    565       if (src->Register.SwizzleX != TGSI_SWIZZLE_X ||
    566           src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
    567           src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
    568           src->Register.SwizzleW != TGSI_SWIZZLE_W) {
    569          CHR( '.' );
    570          ENM( src->Register.SwizzleX, tgsi_swizzle_names );
    571          ENM( src->Register.SwizzleY, tgsi_swizzle_names );
    572          ENM( src->Register.SwizzleZ, tgsi_swizzle_names );
    573          ENM( src->Register.SwizzleW, tgsi_swizzle_names );
    574       }
    575 
    576       if (src->Register.Absolute)
    577          CHR( '|' );
    578 
    579       first_reg = FALSE;
    580    }
    581 
    582    if (inst->Instruction.Texture) {
    583       TXT( ", " );
    584       ENM( inst->Texture.Texture, tgsi_texture_names );
    585       for (i = 0; i < inst->Texture.NumOffsets; i++) {
    586          TXT( ", " );
    587          ENM( inst->TexOffsets[i].File, tgsi_file_names);
    588          CHR( '[' );
    589          SID( inst->TexOffsets[i].Index );
    590          CHR( ']' );
    591          CHR( '.' );
    592          ENM( inst->TexOffsets[i].SwizzleX, tgsi_swizzle_names);
    593          ENM( inst->TexOffsets[i].SwizzleY, tgsi_swizzle_names);
    594          ENM( inst->TexOffsets[i].SwizzleZ, tgsi_swizzle_names);
    595       }
    596    }
    597 
    598    switch (inst->Instruction.Opcode) {
    599    case TGSI_OPCODE_IF:
    600    case TGSI_OPCODE_ELSE:
    601    case TGSI_OPCODE_BGNLOOP:
    602    case TGSI_OPCODE_ENDLOOP:
    603    case TGSI_OPCODE_CAL:
    604       TXT( " :" );
    605       UID( inst->Label.Label );
    606       break;
    607    }
    608 
    609    /* update indentation */
    610    if (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
    611        inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
    612        inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP) {
    613       ctx->indentation += indent_spaces;
    614    }
    615 
    616    EOL();
    617 
    618    return TRUE;
    619 }
    620 
    621 void
    622 tgsi_dump_instruction(
    623    const struct tgsi_full_instruction *inst,
    624    uint instno )
    625 {
    626    struct dump_ctx ctx;
    627 
    628    ctx.instno = instno;
    629    ctx.indent = 0;
    630    ctx.dump_printf = dump_ctx_printf;
    631    ctx.indentation = 0;
    632 
    633    iter_instruction( &ctx.iter, (struct tgsi_full_instruction *)inst );
    634 }
    635 
    636 static boolean
    637 prolog(
    638    struct tgsi_iterate_context *iter )
    639 {
    640    struct dump_ctx *ctx = (struct dump_ctx *) iter;
    641    ENM( iter->processor.Processor, tgsi_processor_type_names );
    642    EOL();
    643    return TRUE;
    644 }
    645 
    646 void
    647 tgsi_dump(
    648    const struct tgsi_token *tokens,
    649    uint flags )
    650 {
    651    struct dump_ctx ctx;
    652 
    653    ctx.iter.prolog = prolog;
    654    ctx.iter.iterate_instruction = iter_instruction;
    655    ctx.iter.iterate_declaration = iter_declaration;
    656    ctx.iter.iterate_immediate = iter_immediate;
    657    ctx.iter.iterate_property = iter_property;
    658    ctx.iter.epilog = NULL;
    659 
    660    ctx.instno = 0;
    661    ctx.indent = 0;
    662    ctx.dump_printf = dump_ctx_printf;
    663    ctx.indentation = 0;
    664 
    665    tgsi_iterate_shader( tokens, &ctx.iter );
    666 }
    667 
    668 struct str_dump_ctx
    669 {
    670    struct dump_ctx base;
    671    char *str;
    672    char *ptr;
    673    int left;
    674 };
    675 
    676 static void
    677 str_dump_ctx_printf(struct dump_ctx *ctx, const char *format, ...)
    678 {
    679    struct str_dump_ctx *sctx = (struct str_dump_ctx *)ctx;
    680 
    681    if(sctx->left > 1) {
    682       int written;
    683       va_list ap;
    684       va_start(ap, format);
    685       written = util_vsnprintf(sctx->ptr, sctx->left, format, ap);
    686       va_end(ap);
    687 
    688       /* Some complicated logic needed to handle the return value of
    689        * vsnprintf:
    690        */
    691       if (written > 0) {
    692          written = MIN2(sctx->left, written);
    693          sctx->ptr += written;
    694          sctx->left -= written;
    695       }
    696    }
    697 }
    698 
    699 void
    700 tgsi_dump_str(
    701    const struct tgsi_token *tokens,
    702    uint flags,
    703    char *str,
    704    size_t size)
    705 {
    706    struct str_dump_ctx ctx;
    707 
    708    ctx.base.iter.prolog = prolog;
    709    ctx.base.iter.iterate_instruction = iter_instruction;
    710    ctx.base.iter.iterate_declaration = iter_declaration;
    711    ctx.base.iter.iterate_immediate = iter_immediate;
    712    ctx.base.iter.iterate_property = iter_property;
    713    ctx.base.iter.epilog = NULL;
    714 
    715    ctx.base.instno = 0;
    716    ctx.base.indent = 0;
    717    ctx.base.dump_printf = &str_dump_ctx_printf;
    718    ctx.base.indentation = 0;
    719 
    720    ctx.str = str;
    721    ctx.str[0] = 0;
    722    ctx.ptr = str;
    723    ctx.left = (int)size;
    724 
    725    tgsi_iterate_shader( tokens, &ctx.base.iter );
    726 }
    727