Home | History | Annotate | Download | only in r300
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Marek Olk <maraeo (at) gmail.com>
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  **************************************************************************/
     26 
     27 /* This file contains the vertex shader tranformations for SW TCL needed
     28  * to overcome the limitations of the r300 rasterizer.
     29  *
     30  * Transformations:
     31  * 1) If the secondary color output is present, the primary color must be
     32  *    present too.
     33  * 2) If any back-face color output is present, there must be all 4 color
     34  *    outputs and missing ones must be inserted.
     35  * 3) Insert a trailing texcoord output containing a copy of POS, for WPOS.
     36  *
     37  * I know this code is cumbersome, but I don't know of any nicer way
     38  * of transforming TGSI shaders. ~ M.
     39  */
     40 
     41 #include "r300_vs.h"
     42 
     43 #include <stdio.h>
     44 
     45 #include "tgsi/tgsi_transform.h"
     46 #include "tgsi/tgsi_dump.h"
     47 
     48 #include "draw/draw_context.h"
     49 
     50 struct vs_transform_context {
     51     struct tgsi_transform_context base;
     52 
     53     boolean color_used[2];
     54     boolean bcolor_used[2];
     55 
     56     /* Index of the pos output, typically 0. */
     57     unsigned pos_output;
     58     /* Index of the pos temp where all writes of pos are redirected to. */
     59     unsigned pos_temp;
     60     /* The index of the last generic output, after which we insert a new
     61      * output for WPOS. */
     62     int last_generic;
     63 
     64     unsigned num_outputs;
     65     /* Used to shift output decl. indices when inserting new ones. */
     66     unsigned decl_shift;
     67     /* Used to remap writes to output decls if their indices changed. */
     68     unsigned out_remap[32];
     69 
     70     /* First instruction processed? */
     71     boolean first_instruction;
     72     /* End instruction processed? */
     73     boolean end_instruction;
     74 
     75     boolean temp_used[1024];
     76 };
     77 
     78 static void emit_temp(struct tgsi_transform_context *ctx, unsigned reg)
     79 {
     80     struct tgsi_full_declaration decl;
     81 
     82     decl = tgsi_default_full_declaration();
     83     decl.Declaration.File = TGSI_FILE_TEMPORARY;
     84     decl.Range.First = decl.Range.Last = reg;
     85     ctx->emit_declaration(ctx, &decl);
     86 }
     87 
     88 static void emit_output(struct tgsi_transform_context *ctx,
     89                         unsigned name, unsigned index, unsigned interp,
     90                         unsigned reg)
     91 {
     92     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
     93     struct tgsi_full_declaration decl;
     94 
     95     decl = tgsi_default_full_declaration();
     96     decl.Declaration.File = TGSI_FILE_OUTPUT;
     97     decl.Declaration.Interpolate = 1;
     98     decl.Declaration.Semantic = TRUE;
     99     decl.Semantic.Name = name;
    100     decl.Semantic.Index = index;
    101     decl.Range.First = decl.Range.Last = reg;
    102     decl.Interp.Interpolate = interp;
    103     ctx->emit_declaration(ctx, &decl);
    104     ++vsctx->num_outputs;
    105 }
    106 
    107 static void insert_output_before(struct tgsi_transform_context *ctx,
    108                                  struct tgsi_full_declaration *before,
    109                                  unsigned name, unsigned index, unsigned interp)
    110 {
    111     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
    112     unsigned i;
    113 
    114     /* Make a place for the new output. */
    115     for (i = before->Range.First; i < Elements(vsctx->out_remap); i++) {
    116         ++vsctx->out_remap[i];
    117     }
    118 
    119     /* Insert the new output. */
    120     emit_output(ctx, name, index, interp,
    121                 before->Range.First + vsctx->decl_shift);
    122 
    123     ++vsctx->decl_shift;
    124 }
    125 
    126 static void insert_output_after(struct tgsi_transform_context *ctx,
    127                                 struct tgsi_full_declaration *after,
    128                                 unsigned name, unsigned index, unsigned interp)
    129 {
    130     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
    131     unsigned i;
    132 
    133     /* Make a place for the new output. */
    134     for (i = after->Range.First+1; i < Elements(vsctx->out_remap); i++) {
    135         ++vsctx->out_remap[i];
    136     }
    137 
    138     /* Insert the new output. */
    139     emit_output(ctx, name, index, interp,
    140                 after->Range.First + 1);
    141 
    142     ++vsctx->decl_shift;
    143 }
    144 
    145 static void transform_decl(struct tgsi_transform_context *ctx,
    146                            struct tgsi_full_declaration *decl)
    147 {
    148     struct vs_transform_context *vsctx = (struct vs_transform_context *)ctx;
    149     unsigned i;
    150 
    151     if (decl->Declaration.File == TGSI_FILE_OUTPUT) {
    152         switch (decl->Semantic.Name) {
    153             case TGSI_SEMANTIC_POSITION:
    154                 vsctx->pos_output = decl->Range.First;
    155                 break;
    156 
    157             case TGSI_SEMANTIC_COLOR:
    158                 assert(decl->Semantic.Index < 2);
    159 
    160                 /* We must rasterize the first color if the second one is
    161                  * used, otherwise the rasterizer doesn't do the color
    162                  * selection correctly. Declare it, but don't write to it. */
    163                 if (decl->Semantic.Index == 1 && !vsctx->color_used[0]) {
    164                     insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
    165                                          TGSI_INTERPOLATE_LINEAR);
    166                     vsctx->color_used[0] = TRUE;
    167                 }
    168                 break;
    169 
    170             case TGSI_SEMANTIC_BCOLOR:
    171                 assert(decl->Semantic.Index < 2);
    172 
    173                 /* We must rasterize all 4 colors if back-face colors are
    174                  * used, otherwise the rasterizer doesn't do the color
    175                  * selection correctly. Declare it, but don't write to it. */
    176                 if (!vsctx->color_used[0]) {
    177                     insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 0,
    178                                          TGSI_INTERPOLATE_LINEAR);
    179                     vsctx->color_used[0] = TRUE;
    180                 }
    181                 if (!vsctx->color_used[1]) {
    182                     insert_output_before(ctx, decl, TGSI_SEMANTIC_COLOR, 1,
    183                                          TGSI_INTERPOLATE_LINEAR);
    184                     vsctx->color_used[1] = TRUE;
    185                 }
    186                 if (decl->Semantic.Index == 1 && !vsctx->bcolor_used[0]) {
    187                     insert_output_before(ctx, decl, TGSI_SEMANTIC_BCOLOR, 0,
    188                                          TGSI_INTERPOLATE_LINEAR);
    189                     vsctx->bcolor_used[0] = TRUE;
    190                 }
    191                 break;
    192 
    193             case TGSI_SEMANTIC_GENERIC:
    194                 vsctx->last_generic = MAX2(vsctx->last_generic, decl->Semantic.Index);
    195                 break;
    196         }
    197 
    198         /* Since we're inserting new outputs in between, the following outputs
    199          * should be moved to the right so that they don't overlap with
    200          * the newly added ones. */
    201         decl->Range.First += vsctx->decl_shift;
    202         decl->Range.Last += vsctx->decl_shift;
    203 
    204         ++vsctx->num_outputs;
    205     } else if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
    206         for (i = decl->Range.First; i <= decl->Range.Last; i++) {
    207            vsctx->temp_used[i] = TRUE;
    208         }
    209     }
    210 
    211     ctx->emit_declaration(ctx, decl);
    212 
    213     /* Insert BCOLOR1 if needed. */
    214     if (decl->Declaration.File == TGSI_FILE_OUTPUT &&
    215         decl->Semantic.Name == TGSI_SEMANTIC_BCOLOR &&
    216         !vsctx->bcolor_used[1]) {
    217         insert_output_after(ctx, decl, TGSI_SEMANTIC_BCOLOR, 1,
    218                             TGSI_INTERPOLATE_LINEAR);
    219     }
    220 }
    221 
    222 static void transform_inst(struct tgsi_transform_context *ctx,
    223                            struct tgsi_full_instruction *inst)
    224 {
    225     struct vs_transform_context *vsctx = (struct vs_transform_context *) ctx;
    226     struct tgsi_full_instruction new_inst;
    227     unsigned i;
    228 
    229     if (!vsctx->first_instruction) {
    230         vsctx->first_instruction = TRUE;
    231 
    232         /* Insert the generic output for WPOS. */
    233         emit_output(ctx, TGSI_SEMANTIC_GENERIC, vsctx->last_generic + 1,
    234                     TGSI_INTERPOLATE_PERSPECTIVE, vsctx->num_outputs);
    235 
    236         /* Find a free temp for POSITION. */
    237         for (i = 0; i < Elements(vsctx->temp_used); i++) {
    238             if (!vsctx->temp_used[i]) {
    239                 emit_temp(ctx, i);
    240                 vsctx->pos_temp = i;
    241                 break;
    242             }
    243         }
    244     }
    245 
    246     if (inst->Instruction.Opcode == TGSI_OPCODE_END) {
    247         /* MOV OUT[pos_output], TEMP[pos_temp]; */
    248         new_inst = tgsi_default_full_instruction();
    249         new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
    250         new_inst.Instruction.NumDstRegs = 1;
    251         new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
    252         new_inst.Dst[0].Register.Index = vsctx->pos_output;
    253         new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
    254         new_inst.Instruction.NumSrcRegs = 1;
    255         new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
    256         new_inst.Src[0].Register.Index = vsctx->pos_temp;
    257         ctx->emit_instruction(ctx, &new_inst);
    258 
    259         /* MOV OUT[n-1], TEMP[pos_temp]; */
    260         new_inst = tgsi_default_full_instruction();
    261         new_inst.Instruction.Opcode = TGSI_OPCODE_MOV;
    262         new_inst.Instruction.NumDstRegs = 1;
    263         new_inst.Dst[0].Register.File = TGSI_FILE_OUTPUT;
    264         new_inst.Dst[0].Register.Index = vsctx->num_outputs - 1;
    265         new_inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
    266         new_inst.Instruction.NumSrcRegs = 1;
    267         new_inst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
    268         new_inst.Src[0].Register.Index = vsctx->pos_temp;
    269         ctx->emit_instruction(ctx, &new_inst);
    270 
    271         vsctx->end_instruction = TRUE;
    272     } else {
    273         /* Not an END instruction. */
    274         /* Fix writes to outputs. */
    275         for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
    276             struct tgsi_full_dst_register *dst = &inst->Dst[i];
    277             if (dst->Register.File == TGSI_FILE_OUTPUT) {
    278                 if (dst->Register.Index == vsctx->pos_output) {
    279                     /* Replace writes to OUT[pos_output] with TEMP[pos_temp]. */
    280                     dst->Register.File = TGSI_FILE_TEMPORARY;
    281                     dst->Register.Index = vsctx->pos_temp;
    282                 } else {
    283                     /* Not a position, good...
    284                      * Since we were changing the indices of output decls,
    285                      * we must redirect writes into them too. */
    286                     dst->Register.Index = vsctx->out_remap[dst->Register.Index];
    287                 }
    288             }
    289         }
    290 
    291         /* Inserting 2 instructions before the END opcode moves all following
    292          * labels by 2. Subroutines are always after the END opcode so
    293          * they're always moved. */
    294         if (inst->Instruction.Opcode == TGSI_OPCODE_CAL) {
    295             inst->Label.Label += 2;
    296         }
    297         /* The labels of the following opcodes are moved only after
    298          * the END opcode. */
    299         if (vsctx->end_instruction &&
    300             (inst->Instruction.Opcode == TGSI_OPCODE_IF ||
    301              inst->Instruction.Opcode == TGSI_OPCODE_ELSE ||
    302              inst->Instruction.Opcode == TGSI_OPCODE_BGNLOOP ||
    303              inst->Instruction.Opcode == TGSI_OPCODE_ENDLOOP)) {
    304             inst->Label.Label += 2;
    305         }
    306     }
    307 
    308     ctx->emit_instruction(ctx, inst);
    309 }
    310 
    311 void r300_draw_init_vertex_shader(struct r300_context *r300,
    312                                   struct r300_vertex_shader *vs)
    313 {
    314     struct draw_context *draw = r300->draw;
    315     struct pipe_shader_state new_vs;
    316     struct tgsi_shader_info info;
    317     struct vs_transform_context transform;
    318     const uint newLen = tgsi_num_tokens(vs->state.tokens) + 100 /* XXX */;
    319     unsigned i;
    320 
    321     tgsi_scan_shader(vs->state.tokens, &info);
    322 
    323     new_vs.tokens = tgsi_alloc_tokens(newLen);
    324     if (new_vs.tokens == NULL)
    325         return;
    326 
    327     memset(&transform, 0, sizeof(transform));
    328     for (i = 0; i < Elements(transform.out_remap); i++) {
    329         transform.out_remap[i] = i;
    330     }
    331     transform.last_generic = -1;
    332     transform.base.transform_instruction = transform_inst;
    333     transform.base.transform_declaration = transform_decl;
    334 
    335     for (i = 0; i < info.num_outputs; i++) {
    336         unsigned index = info.output_semantic_index[i];
    337 
    338         switch (info.output_semantic_name[i]) {
    339             case TGSI_SEMANTIC_COLOR:
    340                 assert(index < 2);
    341                 transform.color_used[index] = TRUE;
    342                 break;
    343 
    344             case TGSI_SEMANTIC_BCOLOR:
    345                 assert(index < 2);
    346                 transform.bcolor_used[index] = TRUE;
    347                 break;
    348         }
    349     }
    350 
    351     tgsi_transform_shader(vs->state.tokens,
    352                           (struct tgsi_token*)new_vs.tokens,
    353                           newLen, &transform.base);
    354 
    355 #if 0
    356     printf("----------------------------------------------\norig shader:\n");
    357     tgsi_dump(vs->state.tokens, 0);
    358     printf("----------------------------------------------\nnew shader:\n");
    359     tgsi_dump(new_vs.tokens, 0);
    360     printf("----------------------------------------------\n");
    361 #endif
    362 
    363     /* Free old tokens. */
    364     FREE((void*)vs->state.tokens);
    365 
    366     vs->draw_vs = draw_create_vertex_shader(draw, &new_vs);
    367 
    368     /* Instead of duplicating and freeing the tokens, copy the pointer directly. */
    369     vs->state.tokens = new_vs.tokens;
    370 
    371     /* Init the VS output table for the rasterizer. */
    372     r300_init_vs_outputs(r300, vs);
    373 
    374     /* Make the last generic be WPOS. */
    375     vs->outputs.wpos = vs->outputs.generic[transform.last_generic + 1];
    376     vs->outputs.generic[transform.last_generic + 1] = ATTR_UNUSED;
    377 }
    378