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