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