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 "main/macros.h"
     34 #include "brw_context.h"
     35 #include "brw_vs.h"
     36 
     37 /* Component is active if it may diverge from [0,0,0,1].  Undef values
     38  * are promoted to [0,0,0,1] for the purposes of this analysis.
     39  */
     40 struct tracker {
     41    bool twoside;
     42    GLubyte active[PROGRAM_OUTPUT+1][MAX_PROGRAM_TEMPS];
     43    GLbitfield size_masks[4];  /**< one bit per fragment program input attrib */
     44 };
     45 
     46 
     47 static void set_active_component( struct tracker *t,
     48 				  GLuint file,
     49 				  GLuint index,
     50 				  GLubyte active )
     51 {
     52    switch (file) {
     53    case PROGRAM_TEMPORARY:
     54    case PROGRAM_INPUT:
     55    case PROGRAM_OUTPUT:
     56       assert(file < PROGRAM_OUTPUT + 1);
     57       assert(index < Elements(t->active[0]));
     58       t->active[file][index] |= active;
     59       break;
     60    default:
     61       break;
     62    }
     63 }
     64 
     65 static void set_active( struct tracker *t,
     66 			struct prog_dst_register dst,
     67 			GLuint active )
     68 {
     69    set_active_component( t, dst.File, dst.Index, active & dst.WriteMask );
     70 }
     71 
     72 
     73 static GLubyte get_active_component( struct tracker *t,
     74 				     GLuint file,
     75 				     GLuint index,
     76 				     GLuint component,
     77 				     GLubyte swz )
     78 {
     79    switch (swz) {
     80    case SWIZZLE_ZERO:
     81       return component < 3 ? 0 : (1<<component);
     82    case SWIZZLE_ONE:
     83       return component == 3 ? 0 : (1<<component);
     84    default:
     85       switch (file) {
     86       case PROGRAM_TEMPORARY:
     87       case PROGRAM_INPUT:
     88       case PROGRAM_OUTPUT:
     89 	 return t->active[file][index] & (1<<component);
     90       default:
     91 	 return 1 << component;
     92       }
     93    }
     94 }
     95 
     96 
     97 static GLubyte get_active( struct tracker *t,
     98 			   struct prog_src_register src )
     99 {
    100    GLuint i;
    101    GLubyte active = src.Negate; /* NOTE! */
    102 
    103    if (src.RelAddr)
    104       return 0xf;
    105 
    106    for (i = 0; i < 4; i++)
    107       active |= get_active_component(t, src.File, src.Index, i,
    108 				     GET_SWZ(src.Swizzle, i));
    109 
    110    return active;
    111 }
    112 
    113 /**
    114  * Return the size (1,2,3 or 4) of the output/result for VERT_RESULT_idx.
    115  */
    116 static GLubyte get_output_size( struct tracker *t,
    117 				GLuint idx )
    118 {
    119    GLubyte active;
    120    assert(idx < VERT_RESULT_MAX);
    121    active = t->active[PROGRAM_OUTPUT][idx];
    122    if (active & (1<<3)) return 4;
    123    if (active & (1<<2)) return 3;
    124    if (active & (1<<1)) return 2;
    125    if (active & (1<<0)) return 1;
    126    return 0;
    127 }
    128 
    129 /* Note the potential copying that occurs in the setup program:
    130  */
    131 static void calc_sizes( struct tracker *t )
    132 {
    133    GLint vertRes;
    134 
    135    if (t->twoside) {
    136       t->active[PROGRAM_OUTPUT][VERT_RESULT_COL0] |=
    137 	 t->active[PROGRAM_OUTPUT][VERT_RESULT_BFC0];
    138 
    139       t->active[PROGRAM_OUTPUT][VERT_RESULT_COL1] |=
    140 	 t->active[PROGRAM_OUTPUT][VERT_RESULT_BFC1];
    141    }
    142 
    143    /* Examine vertex program output sizes to set the size_masks[] info
    144     * which describes the fragment program input sizes.
    145     */
    146    for (vertRes = 0; vertRes < VERT_RESULT_MAX; vertRes++) {
    147 
    148       /* map vertex program output index to fragment program input index */
    149       GLint fragAttrib = _mesa_vert_result_to_frag_attrib(vertRes);
    150       if (fragAttrib < 0)
    151          continue;
    152 
    153       switch (get_output_size(t, vertRes)) {
    154       case 4: t->size_masks[4-1] |= 1 << fragAttrib;
    155       case 3: t->size_masks[3-1] |= 1 << fragAttrib;
    156       case 2: t->size_masks[2-1] |= 1 << fragAttrib;
    157       case 1: t->size_masks[1-1] |= 1 << fragAttrib;
    158 	 break;
    159       }
    160    }
    161 }
    162 
    163 static GLubyte szflag[4+1] = {
    164    0,
    165    0x1,
    166    0x3,
    167    0x7,
    168    0xf
    169 };
    170 
    171 /* Pull a size out of the packed array:
    172  */
    173 static GLuint get_input_size(struct brw_context *brw,
    174 			     GLuint attr)
    175 {
    176    GLuint sizes_dword = brw->vb.info.sizes[attr/16];
    177    GLuint sizes_bits = (sizes_dword>>((attr%16)*2)) & 0x3;
    178    return sizes_bits + 1;
    179 /*    return brw->vb.inputs[attr].glarray->Size; */
    180 }
    181 
    182 /* Calculate sizes of vertex program outputs.  Size is the largest
    183  * component index which might vary from [0,0,0,1]
    184  */
    185 static void calc_wm_input_sizes( struct brw_context *brw )
    186 {
    187    struct gl_context *ctx = &brw->intel.ctx;
    188    /* BRW_NEW_VERTEX_PROGRAM */
    189    const struct brw_vertex_program *vp =
    190       brw_vertex_program_const(brw->vertex_program);
    191    /* BRW_NEW_INPUT_DIMENSIONS */
    192    struct tracker t;
    193    GLuint insn;
    194    GLuint i;
    195 
    196    /* Mesa IR is not generated for GLSL vertex shaders.  If there's no Mesa
    197     * IR, the code below cannot determine which output components are
    198     * written.  So, skip it and assume everything is written.  This
    199     * circumvents some optimizations in the fragment shader, but it guarantees
    200     * that correct code is generated.
    201     */
    202    if (vp->program.Base.NumInstructions == 0) {
    203       brw->wm.input_size_masks[0] = ~0;
    204       brw->wm.input_size_masks[1] = ~0;
    205       brw->wm.input_size_masks[2] = ~0;
    206       brw->wm.input_size_masks[3] = ~0;
    207       return;
    208    }
    209 
    210 
    211    memset(&t, 0, sizeof(t));
    212 
    213    /* _NEW_LIGHT | _NEW_PROGRAM */
    214    if (ctx->VertexProgram._TwoSideEnabled)
    215       t.twoside = 1;
    216 
    217    for (i = 0; i < VERT_ATTRIB_MAX; i++)
    218       if (vp->program.Base.InputsRead & BITFIELD64_BIT(i))
    219 	 set_active_component(&t, PROGRAM_INPUT, i,
    220 			      szflag[get_input_size(brw, i)]);
    221 
    222    for (insn = 0; insn < vp->program.Base.NumInstructions; insn++) {
    223       struct prog_instruction *inst = &vp->program.Base.Instructions[insn];
    224 
    225       switch (inst->Opcode) {
    226       case OPCODE_ARL:
    227 	 break;
    228 
    229       case OPCODE_MOV:
    230 	 set_active(&t, inst->DstReg, get_active(&t, inst->SrcReg[0]));
    231 	 break;
    232 
    233       default:
    234 	 set_active(&t, inst->DstReg, 0xf);
    235 	 break;
    236       }
    237    }
    238 
    239    calc_sizes(&t);
    240 
    241    if (memcmp(brw->wm.input_size_masks, t.size_masks, sizeof(t.size_masks)) != 0) {
    242       memcpy(brw->wm.input_size_masks, t.size_masks, sizeof(t.size_masks));
    243       brw->state.dirty.brw |= BRW_NEW_WM_INPUT_DIMENSIONS;
    244    }
    245 }
    246 
    247 const struct brw_tracked_state brw_wm_input_sizes = {
    248    .dirty = {
    249       .mesa  = _NEW_LIGHT | _NEW_PROGRAM,
    250       .brw   = BRW_NEW_VERTEX_PROGRAM | BRW_NEW_INPUT_DIMENSIONS,
    251       .cache = 0
    252    },
    253    .emit = calc_wm_input_sizes
    254 };
    255 
    256