Home | History | Annotate | Download | only in tgsi
      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
     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
     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
    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
    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
    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
    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
    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
    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
    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 
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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