Home | History | Annotate | Download | only in i965
      1 /*
      2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
      3  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
      4  develop this 3D driver.
      5 
      6  Permission is hereby granted, free of charge, to any person obtaining
      7  a 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, sublicense, 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
     16  portions of the Software.
     17 
     18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     21  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
     22  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     23  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     24  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25 
     26  **********************************************************************/
     27  /*
     28   * Authors:
     29   *   Keith Whitwell <keith (at) tungstengraphics.com>
     30   */
     31 
     32 
     33 #include "brw_context.h"
     34 #include "brw_wm.h"
     35 #include "program/prog_parameter.h"
     36 
     37 
     38 
     39 /***********************************************************************
     40  */
     41 
     42 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
     43 {
     44    assert(c->nr_refs < BRW_WM_MAX_REF);
     45    memset(&c->refs[c->nr_refs], 0, sizeof(*c->refs));
     46    return &c->refs[c->nr_refs++];
     47 }
     48 
     49 static struct brw_wm_value *get_value( struct brw_wm_compile *c)
     50 {
     51    assert(c->nr_refs < BRW_WM_MAX_VREG);
     52    memset(&c->vreg[c->nr_vreg], 0, sizeof(*c->vreg));
     53    return &c->vreg[c->nr_vreg++];
     54 }
     55 
     56 /** return pointer to a newly allocated instruction */
     57 static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
     58 {
     59    assert(c->nr_insns < BRW_WM_MAX_INSN);
     60    memset(&c->instruction[c->nr_insns], 0, sizeof(*c->instruction));
     61    return &c->instruction[c->nr_insns++];
     62 }
     63 
     64 /***********************************************************************
     65  */
     66 
     67 /** Init the "undef" register */
     68 static void pass0_init_undef( struct brw_wm_compile *c)
     69 {
     70    struct brw_wm_ref *ref = &c->undef_ref;
     71    ref->value = &c->undef_value;
     72    ref->hw_reg = brw_vec8_grf(0, 0);
     73    ref->insn = 0;
     74    ref->prevuse = NULL;
     75 }
     76 
     77 /** Set a FP register to a value */
     78 static void pass0_set_fpreg_value( struct brw_wm_compile *c,
     79 				   GLuint file,
     80 				   GLuint idx,
     81 				   GLuint component,
     82 				   struct brw_wm_value *value )
     83 {
     84    struct brw_wm_ref *ref = get_ref(c);
     85    ref->value = value;
     86    ref->hw_reg = brw_vec8_grf(0, 0);
     87    ref->insn = 0;
     88    ref->prevuse = NULL;
     89    c->pass0_fp_reg[file][idx][component] = ref;
     90 }
     91 
     92 /** Set a FP register to a ref */
     93 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
     94 				 GLuint file,
     95 				 GLuint idx,
     96 				 GLuint component,
     97 				 const struct brw_wm_ref *src_ref )
     98 {
     99    c->pass0_fp_reg[file][idx][component] = src_ref;
    100 }
    101 
    102 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
    103 					       const GLfloat *param_ptr )
    104 {
    105    GLuint i = c->prog_data.nr_params++;
    106 
    107    if (i >= BRW_WM_MAX_PARAM) {
    108       printf("%s: out of params\n", __FUNCTION__);
    109       c->prog_data.error = 1;
    110       return NULL;
    111    }
    112    else {
    113       struct brw_wm_ref *ref = get_ref(c);
    114 
    115       c->prog_data.param[i] = param_ptr;
    116       c->nr_creg = (i+16)/16;
    117 
    118       /* Push the offsets into hw_reg.  These will be added to the
    119        * real register numbers once one is allocated in pass2.
    120        */
    121       ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
    122       ref->value = &c->creg[i/16];
    123       ref->insn = 0;
    124       ref->prevuse = NULL;
    125 
    126       return ref;
    127    }
    128 }
    129 
    130 
    131 /** Return a ref to a constant/literal value */
    132 static const struct brw_wm_ref *get_const_ref( struct brw_wm_compile *c,
    133 					       const GLfloat *constval )
    134 {
    135    GLuint i;
    136 
    137    /* Search for an existing const value matching the request:
    138     */
    139    for (i = 0; i < c->nr_constrefs; i++) {
    140       if (c->constref[i].constval == *constval)
    141 	 return c->constref[i].ref;
    142    }
    143 
    144    /* Else try to add a new one:
    145     */
    146    if (c->nr_constrefs < BRW_WM_MAX_CONST) {
    147       GLuint i = c->nr_constrefs++;
    148 
    149       /* A constant is a special type of parameter:
    150        */
    151       c->constref[i].constval = *constval;
    152       c->constref[i].ref = get_param_ref(c, constval);
    153 
    154       return c->constref[i].ref;
    155    }
    156    else {
    157       printf("%s: out of constrefs\n", __FUNCTION__);
    158       c->prog_data.error = 1;
    159       return NULL;
    160    }
    161 }
    162 
    163 
    164 /* Lookup our internal registers
    165  */
    166 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
    167 					       GLuint file,
    168 					       GLuint idx,
    169 					       GLuint component )
    170 {
    171    const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
    172 
    173    if (!ref) {
    174       switch (file) {
    175       case PROGRAM_INPUT:
    176       case PROGRAM_PAYLOAD:
    177       case PROGRAM_TEMPORARY:
    178       case PROGRAM_OUTPUT:
    179       case PROGRAM_VARYING:
    180 	 break;
    181 
    182       case PROGRAM_LOCAL_PARAM:
    183 	 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
    184 	 break;
    185 
    186       case PROGRAM_ENV_PARAM:
    187 	 ref = get_param_ref(c, &c->env_param[idx][component]);
    188 	 break;
    189 
    190       case PROGRAM_STATE_VAR:
    191       case PROGRAM_UNIFORM:
    192       case PROGRAM_CONSTANT:
    193       case PROGRAM_NAMED_PARAM: {
    194 	 struct gl_program_parameter_list *plist = c->fp->program.Base.Parameters;
    195 
    196 	 /* There's something really hokey about parameters parsed in
    197 	  * arb programs - they all end up in here, whether they be
    198 	  * state values, parameters or constants.  This duplicates the
    199 	  * structure above & also seems to subvert the limits set for
    200 	  * each type of constant/param.
    201 	  */
    202 	 switch (plist->Parameters[idx].Type) {
    203 	 case PROGRAM_NAMED_PARAM:
    204 	 case PROGRAM_CONSTANT:
    205 	    /* These are invariant:
    206 	     */
    207 	    ref = get_const_ref(c, &plist->ParameterValues[idx][component].f);
    208 	    break;
    209 
    210 	 case PROGRAM_STATE_VAR:
    211 	 case PROGRAM_UNIFORM:
    212 	    /* These may change from run to run:
    213 	     */
    214 	    ref = get_param_ref(c, &plist->ParameterValues[idx][component].f );
    215 	    break;
    216 
    217 	 default:
    218 	    assert(0);
    219 	    break;
    220 	 }
    221 	 break;
    222       }
    223 
    224       default:
    225 	 assert(0);
    226 	 break;
    227       }
    228 
    229       c->pass0_fp_reg[file][idx][component] = ref;
    230    }
    231 
    232    if (!ref)
    233       ref = &c->undef_ref;
    234 
    235    return ref;
    236 }
    237 
    238 
    239 
    240 /***********************************************************************
    241  * Straight translation to internal instruction format
    242  */
    243 
    244 static void pass0_set_dst( struct brw_wm_compile *c,
    245 			   struct brw_wm_instruction *out,
    246 			   const struct prog_instruction *inst,
    247 			   GLuint writemask )
    248 {
    249    const struct prog_dst_register *dst = &inst->DstReg;
    250    GLuint i;
    251 
    252    for (i = 0; i < 4; i++) {
    253       if (writemask & (1<<i)) {
    254 	 out->dst[i] = get_value(c);
    255 	 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[i]);
    256       }
    257    }
    258 
    259    out->writemask = writemask;
    260 }
    261 
    262 
    263 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
    264 						    struct prog_src_register src,
    265 						    GLuint i )
    266 {
    267    GLuint component = GET_SWZ(src.Swizzle,i);
    268    const struct brw_wm_ref *src_ref;
    269    static const GLfloat const_zero = 0.0;
    270    static const GLfloat const_one = 1.0;
    271 
    272    if (component == SWIZZLE_ZERO)
    273       src_ref = get_const_ref(c, &const_zero);
    274    else if (component == SWIZZLE_ONE)
    275       src_ref = get_const_ref(c, &const_one);
    276    else
    277       src_ref = pass0_get_reg(c, src.File, src.Index, component);
    278 
    279    return src_ref;
    280 }
    281 
    282 
    283 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
    284 				       struct prog_src_register src,
    285 				       GLuint i,
    286 				       struct brw_wm_instruction *insn)
    287 {
    288    const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
    289    struct brw_wm_ref *newref = get_ref(c);
    290 
    291    newref->value = ref->value;
    292    newref->hw_reg = ref->hw_reg;
    293 
    294    if (insn) {
    295       newref->insn = insn - c->instruction;
    296       newref->prevuse = newref->value->lastuse;
    297       newref->value->lastuse = newref;
    298    }
    299 
    300    if (src.Negate & (1 << i))
    301       newref->hw_reg.negate ^= 1;
    302 
    303    if (src.Abs) {
    304       newref->hw_reg.negate = 0;
    305       newref->hw_reg.abs = 1;
    306    }
    307 
    308    return newref;
    309 }
    310 
    311 
    312 static void
    313 translate_insn(struct brw_wm_compile *c,
    314                const struct prog_instruction *inst)
    315 {
    316    struct brw_wm_instruction *out = get_instruction(c);
    317    GLuint writemask = inst->DstReg.WriteMask;
    318    GLuint nr_args = brw_wm_nr_args(inst->Opcode);
    319    GLuint i, j;
    320 
    321    /* Copy some data out of the instruction
    322     */
    323    out->opcode = inst->Opcode;
    324    out->saturate = (inst->SaturateMode != SATURATE_OFF);
    325    out->tex_unit = inst->TexSrcUnit;
    326    out->tex_idx = inst->TexSrcTarget;
    327    out->tex_shadow = inst->TexShadow;
    328    out->eot = inst->Aux & INST_AUX_EOT;
    329    out->target = INST_AUX_GET_TARGET(inst->Aux);
    330 
    331    /* Args:
    332     */
    333    for (i = 0; i < nr_args; i++) {
    334       for (j = 0; j < 4; j++) {
    335 	 out->src[i][j] = get_new_ref(c, inst->SrcReg[i], j, out);
    336       }
    337    }
    338 
    339    /* Dst:
    340     */
    341    pass0_set_dst(c, out, inst, writemask);
    342 }
    343 
    344 
    345 
    346 /***********************************************************************
    347  * Optimize moves and swizzles away:
    348  */
    349 static void pass0_precalc_mov( struct brw_wm_compile *c,
    350 			       const struct prog_instruction *inst )
    351 {
    352    const struct prog_dst_register *dst = &inst->DstReg;
    353    GLuint writemask = inst->DstReg.WriteMask;
    354    struct brw_wm_ref *refs[4];
    355    GLuint i;
    356 
    357    /* Get the effect of a MOV by manipulating our register table:
    358     * First get all refs, then assign refs.  This ensures that "in-place"
    359     * swizzles such as:
    360     *   MOV t, t.xxyx
    361     * are handled correctly.  Previously, these two steps were done in
    362     * one loop and the above case was incorrectly handled.
    363     */
    364    for (i = 0; i < 4; i++) {
    365       refs[i] = get_new_ref(c, inst->SrcReg[0], i, NULL);
    366    }
    367    for (i = 0; i < 4; i++) {
    368       if (writemask & (1 << i)) {
    369          pass0_set_fpreg_ref( c, dst->File, dst->Index, i, refs[i]);
    370       }
    371    }
    372 }
    373 
    374 
    375 /* Initialize payload "registers".
    376  */
    377 static void pass0_init_payload( struct brw_wm_compile *c )
    378 {
    379    GLuint i;
    380 
    381    for (i = 0; i < 4; i++) {
    382       GLuint j = i >= (c->nr_payload_regs + 1) / 2 ? 0 : i;
    383       pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i,
    384 			     &c->payload.depth[j] );
    385    }
    386 
    387 #if 0
    388    /* This seems to be an alternative to the INTERP_WPOS stuff I do
    389     * elsewhere:
    390     */
    391    if (c->key.source_depth_reg)
    392       pass0_set_fpreg_value(c, PROGRAM_INPUT, FRAG_ATTRIB_WPOS, 2,
    393 			    &c->payload.depth[c->key.source_depth_reg/2]);
    394 #endif
    395 
    396    for (i = 0; i < FRAG_ATTRIB_MAX; i++)
    397       pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, i, 0,
    398 			     &c->payload.input_interp[i] );
    399 }
    400 
    401 
    402 /***********************************************************************
    403  * PASS 0
    404  *
    405  * Work forwards to give each calculated value a unique number.  Where
    406  * an instruction produces duplicate values (eg DP3), all are given
    407  * the same number.
    408  *
    409  * Translate away swizzling and eliminate non-saturating moves.
    410  */
    411 void brw_wm_pass0( struct brw_wm_compile *c )
    412 {
    413    GLuint insn;
    414 
    415    c->nr_vreg = 0;
    416    c->nr_insns = 0;
    417 
    418    pass0_init_undef(c);
    419    pass0_init_payload(c);
    420 
    421    for (insn = 0; insn < c->nr_fp_insns; insn++) {
    422       const struct prog_instruction *inst = &c->prog_instructions[insn];
    423 
    424       /* Optimize away moves, otherwise emit translated instruction:
    425        */
    426       switch (inst->Opcode) {
    427       case OPCODE_MOV:
    428       case OPCODE_SWZ:
    429 	 if (!inst->SaturateMode) {
    430 	    pass0_precalc_mov(c, inst);
    431 	 }
    432 	 else {
    433 	    translate_insn(c, inst);
    434 	 }
    435 	 break;
    436       default:
    437 	 translate_insn(c, inst);
    438 	 break;
    439       }
    440    }
    441 
    442    if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
    443       brw_wm_print_program(c, "pass0");
    444    }
    445 }
    446