Home | History | Annotate | Download | only in tgsi
      1 /**************************************************************************
      2  *
      3  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
      4  * All Rights Reserved.
      5  * Copyright 2008 VMware, Inc.  All rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the
      9  * "Software"), to deal in the Software without restriction, including
     10  * without limitation the rights to use, copy, modify, merge, publish,
     11  * distribute, sub license, and/or sell copies of the Software, and to
     12  * permit persons to whom the Software is furnished to do so, subject to
     13  * the following conditions:
     14  *
     15  * The above copyright notice and this permission notice (including the
     16  * next paragraph) shall be included in all copies or substantial portions
     17  * of the Software.
     18  *
     19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     22  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  **************************************************************************/
     28 
     29 /**
     30  * TGSI program scan utility.
     31  * Used to determine which registers and instructions are used by a shader.
     32  *
     33  * Authors:  Brian Paul
     34  */
     35 
     36 
     37 #include "util/u_math.h"
     38 #include "tgsi/tgsi_parse.h"
     39 #include "tgsi/tgsi_util.h"
     40 #include "tgsi/tgsi_scan.h"
     41 
     42 
     43 
     44 
     45 /**
     46  * Scan the given TGSI shader to collect information such as number of
     47  * registers used, special instructions used, etc.
     48  * \return info  the result of the scan
     49  */
     50 void
     51 tgsi_scan_shader(const struct tgsi_token *tokens,
     52                  struct tgsi_shader_info *info)
     53 {
     54    uint procType, i;
     55    struct tgsi_parse_context parse;
     56 
     57    memset(info, 0, sizeof(*info));
     58    for (i = 0; i < TGSI_FILE_COUNT; i++)
     59       info->file_max[i] = -1;
     60 
     61    /**
     62     ** Setup to begin parsing input shader
     63     **/
     64    if (tgsi_parse_init( &parse, tokens ) != TGSI_PARSE_OK) {
     65       debug_printf("tgsi_parse_init() failed in tgsi_scan_shader()!\n");
     66       return;
     67    }
     68    procType = parse.FullHeader.Processor.Processor;
     69    assert(procType == TGSI_PROCESSOR_FRAGMENT ||
     70           procType == TGSI_PROCESSOR_VERTEX ||
     71           procType == TGSI_PROCESSOR_GEOMETRY ||
     72           procType == TGSI_PROCESSOR_COMPUTE);
     73 
     74 
     75    /**
     76     ** Loop over incoming program tokens/instructions
     77     */
     78    while( !tgsi_parse_end_of_tokens( &parse ) ) {
     79 
     80       info->num_tokens++;
     81 
     82       tgsi_parse_token( &parse );
     83 
     84       switch( parse.FullToken.Token.Type ) {
     85       case TGSI_TOKEN_TYPE_INSTRUCTION:
     86          {
     87             const struct tgsi_full_instruction *fullinst
     88                = &parse.FullToken.FullInstruction;
     89             uint i;
     90 
     91             assert(fullinst->Instruction.Opcode < TGSI_OPCODE_LAST);
     92             info->opcode_count[fullinst->Instruction.Opcode]++;
     93 
     94             for (i = 0; i < fullinst->Instruction.NumSrcRegs; i++) {
     95                const struct tgsi_full_src_register *src =
     96                   &fullinst->Src[i];
     97                int ind = src->Register.Index;
     98 
     99                /* Mark which inputs are effectively used */
    100                if (src->Register.File == TGSI_FILE_INPUT) {
    101                   unsigned usage_mask;
    102                   usage_mask = tgsi_util_get_inst_usage_mask(fullinst, i);
    103                   if (src->Register.Indirect) {
    104                      for (ind = 0; ind < info->num_inputs; ++ind) {
    105                         info->input_usage_mask[ind] |= usage_mask;
    106                      }
    107                   } else {
    108                      assert(ind >= 0);
    109                      assert(ind < PIPE_MAX_SHADER_INPUTS);
    110                      info->input_usage_mask[ind] |= usage_mask;
    111                   }
    112 
    113                   if (procType == TGSI_PROCESSOR_FRAGMENT &&
    114                       src->Register.File == TGSI_FILE_INPUT &&
    115                       info->reads_position &&
    116                       src->Register.Index == 0 &&
    117                       (src->Register.SwizzleX == TGSI_SWIZZLE_Z ||
    118                        src->Register.SwizzleY == TGSI_SWIZZLE_Z ||
    119                        src->Register.SwizzleZ == TGSI_SWIZZLE_Z ||
    120                        src->Register.SwizzleW == TGSI_SWIZZLE_Z)) {
    121                      info->reads_z = TRUE;
    122                   }
    123                }
    124 
    125                /* check for indirect register reads */
    126                if (src->Register.Indirect) {
    127                   info->indirect_files |= (1 << src->Register.File);
    128                }
    129             }
    130 
    131             /* check for indirect register writes */
    132             for (i = 0; i < fullinst->Instruction.NumDstRegs; i++) {
    133                const struct tgsi_full_dst_register *dst = &fullinst->Dst[i];
    134                if (dst->Register.Indirect) {
    135                   info->indirect_files |= (1 << dst->Register.File);
    136                }
    137             }
    138 
    139             info->num_instructions++;
    140          }
    141          break;
    142 
    143       case TGSI_TOKEN_TYPE_DECLARATION:
    144          {
    145             const struct tgsi_full_declaration *fulldecl
    146                = &parse.FullToken.FullDeclaration;
    147             const uint file = fulldecl->Declaration.File;
    148             uint reg;
    149             for (reg = fulldecl->Range.First;
    150                  reg <= fulldecl->Range.Last;
    151                  reg++) {
    152 
    153                /* only first 32 regs will appear in this bitfield */
    154                info->file_mask[file] |= (1 << reg);
    155                info->file_count[file]++;
    156                info->file_max[file] = MAX2(info->file_max[file], (int)reg);
    157 
    158                if (file == TGSI_FILE_INPUT) {
    159                   info->input_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name;
    160                   info->input_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index;
    161                   info->input_interpolate[reg] = (ubyte)fulldecl->Interp.Interpolate;
    162                   info->input_centroid[reg] = (ubyte)fulldecl->Interp.Centroid;
    163                   info->input_cylindrical_wrap[reg] = (ubyte)fulldecl->Interp.CylindricalWrap;
    164                   info->num_inputs++;
    165 
    166                   if (procType == TGSI_PROCESSOR_FRAGMENT &&
    167                       fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION)
    168                         info->reads_position = TRUE;
    169                }
    170                else if (file == TGSI_FILE_SYSTEM_VALUE) {
    171                   unsigned index = fulldecl->Range.First;
    172                   unsigned semName = fulldecl->Semantic.Name;
    173 
    174                   info->system_value_semantic_name[index] = semName;
    175                   info->num_system_values = MAX2(info->num_system_values,
    176                                                  index + 1);
    177 
    178                   /*
    179                   info->system_value_semantic_name[info->num_system_values++] =
    180                      fulldecl->Semantic.Name;
    181                   */
    182 
    183                   if (fulldecl->Semantic.Name == TGSI_SEMANTIC_INSTANCEID) {
    184                      info->uses_instanceid = TRUE;
    185                   }
    186                   else if (fulldecl->Semantic.Name == TGSI_SEMANTIC_VERTEXID) {
    187                      info->uses_vertexid = TRUE;
    188                   }
    189                }
    190                else if (file == TGSI_FILE_OUTPUT) {
    191                   info->output_semantic_name[reg] = (ubyte)fulldecl->Semantic.Name;
    192                   info->output_semantic_index[reg] = (ubyte)fulldecl->Semantic.Index;
    193                   info->num_outputs++;
    194 
    195                   if (procType == TGSI_PROCESSOR_VERTEX &&
    196                       fulldecl->Semantic.Name == TGSI_SEMANTIC_CLIPDIST) {
    197                      info->num_written_clipdistance += util_bitcount(fulldecl->Declaration.UsageMask);
    198                   }
    199                   /* extra info for special outputs */
    200                   if (procType == TGSI_PROCESSOR_FRAGMENT &&
    201                       fulldecl->Semantic.Name == TGSI_SEMANTIC_POSITION)
    202                         info->writes_z = TRUE;
    203                   if (procType == TGSI_PROCESSOR_FRAGMENT &&
    204                       fulldecl->Semantic.Name == TGSI_SEMANTIC_STENCIL)
    205                         info->writes_stencil = TRUE;
    206                   if (procType == TGSI_PROCESSOR_VERTEX &&
    207                       fulldecl->Semantic.Name == TGSI_SEMANTIC_EDGEFLAG) {
    208                      info->writes_edgeflag = TRUE;
    209                   }
    210                }
    211 
    212              }
    213          }
    214          break;
    215 
    216       case TGSI_TOKEN_TYPE_IMMEDIATE:
    217          {
    218             uint reg = info->immediate_count++;
    219             uint file = TGSI_FILE_IMMEDIATE;
    220 
    221             info->file_mask[file] |= (1 << reg);
    222             info->file_count[file]++;
    223             info->file_max[file] = MAX2(info->file_max[file], (int)reg);
    224          }
    225          break;
    226 
    227       case TGSI_TOKEN_TYPE_PROPERTY:
    228          {
    229             const struct tgsi_full_property *fullprop
    230                = &parse.FullToken.FullProperty;
    231 
    232             info->properties[info->num_properties].name =
    233                fullprop->Property.PropertyName;
    234             memcpy(info->properties[info->num_properties].data,
    235                    fullprop->u, 8 * sizeof(unsigned));;
    236 
    237             ++info->num_properties;
    238          }
    239          break;
    240 
    241       default:
    242          assert( 0 );
    243       }
    244    }
    245 
    246    info->uses_kill = (info->opcode_count[TGSI_OPCODE_KIL] ||
    247                       info->opcode_count[TGSI_OPCODE_KILP]);
    248 
    249    /* extract simple properties */
    250    for (i = 0; i < info->num_properties; ++i) {
    251       switch (info->properties[i].name) {
    252       case TGSI_PROPERTY_FS_COORD_ORIGIN:
    253          info->origin_lower_left = info->properties[i].data[0];
    254          break;
    255       case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER:
    256          info->pixel_center_integer = info->properties[i].data[0];
    257          break;
    258       case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS:
    259          info->color0_writes_all_cbufs = info->properties[i].data[0];
    260          break;
    261       default:
    262          ;
    263       }
    264    }
    265 
    266    tgsi_parse_free (&parse);
    267 }
    268 
    269 
    270 
    271 /**
    272  * Check if the given shader is a "passthrough" shader consisting of only
    273  * MOV instructions of the form:  MOV OUT[n], IN[n]
    274  *
    275  */
    276 boolean
    277 tgsi_is_passthrough_shader(const struct tgsi_token *tokens)
    278 {
    279    struct tgsi_parse_context parse;
    280 
    281    /**
    282     ** Setup to begin parsing input shader
    283     **/
    284    if (tgsi_parse_init(&parse, tokens) != TGSI_PARSE_OK) {
    285       debug_printf("tgsi_parse_init() failed in tgsi_is_passthrough_shader()!\n");
    286       return FALSE;
    287    }
    288 
    289    /**
    290     ** Loop over incoming program tokens/instructions
    291     */
    292    while (!tgsi_parse_end_of_tokens(&parse)) {
    293 
    294       tgsi_parse_token(&parse);
    295 
    296       switch (parse.FullToken.Token.Type) {
    297       case TGSI_TOKEN_TYPE_INSTRUCTION:
    298          {
    299             struct tgsi_full_instruction *fullinst =
    300                &parse.FullToken.FullInstruction;
    301             const struct tgsi_full_src_register *src =
    302                &fullinst->Src[0];
    303             const struct tgsi_full_dst_register *dst =
    304                &fullinst->Dst[0];
    305 
    306             /* Do a whole bunch of checks for a simple move */
    307             if (fullinst->Instruction.Opcode != TGSI_OPCODE_MOV ||
    308                 (src->Register.File != TGSI_FILE_INPUT &&
    309                  src->Register.File != TGSI_FILE_SYSTEM_VALUE) ||
    310                 dst->Register.File != TGSI_FILE_OUTPUT ||
    311                 src->Register.Index != dst->Register.Index ||
    312 
    313                 src->Register.Negate ||
    314                 src->Register.Absolute ||
    315 
    316                 src->Register.SwizzleX != TGSI_SWIZZLE_X ||
    317                 src->Register.SwizzleY != TGSI_SWIZZLE_Y ||
    318                 src->Register.SwizzleZ != TGSI_SWIZZLE_Z ||
    319                 src->Register.SwizzleW != TGSI_SWIZZLE_W ||
    320 
    321                 dst->Register.WriteMask != TGSI_WRITEMASK_XYZW)
    322             {
    323                tgsi_parse_free(&parse);
    324                return FALSE;
    325             }
    326          }
    327          break;
    328 
    329       case TGSI_TOKEN_TYPE_DECLARATION:
    330          /* fall-through */
    331       case TGSI_TOKEN_TYPE_IMMEDIATE:
    332          /* fall-through */
    333       case TGSI_TOKEN_TYPE_PROPERTY:
    334          /* fall-through */
    335       default:
    336          ; /* no-op */
    337       }
    338    }
    339 
    340    tgsi_parse_free(&parse);
    341 
    342    /* if we get here, it's a pass-through shader */
    343    return TRUE;
    344 }
    345