Home | History | Annotate | Download | only in tgsi
      1 /**************************************************************************
      2  *
      3  * Copyright 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 /**
     29  * TGSI program transformation utility.
     30  *
     31  * Authors:  Brian Paul
     32  */
     33 
     34 #include "util/u_debug.h"
     35 
     36 #include "tgsi_transform.h"
     37 
     38 
     39 
     40 static void
     41 emit_instruction(struct tgsi_transform_context *ctx,
     42                  const struct tgsi_full_instruction *inst)
     43 {
     44    uint ti = ctx->ti;
     45 
     46    ti += tgsi_build_full_instruction(inst,
     47                                      ctx->tokens_out + ti,
     48                                      ctx->header,
     49                                      ctx->max_tokens_out - ti);
     50    ctx->ti = ti;
     51 }
     52 
     53 
     54 static void
     55 emit_declaration(struct tgsi_transform_context *ctx,
     56                  const struct tgsi_full_declaration *decl)
     57 {
     58    uint ti = ctx->ti;
     59 
     60    ti += tgsi_build_full_declaration(decl,
     61                                      ctx->tokens_out + ti,
     62                                      ctx->header,
     63                                      ctx->max_tokens_out - ti);
     64    ctx->ti = ti;
     65 }
     66 
     67 
     68 static void
     69 emit_immediate(struct tgsi_transform_context *ctx,
     70                const struct tgsi_full_immediate *imm)
     71 {
     72    uint ti = ctx->ti;
     73 
     74    ti += tgsi_build_full_immediate(imm,
     75                                    ctx->tokens_out + ti,
     76                                    ctx->header,
     77                                    ctx->max_tokens_out - ti);
     78    ctx->ti = ti;
     79 }
     80 
     81 
     82 static void
     83 emit_property(struct tgsi_transform_context *ctx,
     84               const struct tgsi_full_property *prop)
     85 {
     86    uint ti = ctx->ti;
     87 
     88    ti += tgsi_build_full_property(prop,
     89                                   ctx->tokens_out + ti,
     90                                   ctx->header,
     91                                   ctx->max_tokens_out - ti);
     92    ctx->ti = ti;
     93 }
     94 
     95 
     96 /**
     97  * Apply user-defined transformations to the input shader to produce
     98  * the output shader.
     99  * For example, a register search-and-replace operation could be applied
    100  * by defining a transform_instruction() callback that examined and changed
    101  * the instruction src/dest regs.
    102  *
    103  * \return number of tokens emitted
    104  */
    105 int
    106 tgsi_transform_shader(const struct tgsi_token *tokens_in,
    107                       struct tgsi_token *tokens_out,
    108                       uint max_tokens_out,
    109                       struct tgsi_transform_context *ctx)
    110 {
    111    uint procType;
    112    boolean first_instruction = TRUE;
    113 
    114    /* input shader */
    115    struct tgsi_parse_context parse;
    116 
    117    /* output shader */
    118    struct tgsi_processor *processor;
    119 
    120 
    121    /**
    122     ** callback context init
    123     **/
    124    ctx->emit_instruction = emit_instruction;
    125    ctx->emit_declaration = emit_declaration;
    126    ctx->emit_immediate = emit_immediate;
    127    ctx->emit_property = emit_property;
    128    ctx->tokens_out = tokens_out;
    129    ctx->max_tokens_out = max_tokens_out;
    130 
    131 
    132    /**
    133     ** Setup to begin parsing input shader
    134     **/
    135    if (tgsi_parse_init( &parse, tokens_in ) != TGSI_PARSE_OK) {
    136       debug_printf("tgsi_parse_init() failed in tgsi_transform_shader()!\n");
    137       return -1;
    138    }
    139    procType = parse.FullHeader.Processor.Processor;
    140    assert(procType == PIPE_SHADER_FRAGMENT ||
    141           procType == PIPE_SHADER_VERTEX ||
    142           procType == PIPE_SHADER_GEOMETRY);
    143 
    144 
    145    /**
    146     **  Setup output shader
    147     **/
    148    ctx->header = (struct tgsi_header *)tokens_out;
    149    *ctx->header = tgsi_build_header();
    150 
    151    processor = (struct tgsi_processor *) (tokens_out + 1);
    152    *processor = tgsi_build_processor( procType, ctx->header );
    153 
    154    ctx->ti = 2;
    155 
    156 
    157    /**
    158     ** Loop over incoming program tokens/instructions
    159     */
    160    while( !tgsi_parse_end_of_tokens( &parse ) ) {
    161 
    162       tgsi_parse_token( &parse );
    163 
    164       switch( parse.FullToken.Token.Type ) {
    165       case TGSI_TOKEN_TYPE_INSTRUCTION:
    166          {
    167             struct tgsi_full_instruction *fullinst
    168                = &parse.FullToken.FullInstruction;
    169 
    170             if (first_instruction && ctx->prolog) {
    171                ctx->prolog(ctx);
    172             }
    173 
    174             /* XXX Note: we may also want to look for a main/top-level
    175              * TGSI_OPCODE_RET instruction in the future.
    176              */
    177             if (fullinst->Instruction.Opcode == TGSI_OPCODE_END
    178                 && ctx->epilog) {
    179                /* Emit caller's epilog */
    180                ctx->epilog(ctx);
    181                /* Emit END */
    182                ctx->emit_instruction(ctx, fullinst);
    183             }
    184             else {
    185                if (ctx->transform_instruction)
    186                   ctx->transform_instruction(ctx, fullinst);
    187                else
    188                   ctx->emit_instruction(ctx, fullinst);
    189             }
    190 
    191             first_instruction = FALSE;
    192          }
    193          break;
    194 
    195       case TGSI_TOKEN_TYPE_DECLARATION:
    196          {
    197             struct tgsi_full_declaration *fulldecl
    198                = &parse.FullToken.FullDeclaration;
    199 
    200             if (ctx->transform_declaration)
    201                ctx->transform_declaration(ctx, fulldecl);
    202             else
    203                ctx->emit_declaration(ctx, fulldecl);
    204          }
    205          break;
    206 
    207       case TGSI_TOKEN_TYPE_IMMEDIATE:
    208          {
    209             struct tgsi_full_immediate *fullimm
    210                = &parse.FullToken.FullImmediate;
    211 
    212             if (ctx->transform_immediate)
    213                ctx->transform_immediate(ctx, fullimm);
    214             else
    215                ctx->emit_immediate(ctx, fullimm);
    216          }
    217          break;
    218       case TGSI_TOKEN_TYPE_PROPERTY:
    219          {
    220             struct tgsi_full_property *fullprop
    221                = &parse.FullToken.FullProperty;
    222 
    223             if (ctx->transform_property)
    224                ctx->transform_property(ctx, fullprop);
    225             else
    226                ctx->emit_property(ctx, fullprop);
    227          }
    228          break;
    229 
    230       default:
    231          assert( 0 );
    232       }
    233    }
    234 
    235    tgsi_parse_free (&parse);
    236 
    237    return ctx->ti;
    238 }
    239 
    240 
    241 #include "tgsi_text.h"
    242 
    243 extern int tgsi_transform_foo( struct tgsi_token *tokens_out,
    244                                uint max_tokens_out );
    245 
    246 /* This function exists only so that tgsi_text_translate() doesn't get
    247  * magic-ed out of the libtgsi.a archive by the build system.  Don't
    248  * remove unless you know this has been fixed - check on mingw/scons
    249  * builds as well.
    250  */
    251 int
    252 tgsi_transform_foo( struct tgsi_token *tokens_out,
    253                     uint max_tokens_out )
    254 {
    255    const char *text =
    256       "FRAG\n"
    257       "DCL IN[0], COLOR, CONSTANT\n"
    258       "DCL OUT[0], COLOR\n"
    259       "  0: MOV OUT[0], IN[0]\n"
    260       "  1: END";
    261 
    262    return tgsi_text_translate( text,
    263                                tokens_out,
    264                                max_tokens_out );
    265 }
    266