Home | History | Annotate | Download | only in compiler
      1 /*
      2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
      3  Intel funded Tungsten Graphics 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 <keithw (at) vmware.com>
     30   */
     31 
     32 #include "main/macros.h"
     33 #include "main/enums.h"
     34 #include "program/program.h"
     35 
     36 #include "brw_clip.h"
     37 
     38 
     39 /* This is performed against the original triangles, so no indirection
     40  * required:
     41 BZZZT!
     42  */
     43 static void compute_tri_direction( struct brw_clip_compile *c )
     44 {
     45    struct brw_codegen *p = &c->func;
     46    struct brw_reg e = c->reg.tmp0;
     47    struct brw_reg f = c->reg.tmp1;
     48    GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
     49    struct brw_reg v0 = byte_offset(c->reg.vertex[0], hpos_offset);
     50    struct brw_reg v1 = byte_offset(c->reg.vertex[1], hpos_offset);
     51    struct brw_reg v2 = byte_offset(c->reg.vertex[2], hpos_offset);
     52 
     53 
     54    struct brw_reg v0n = get_tmp(c);
     55    struct brw_reg v1n = get_tmp(c);
     56    struct brw_reg v2n = get_tmp(c);
     57 
     58    /* Convert to NDC.
     59     * NOTE: We can't modify the original vertex coordinates,
     60     * as it may impact further operations.
     61     * So, we have to keep normalized coordinates in temp registers.
     62     *
     63     * TBD-KC
     64     * Try to optimize unnecessary MOV's.
     65     */
     66    brw_MOV(p, v0n, v0);
     67    brw_MOV(p, v1n, v1);
     68    brw_MOV(p, v2n, v2);
     69 
     70    brw_clip_project_position(c, v0n);
     71    brw_clip_project_position(c, v1n);
     72    brw_clip_project_position(c, v2n);
     73 
     74    /* Calculate the vectors of two edges of the triangle:
     75     */
     76    brw_ADD(p, e, v0n, negate(v2n));
     77    brw_ADD(p, f, v1n, negate(v2n));
     78 
     79    /* Take their crossproduct:
     80     */
     81    brw_set_default_access_mode(p, BRW_ALIGN_16);
     82    brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, BRW_SWIZZLE_YZXW),
     83            brw_swizzle(f, BRW_SWIZZLE_ZXYW));
     84    brw_MAC(p, vec4(e),  negate(brw_swizzle(e, BRW_SWIZZLE_ZXYW)),
     85            brw_swizzle(f, BRW_SWIZZLE_YZXW));
     86    brw_set_default_access_mode(p, BRW_ALIGN_1);
     87 
     88    brw_MUL(p, c->reg.dir, c->reg.dir, vec4(e));
     89 }
     90 
     91 
     92 static void cull_direction( struct brw_clip_compile *c )
     93 {
     94    struct brw_codegen *p = &c->func;
     95    GLuint conditional;
     96 
     97    assert (!(c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL &&
     98 	     c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL));
     99 
    100    if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL)
    101       conditional = BRW_CONDITIONAL_GE;
    102    else
    103       conditional = BRW_CONDITIONAL_L;
    104 
    105    brw_CMP(p,
    106 	   vec1(brw_null_reg()),
    107 	   conditional,
    108 	   get_element(c->reg.dir, 2),
    109 	   brw_imm_f(0));
    110 
    111    brw_IF(p, BRW_EXECUTE_1);
    112    {
    113       brw_clip_kill_thread(c);
    114    }
    115    brw_ENDIF(p);
    116 }
    117 
    118 
    119 
    120 static void copy_bfc( struct brw_clip_compile *c )
    121 {
    122    struct brw_codegen *p = &c->func;
    123    GLuint conditional;
    124 
    125    /* Do we have any colors to copy?
    126     */
    127    if (!(brw_clip_have_varying(c, VARYING_SLOT_COL0) &&
    128          brw_clip_have_varying(c, VARYING_SLOT_BFC0)) &&
    129        !(brw_clip_have_varying(c, VARYING_SLOT_COL1) &&
    130          brw_clip_have_varying(c, VARYING_SLOT_BFC1)))
    131       return;
    132 
    133    /* In some weird degenerate cases we can end up testing the
    134     * direction twice, once for culling and once for bfc copying.  Oh
    135     * well, that's what you get for setting weird GL state.
    136     */
    137    if (c->key.copy_bfc_ccw)
    138       conditional = BRW_CONDITIONAL_GE;
    139    else
    140       conditional = BRW_CONDITIONAL_L;
    141 
    142    brw_CMP(p,
    143 	   vec1(brw_null_reg()),
    144 	   conditional,
    145 	   get_element(c->reg.dir, 2),
    146 	   brw_imm_f(0));
    147 
    148    brw_IF(p, BRW_EXECUTE_1);
    149    {
    150       GLuint i;
    151 
    152       for (i = 0; i < 3; i++) {
    153 	 if (brw_clip_have_varying(c, VARYING_SLOT_COL0) &&
    154              brw_clip_have_varying(c, VARYING_SLOT_BFC0))
    155 	    brw_MOV(p,
    156 		    byte_offset(c->reg.vertex[i],
    157                                 brw_varying_to_offset(&c->vue_map,
    158                                                       VARYING_SLOT_COL0)),
    159 		    byte_offset(c->reg.vertex[i],
    160                                 brw_varying_to_offset(&c->vue_map,
    161                                                       VARYING_SLOT_BFC0)));
    162 
    163 	 if (brw_clip_have_varying(c, VARYING_SLOT_COL1) &&
    164              brw_clip_have_varying(c, VARYING_SLOT_BFC1))
    165 	    brw_MOV(p,
    166 		    byte_offset(c->reg.vertex[i],
    167                                 brw_varying_to_offset(&c->vue_map,
    168                                                       VARYING_SLOT_COL1)),
    169 		    byte_offset(c->reg.vertex[i],
    170                                 brw_varying_to_offset(&c->vue_map,
    171                                                       VARYING_SLOT_BFC1)));
    172       }
    173    }
    174    brw_ENDIF(p);
    175 }
    176 
    177 
    178 
    179 
    180 /*
    181   GLfloat iz	= 1.0 / dir.z;
    182   GLfloat ac	= dir.x * iz;
    183   GLfloat bc	= dir.y * iz;
    184   offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
    185   offset += MAX2( abs(ac), abs(bc) ) * ctx->Polygon.OffsetFactor;
    186   if (ctx->Polygon.OffsetClamp && isfinite(ctx->Polygon.OffsetClamp)) {
    187     if (ctx->Polygon.OffsetClamp < 0)
    188       offset = MAX2( offset, ctx->Polygon.OffsetClamp );
    189     else
    190       offset = MIN2( offset, ctx->Polygon.OffsetClamp );
    191   }
    192   offset *= MRD;
    193 */
    194 static void compute_offset( struct brw_clip_compile *c )
    195 {
    196    struct brw_codegen *p = &c->func;
    197    struct brw_reg off = c->reg.offset;
    198    struct brw_reg dir = c->reg.dir;
    199 
    200    brw_math_invert(p, get_element(off, 2), get_element(dir, 2));
    201    brw_MUL(p, vec2(off), vec2(dir), get_element(off, 2));
    202 
    203    brw_CMP(p,
    204 	   vec1(brw_null_reg()),
    205 	   BRW_CONDITIONAL_GE,
    206 	   brw_abs(get_element(off, 0)),
    207 	   brw_abs(get_element(off, 1)));
    208 
    209    brw_SEL(p, vec1(off),
    210            brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1)));
    211    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    212 
    213    brw_MUL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_factor));
    214    brw_ADD(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_units));
    215    if (c->key.offset_clamp && isfinite(c->key.offset_clamp)) {
    216       brw_CMP(p,
    217               vec1(brw_null_reg()),
    218               c->key.offset_clamp < 0 ? BRW_CONDITIONAL_GE : BRW_CONDITIONAL_L,
    219               vec1(off),
    220               brw_imm_f(c->key.offset_clamp));
    221       brw_SEL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_clamp));
    222    }
    223 }
    224 
    225 
    226 static void merge_edgeflags( struct brw_clip_compile *c )
    227 {
    228    struct brw_codegen *p = &c->func;
    229    struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0);
    230 
    231    brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
    232    brw_CMP(p,
    233 	   vec1(brw_null_reg()),
    234 	   BRW_CONDITIONAL_EQ,
    235 	   tmp0,
    236 	   brw_imm_ud(_3DPRIM_POLYGON));
    237 
    238    /* Get away with using reg.vertex because we know that this is not
    239     * a _3DPRIM_TRISTRIP_REVERSE:
    240     */
    241    brw_IF(p, BRW_EXECUTE_1);
    242    {
    243       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8));
    244       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ);
    245       brw_MOV(p, byte_offset(c->reg.vertex[0],
    246                              brw_varying_to_offset(&c->vue_map,
    247                                                    VARYING_SLOT_EDGE)),
    248               brw_imm_f(0));
    249       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    250 
    251       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9));
    252       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ);
    253       brw_MOV(p, byte_offset(c->reg.vertex[2],
    254                              brw_varying_to_offset(&c->vue_map,
    255                                                    VARYING_SLOT_EDGE)),
    256               brw_imm_f(0));
    257       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    258    }
    259    brw_ENDIF(p);
    260 }
    261 
    262 
    263 
    264 static void apply_one_offset( struct brw_clip_compile *c,
    265 			  struct brw_indirect vert )
    266 {
    267    struct brw_codegen *p = &c->func;
    268    GLuint ndc_offset = brw_varying_to_offset(&c->vue_map,
    269                                              BRW_VARYING_SLOT_NDC);
    270    struct brw_reg z = deref_1f(vert, ndc_offset +
    271 			       2 * type_sz(BRW_REGISTER_TYPE_F));
    272 
    273    brw_ADD(p, z, z, vec1(c->reg.offset));
    274 }
    275 
    276 
    277 
    278 /***********************************************************************
    279  * Output clipped polygon as an unfilled primitive:
    280  */
    281 static void emit_lines(struct brw_clip_compile *c,
    282 		       bool do_offset)
    283 {
    284    struct brw_codegen *p = &c->func;
    285    struct brw_indirect v0 = brw_indirect(0, 0);
    286    struct brw_indirect v1 = brw_indirect(1, 0);
    287    struct brw_indirect v0ptr = brw_indirect(2, 0);
    288    struct brw_indirect v1ptr = brw_indirect(3, 0);
    289 
    290    /* Need a separate loop for offset:
    291     */
    292    if (do_offset) {
    293       brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    294       brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    295 
    296       brw_DO(p, BRW_EXECUTE_1);
    297       {
    298 	 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    299 	 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    300 
    301 	 apply_one_offset(c, v0);
    302 
    303 	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    304          brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_G);
    305       }
    306       brw_WHILE(p);
    307       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    308    }
    309 
    310    /* v1ptr = &inlist[nr_verts]
    311     * *v1ptr = v0
    312     */
    313    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    314    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    315    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
    316    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
    317    brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0));
    318 
    319    brw_DO(p, BRW_EXECUTE_1);
    320    {
    321       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    322       brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2));
    323       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    324 
    325       /* draw edge if edgeflag != 0 */
    326       brw_CMP(p,
    327 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
    328 	      deref_1f(v0, brw_varying_to_offset(&c->vue_map,
    329                                                  VARYING_SLOT_EDGE)),
    330 	      brw_imm_f(0));
    331       brw_IF(p, BRW_EXECUTE_1);
    332       {
    333 	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
    334                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
    335                            | URB_WRITE_PRIM_START);
    336 	 brw_clip_emit_vue(c, v1, BRW_URB_WRITE_ALLOCATE_COMPLETE,
    337                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
    338                            | URB_WRITE_PRIM_END);
    339       }
    340       brw_ENDIF(p);
    341 
    342       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    343       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
    344    }
    345    brw_WHILE(p);
    346    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    347 }
    348 
    349 
    350 
    351 static void emit_points(struct brw_clip_compile *c,
    352 			bool do_offset )
    353 {
    354    struct brw_codegen *p = &c->func;
    355 
    356    struct brw_indirect v0 = brw_indirect(0, 0);
    357    struct brw_indirect v0ptr = brw_indirect(2, 0);
    358 
    359    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    360    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    361 
    362    brw_DO(p, BRW_EXECUTE_1);
    363    {
    364       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    365       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    366 
    367       /* draw if edgeflag != 0
    368        */
    369       brw_CMP(p,
    370 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
    371 	      deref_1f(v0, brw_varying_to_offset(&c->vue_map,
    372                                                  VARYING_SLOT_EDGE)),
    373 	      brw_imm_f(0));
    374       brw_IF(p, BRW_EXECUTE_1);
    375       {
    376 	 if (do_offset)
    377 	    apply_one_offset(c, v0);
    378 
    379 	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
    380                            (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT)
    381                            | URB_WRITE_PRIM_START | URB_WRITE_PRIM_END);
    382       }
    383       brw_ENDIF(p);
    384 
    385       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    386       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
    387    }
    388    brw_WHILE(p);
    389    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
    390 }
    391 
    392 
    393 
    394 
    395 
    396 
    397 
    398 static void emit_primitives( struct brw_clip_compile *c,
    399 			     GLuint mode,
    400 			     bool do_offset )
    401 {
    402    switch (mode) {
    403    case BRW_CLIP_FILL_MODE_FILL:
    404       brw_clip_tri_emit_polygon(c);
    405       break;
    406 
    407    case BRW_CLIP_FILL_MODE_LINE:
    408       emit_lines(c, do_offset);
    409       break;
    410 
    411    case BRW_CLIP_FILL_MODE_POINT:
    412       emit_points(c, do_offset);
    413       break;
    414 
    415    case BRW_CLIP_FILL_MODE_CULL:
    416       unreachable("not reached");
    417    }
    418 }
    419 
    420 
    421 
    422 static void emit_unfilled_primitives( struct brw_clip_compile *c )
    423 {
    424    struct brw_codegen *p = &c->func;
    425 
    426    /* Direction culling has already been done.
    427     */
    428    if (c->key.fill_ccw != c->key.fill_cw &&
    429        c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL &&
    430        c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL)
    431    {
    432       brw_CMP(p,
    433 	      vec1(brw_null_reg()),
    434 	      BRW_CONDITIONAL_GE,
    435 	      get_element(c->reg.dir, 2),
    436 	      brw_imm_f(0));
    437 
    438       brw_IF(p, BRW_EXECUTE_1);
    439       {
    440 	 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
    441       }
    442       brw_ELSE(p);
    443       {
    444 	 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
    445       }
    446       brw_ENDIF(p);
    447    }
    448    else if (c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL) {
    449       emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
    450    }
    451    else if (c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL) {
    452       emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
    453    }
    454 }
    455 
    456 
    457 
    458 
    459 static void check_nr_verts( struct brw_clip_compile *c )
    460 {
    461    struct brw_codegen *p = &c->func;
    462 
    463    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3));
    464    brw_IF(p, BRW_EXECUTE_1);
    465    {
    466       brw_clip_kill_thread(c);
    467    }
    468    brw_ENDIF(p);
    469 }
    470 
    471 
    472 void brw_emit_unfilled_clip( struct brw_clip_compile *c )
    473 {
    474    struct brw_codegen *p = &c->func;
    475 
    476    c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) ||
    477 			(c->key.fill_ccw != c->key.fill_cw) ||
    478 			c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL ||
    479 			c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL ||
    480 			c->key.copy_bfc_cw ||
    481 			c->key.copy_bfc_ccw);
    482 
    483    brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
    484    brw_clip_tri_init_vertices(c);
    485    brw_clip_init_ff_sync(c);
    486 
    487    assert(brw_clip_have_varying(c, VARYING_SLOT_EDGE));
    488 
    489    if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL &&
    490        c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL) {
    491       brw_clip_kill_thread(c);
    492       return;
    493    }
    494 
    495    merge_edgeflags(c);
    496 
    497    /* Need to use the inlist indirection here:
    498     */
    499    if (c->need_direction)
    500       compute_tri_direction(c);
    501 
    502    if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL ||
    503        c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL)
    504       cull_direction(c);
    505 
    506    if (c->key.offset_ccw ||
    507        c->key.offset_cw)
    508       compute_offset(c);
    509 
    510    if (c->key.copy_bfc_ccw ||
    511        c->key.copy_bfc_cw)
    512       copy_bfc(c);
    513 
    514    /* Need to do this whether we clip or not:
    515     */
    516    if (c->key.contains_flat_varying)
    517       brw_clip_tri_flat_shade(c);
    518 
    519    brw_clip_init_clipmask(c);
    520    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
    521    brw_IF(p, BRW_EXECUTE_1);
    522    {
    523       brw_clip_init_planes(c);
    524       brw_clip_tri(c);
    525       check_nr_verts(c);
    526    }
    527    brw_ENDIF(p);
    528 
    529    emit_unfilled_primitives(c);
    530    brw_clip_kill_thread(c);
    531 }
    532