Home | History | Annotate | Download | only in gallivm
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 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 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     17  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
     21  *
     22  * The above copyright notice and this permission notice (including the
     23  * next paragraph) shall be included in all copies or substantial portions
     24  * of the Software.
     25  *
     26  **************************************************************************/
     27 
     28 
     29 #include "util/u_memory.h"
     30 #include "util/u_math.h"
     31 #include "tgsi/tgsi_parse.h"
     32 #include "tgsi/tgsi_util.h"
     33 #include "tgsi/tgsi_dump.h"
     34 #include "tgsi/tgsi_strings.h"
     35 #include "lp_bld_debug.h"
     36 #include "lp_bld_tgsi.h"
     37 
     38 
     39 /**
     40  * Analysis context.
     41  *
     42  * This is where we keep store the value of each channel of the IMM/TEMP/OUT
     43  * register values, as we walk the shader.
     44  */
     45 struct analysis_context
     46 {
     47    struct lp_tgsi_info *info;
     48 
     49    unsigned num_imms;
     50    float imm[128][4];
     51 
     52    struct lp_tgsi_channel_info temp[32][4];
     53 };
     54 
     55 
     56 /**
     57  * Describe the specified channel of the src register.
     58  */
     59 static void
     60 analyse_src(struct analysis_context *ctx,
     61             struct lp_tgsi_channel_info *chan_info,
     62             const struct tgsi_src_register *src,
     63             unsigned chan)
     64 {
     65    chan_info->file = TGSI_FILE_NULL;
     66    if (!src->Indirect && !src->Absolute && !src->Negate) {
     67       unsigned swizzle = tgsi_util_get_src_register_swizzle(src, chan);
     68       if (src->File == TGSI_FILE_TEMPORARY) {
     69          if (src->Index < Elements(ctx->temp)) {
     70             *chan_info = ctx->temp[src->Index][swizzle];
     71          }
     72       } else {
     73          chan_info->file = src->File;
     74          if (src->File == TGSI_FILE_IMMEDIATE) {
     75             assert(src->Index < Elements(ctx->imm));
     76             if (src->Index < Elements(ctx->imm)) {
     77                chan_info->u.value = ctx->imm[src->Index][swizzle];
     78             }
     79          } else {
     80             chan_info->u.index = src->Index;
     81             chan_info->swizzle = swizzle;
     82          }
     83       }
     84    }
     85 }
     86 
     87 
     88 /**
     89  * Whether this register channel refers to a specific immediate value.
     90  */
     91 static boolean
     92 is_immediate(const struct lp_tgsi_channel_info *chan_info, float value)
     93 {
     94    return chan_info->file == TGSI_FILE_IMMEDIATE &&
     95           chan_info->u.value == value;
     96 }
     97 
     98 
     99 static void
    100 analyse_tex(struct analysis_context *ctx,
    101             const struct tgsi_full_instruction *inst,
    102             enum lp_build_tex_modifier modifier)
    103 {
    104    struct lp_tgsi_info *info = ctx->info;
    105    unsigned chan;
    106 
    107    if (info->num_texs < Elements(info->tex)) {
    108       struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs];
    109       boolean indirect = FALSE;
    110       unsigned readmask = 0;
    111 
    112       tex_info->target = inst->Texture.Texture;
    113       switch (inst->Texture.Texture) {
    114       case TGSI_TEXTURE_1D:
    115          readmask = TGSI_WRITEMASK_X;
    116          break;
    117       case TGSI_TEXTURE_1D_ARRAY:
    118       case TGSI_TEXTURE_2D:
    119       case TGSI_TEXTURE_RECT:
    120          readmask = TGSI_WRITEMASK_XY;
    121          break;
    122       case TGSI_TEXTURE_SHADOW1D:
    123       case TGSI_TEXTURE_SHADOW1D_ARRAY:
    124       case TGSI_TEXTURE_SHADOW2D:
    125       case TGSI_TEXTURE_SHADOWRECT:
    126       case TGSI_TEXTURE_2D_ARRAY:
    127       case TGSI_TEXTURE_3D:
    128       case TGSI_TEXTURE_CUBE:
    129          readmask = TGSI_WRITEMASK_XYZ;
    130          break;
    131       case TGSI_TEXTURE_SHADOW2D_ARRAY:
    132          readmask = TGSI_WRITEMASK_XYZW;
    133          break;
    134       default:
    135          assert(0);
    136          return;
    137       }
    138 
    139       if (modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV) {
    140          /* We don't track explicit derivatives, although we could */
    141          indirect = TRUE;
    142          tex_info->unit = inst->Src[3].Register.Index;
    143       }  else {
    144          if (modifier == LP_BLD_TEX_MODIFIER_PROJECTED ||
    145              modifier == LP_BLD_TEX_MODIFIER_LOD_BIAS ||
    146              modifier == LP_BLD_TEX_MODIFIER_EXPLICIT_LOD) {
    147             readmask |= TGSI_WRITEMASK_W;
    148          }
    149          tex_info->unit = inst->Src[1].Register.Index;
    150       }
    151 
    152       for (chan = 0; chan < 4; ++chan) {
    153          struct lp_tgsi_channel_info *chan_info = &tex_info->coord[chan];
    154          if (readmask & (1 << chan)) {
    155             analyse_src(ctx, chan_info, &inst->Src[0].Register, chan);
    156             if (chan_info->file != TGSI_FILE_INPUT) {
    157                indirect = TRUE;
    158             }
    159          } else {
    160             memset(chan_info, 0, sizeof *chan_info);
    161          }
    162       }
    163 
    164       if (indirect) {
    165          info->indirect_textures = TRUE;
    166       }
    167 
    168       ++info->num_texs;
    169    } else {
    170       info->indirect_textures = TRUE;
    171    }
    172 }
    173 
    174 
    175 /**
    176  * Process an instruction, and update the register values accordingly.
    177  */
    178 static void
    179 analyse_instruction(struct analysis_context *ctx,
    180                     struct tgsi_full_instruction *inst)
    181 {
    182    struct lp_tgsi_info *info = ctx->info;
    183    struct lp_tgsi_channel_info (*regs)[4];
    184    unsigned max_regs;
    185    unsigned i;
    186    unsigned index;
    187    unsigned chan;
    188 
    189    for (i = 0; i < inst->Instruction.NumDstRegs; ++i) {
    190       const struct tgsi_dst_register *dst = &inst->Dst[i].Register;
    191 
    192       /*
    193        * Get the lp_tgsi_channel_info array corresponding to the destination
    194        * register file.
    195        */
    196 
    197       if (dst->File == TGSI_FILE_TEMPORARY) {
    198          regs = ctx->temp;
    199          max_regs = Elements(ctx->temp);
    200       } else if (dst->File == TGSI_FILE_OUTPUT) {
    201          regs = info->output;
    202          max_regs = Elements(info->output);
    203       } else if (dst->File == TGSI_FILE_ADDRESS ||
    204                  dst->File == TGSI_FILE_PREDICATE) {
    205          continue;
    206       } else {
    207          assert(0);
    208          continue;
    209       }
    210 
    211       /*
    212        * Detect direct TEX instructions
    213        */
    214 
    215       switch (inst->Instruction.Opcode) {
    216       case TGSI_OPCODE_TEX:
    217          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_NONE);
    218          break;
    219       case TGSI_OPCODE_TXD:
    220          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_DERIV);
    221          break;
    222       case TGSI_OPCODE_TXB:
    223          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_LOD_BIAS);
    224          break;
    225       case TGSI_OPCODE_TXL:
    226          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_EXPLICIT_LOD);
    227          break;
    228       case TGSI_OPCODE_TXP:
    229          analyse_tex(ctx, inst, LP_BLD_TEX_MODIFIER_PROJECTED);
    230          break;
    231       default:
    232          break;
    233       }
    234 
    235       /*
    236        * Keep track of assignments and writes
    237        */
    238 
    239       if (dst->Indirect) {
    240          /*
    241           * It could be any register index so clear all register indices.
    242           */
    243 
    244          for (chan = 0; chan < 4; ++chan) {
    245             if (dst->WriteMask & (1 << chan)) {
    246                for (index = 0; index < max_regs; ++index) {
    247                   regs[index][chan].file = TGSI_FILE_NULL;
    248                }
    249             }
    250          }
    251       } else if (dst->Index < max_regs) {
    252          /*
    253           * Update this destination register value.
    254           */
    255 
    256          struct lp_tgsi_channel_info res[4];
    257 
    258          memset(res, 0, sizeof res);
    259 
    260          if (!inst->Instruction.Predicate &&
    261              !inst->Instruction.Saturate) {
    262             for (chan = 0; chan < 4; ++chan) {
    263                if (dst->WriteMask & (1 << chan)) {
    264                   if (inst->Instruction.Opcode == TGSI_OPCODE_MOV) {
    265                      analyse_src(ctx, &res[chan],
    266                                  &inst->Src[0].Register, chan);
    267                   } else if (inst->Instruction.Opcode == TGSI_OPCODE_MUL) {
    268                      /*
    269                       * Propagate values across 1.0 and 0.0 multiplications.
    270                       */
    271 
    272                      struct lp_tgsi_channel_info src0;
    273                      struct lp_tgsi_channel_info src1;
    274 
    275                      analyse_src(ctx, &src0, &inst->Src[0].Register, chan);
    276                      analyse_src(ctx, &src1, &inst->Src[1].Register, chan);
    277 
    278                      if (is_immediate(&src0, 0.0f)) {
    279                         res[chan] = src0;
    280                      } else if (is_immediate(&src1, 0.0f)) {
    281                         res[chan] = src1;
    282                      } else if (is_immediate(&src0, 1.0f)) {
    283                         res[chan] = src1;
    284                      } else if (is_immediate(&src1, 1.0f)) {
    285                         res[chan] = src0;
    286                      }
    287                   }
    288                }
    289             }
    290          }
    291 
    292          for (chan = 0; chan < 4; ++chan) {
    293             if (dst->WriteMask & (1 << chan)) {
    294                regs[dst->Index][chan] = res[chan];
    295             }
    296          }
    297       }
    298    }
    299 
    300    /*
    301     * Clear all temporaries information in presence of a control flow opcode.
    302     */
    303 
    304    switch (inst->Instruction.Opcode) {
    305    case TGSI_OPCODE_IF:
    306    case TGSI_OPCODE_IFC:
    307    case TGSI_OPCODE_ELSE:
    308    case TGSI_OPCODE_ENDIF:
    309    case TGSI_OPCODE_BGNLOOP:
    310    case TGSI_OPCODE_BRK:
    311    case TGSI_OPCODE_BREAKC:
    312    case TGSI_OPCODE_CONT:
    313    case TGSI_OPCODE_ENDLOOP:
    314    case TGSI_OPCODE_CALLNZ:
    315    case TGSI_OPCODE_CAL:
    316    case TGSI_OPCODE_BGNSUB:
    317    case TGSI_OPCODE_ENDSUB:
    318    case TGSI_OPCODE_SWITCH:
    319    case TGSI_OPCODE_CASE:
    320    case TGSI_OPCODE_DEFAULT:
    321    case TGSI_OPCODE_ENDSWITCH:
    322    case TGSI_OPCODE_RET:
    323    case TGSI_OPCODE_END:
    324       /* XXX: Are there more cases? */
    325       memset(&ctx->temp, 0, sizeof ctx->temp);
    326       memset(&info->output, 0, sizeof info->output);
    327    default:
    328       break;
    329    }
    330 }
    331 
    332 
    333 static INLINE void
    334 dump_info(const struct tgsi_token *tokens,
    335           struct lp_tgsi_info *info)
    336 {
    337    unsigned index;
    338    unsigned chan;
    339 
    340    tgsi_dump(tokens, 0);
    341 
    342    for (index = 0; index < info->num_texs; ++index) {
    343       const struct lp_tgsi_texture_info *tex_info = &info->tex[index];
    344       debug_printf("TEX[%u] =", index);
    345       for (chan = 0; chan < 4; ++chan) {
    346          const struct lp_tgsi_channel_info *chan_info =
    347                &tex_info->coord[chan];
    348          if (chan_info->file != TGSI_FILE_NULL) {
    349             debug_printf(" %s[%u].%c",
    350                          tgsi_file_names[chan_info->file],
    351                          chan_info->u.index,
    352                          "xyzw01"[chan_info->swizzle]);
    353          } else {
    354             debug_printf(" _");
    355          }
    356       }
    357       debug_printf(", SAMP[%u], %s\n",
    358                    tex_info->unit,
    359                    tgsi_texture_names[tex_info->target]);
    360    }
    361 
    362    for (index = 0; index < PIPE_MAX_SHADER_OUTPUTS; ++index) {
    363       for (chan = 0; chan < 4; ++chan) {
    364          const struct lp_tgsi_channel_info *chan_info =
    365                &info->output[index][chan];
    366          if (chan_info->file != TGSI_FILE_NULL) {
    367             debug_printf("OUT[%u].%c = ", index, "xyzw"[chan]);
    368             if (chan_info->file == TGSI_FILE_IMMEDIATE) {
    369                debug_printf("%f", chan_info->u.value);
    370             } else {
    371                const char *file_name;
    372                switch (chan_info->file) {
    373                case TGSI_FILE_CONSTANT:
    374                   file_name = "CONST";
    375                   break;
    376                case TGSI_FILE_INPUT:
    377                   file_name = "IN";
    378                   break;
    379                default:
    380                   file_name = "???";
    381                   break;
    382                }
    383                debug_printf("%s[%u].%c",
    384                             file_name,
    385                             chan_info->u.index,
    386                             "xyzw01"[chan_info->swizzle]);
    387             }
    388             debug_printf("\n");
    389          }
    390       }
    391    }
    392 }
    393 
    394 
    395 /**
    396  * Detect any direct relationship between the output color
    397  */
    398 void
    399 lp_build_tgsi_info(const struct tgsi_token *tokens,
    400                    struct lp_tgsi_info *info)
    401 {
    402    struct tgsi_parse_context parse;
    403    struct analysis_context ctx;
    404    unsigned index;
    405    unsigned chan;
    406 
    407    memset(info, 0, sizeof *info);
    408 
    409    tgsi_scan_shader(tokens, &info->base);
    410 
    411    memset(&ctx, 0, sizeof ctx);
    412    ctx.info = info;
    413 
    414    tgsi_parse_init(&parse, tokens);
    415 
    416    while (!tgsi_parse_end_of_tokens(&parse)) {
    417       tgsi_parse_token(&parse);
    418 
    419       switch (parse.FullToken.Token.Type) {
    420       case TGSI_TOKEN_TYPE_DECLARATION:
    421          break;
    422 
    423       case TGSI_TOKEN_TYPE_INSTRUCTION:
    424          {
    425             struct tgsi_full_instruction *inst =
    426                   &parse.FullToken.FullInstruction;
    427 
    428             if (inst->Instruction.Opcode == TGSI_OPCODE_END ||
    429                 inst->Instruction.Opcode == TGSI_OPCODE_BGNSUB) {
    430                /* We reached the end of main function body. */
    431                goto finished;
    432             }
    433 
    434             analyse_instruction(&ctx, inst);
    435          }
    436          break;
    437 
    438       case TGSI_TOKEN_TYPE_IMMEDIATE:
    439          {
    440             const unsigned size =
    441                   parse.FullToken.FullImmediate.Immediate.NrTokens - 1;
    442             assert(size <= 4);
    443             if (ctx.num_imms < Elements(ctx.imm)) {
    444                for (chan = 0; chan < size; ++chan) {
    445                   float value = parse.FullToken.FullImmediate.u[chan].Float;
    446                   ctx.imm[ctx.num_imms][chan] = value;
    447 
    448                   if (value < 0.0f || value > 1.0f) {
    449                      info->unclamped_immediates = TRUE;
    450                   }
    451                }
    452                ++ctx.num_imms;
    453             }
    454          }
    455          break;
    456 
    457       case TGSI_TOKEN_TYPE_PROPERTY:
    458          break;
    459 
    460       default:
    461          assert(0);
    462       }
    463    }
    464 finished:
    465 
    466    tgsi_parse_free(&parse);
    467 
    468 
    469    /*
    470     * Link the output color values.
    471     */
    472 
    473    for (index = 0; index < PIPE_MAX_COLOR_BUFS; ++index) {
    474       const struct lp_tgsi_channel_info null_output[4];
    475       info->cbuf[index] = null_output;
    476    }
    477 
    478    for (index = 0; index < info->base.num_outputs; ++index) {
    479       unsigned semantic_name = info->base.output_semantic_name[index];
    480       unsigned semantic_index = info->base.output_semantic_index[index];
    481       if (semantic_name == TGSI_SEMANTIC_COLOR &&
    482           semantic_index < PIPE_MAX_COLOR_BUFS) {
    483          info->cbuf[semantic_index] = info->output[index];
    484       }
    485    }
    486 
    487    if (gallivm_debug & GALLIVM_DEBUG_TGSI) {
    488       dump_info(tokens, info);
    489    }
    490 }
    491