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 #include "main/glheader.h"
     33 #include "main/macros.h"
     34 #include "main/enums.h"
     35 #include "program/program.h"
     36 
     37 #include "intel_batchbuffer.h"
     38 
     39 #include "brw_defines.h"
     40 #include "brw_context.h"
     41 #include "brw_eu.h"
     42 #include "brw_clip.h"
     43 
     44 
     45 
     46 /* This is performed against the original triangles, so no indirection
     47  * required:
     48 BZZZT!
     49  */
     50 static void compute_tri_direction( struct brw_clip_compile *c )
     51 {
     52    struct brw_compile *p = &c->func;
     53    struct brw_reg e = c->reg.tmp0;
     54    struct brw_reg f = c->reg.tmp1;
     55    GLuint hpos_offset = brw_vert_result_to_offset(&c->vue_map,
     56                                                   VERT_RESULT_HPOS);
     57    struct brw_reg v0 = byte_offset(c->reg.vertex[0], hpos_offset);
     58    struct brw_reg v1 = byte_offset(c->reg.vertex[1], hpos_offset);
     59    struct brw_reg v2 = byte_offset(c->reg.vertex[2], hpos_offset);
     60 
     61 
     62    struct brw_reg v0n = get_tmp(c);
     63    struct brw_reg v1n = get_tmp(c);
     64    struct brw_reg v2n = get_tmp(c);
     65 
     66    /* Convert to NDC.
     67     * NOTE: We can't modify the original vertex coordinates,
     68     * as it may impact further operations.
     69     * So, we have to keep normalized coordinates in temp registers.
     70     *
     71     * TBD-KC
     72     * Try to optimize unnecessary MOV's.
     73     */
     74    brw_MOV(p, v0n, v0);
     75    brw_MOV(p, v1n, v1);
     76    brw_MOV(p, v2n, v2);
     77 
     78    brw_clip_project_position(c, v0n);
     79    brw_clip_project_position(c, v1n);
     80    brw_clip_project_position(c, v2n);
     81 
     82    /* Calculate the vectors of two edges of the triangle:
     83     */
     84    brw_ADD(p, e, v0n, negate(v2n));
     85    brw_ADD(p, f, v1n, negate(v2n));
     86 
     87    /* Take their crossproduct:
     88     */
     89    brw_set_access_mode(p, BRW_ALIGN_16);
     90    brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, 1,2,0,3),  brw_swizzle(f,2,0,1,3));
     91    brw_MAC(p, vec4(e),  negate(brw_swizzle(e, 2,0,1,3)), brw_swizzle(f,1,2,0,3));
     92    brw_set_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_compile *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_compile *p = &c->func;
    129    GLuint conditional;
    130 
    131    /* Do we have any colors to copy?
    132     */
    133    if (!(brw_clip_have_vert_result(c, VERT_RESULT_COL0) &&
    134          brw_clip_have_vert_result(c, VERT_RESULT_BFC0)) &&
    135        !(brw_clip_have_vert_result(c, VERT_RESULT_COL1) &&
    136          brw_clip_have_vert_result(c, VERT_RESULT_BFC1)))
    137       return;
    138 
    139    /* In some wierd degnerate 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 wierd 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_vert_result(c, VERT_RESULT_COL0) &&
    160              brw_clip_have_vert_result(c, VERT_RESULT_BFC0))
    161 	    brw_MOV(p,
    162 		    byte_offset(c->reg.vertex[i],
    163                                 brw_vert_result_to_offset(&c->vue_map,
    164                                                           VERT_RESULT_COL0)),
    165 		    byte_offset(c->reg.vertex[i],
    166                                 brw_vert_result_to_offset(&c->vue_map,
    167                                                           VERT_RESULT_BFC0)));
    168 
    169 	 if (brw_clip_have_vert_result(c, VERT_RESULT_COL1) &&
    170              brw_clip_have_vert_result(c, VERT_RESULT_BFC1))
    171 	    brw_MOV(p,
    172 		    byte_offset(c->reg.vertex[i],
    173                                 brw_vert_result_to_offset(&c->vue_map,
    174                                                           VERT_RESULT_COL1)),
    175 		    byte_offset(c->reg.vertex[i],
    176                                 brw_vert_result_to_offset(&c->vue_map,
    177                                                           VERT_RESULT_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   offset *= MRD;
    193 */
    194 static void compute_offset( struct brw_clip_compile *c )
    195 {
    196    struct brw_compile *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), 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), brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1)));
    210    brw_set_predicate_control(p, BRW_PREDICATE_NONE);
    211 
    212    brw_MUL(p, vec1(off), off, brw_imm_f(c->key.offset_factor));
    213    brw_ADD(p, vec1(off), off, brw_imm_f(c->key.offset_units));
    214 }
    215 
    216 
    217 static void merge_edgeflags( struct brw_clip_compile *c )
    218 {
    219    struct brw_compile *p = &c->func;
    220    struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0);
    221 
    222    brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
    223    brw_CMP(p,
    224 	   vec1(brw_null_reg()),
    225 	   BRW_CONDITIONAL_EQ,
    226 	   tmp0,
    227 	   brw_imm_ud(_3DPRIM_POLYGON));
    228 
    229    /* Get away with using reg.vertex because we know that this is not
    230     * a _3DPRIM_TRISTRIP_REVERSE:
    231     */
    232    brw_IF(p, BRW_EXECUTE_1);
    233    {
    234       brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
    235       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8));
    236       brw_MOV(p, byte_offset(c->reg.vertex[0],
    237                              brw_vert_result_to_offset(&c->vue_map,
    238                                                        VERT_RESULT_EDGE)),
    239               brw_imm_f(0));
    240       brw_set_predicate_control(p, BRW_PREDICATE_NONE);
    241 
    242       brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
    243       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9));
    244       brw_MOV(p, byte_offset(c->reg.vertex[2],
    245                              brw_vert_result_to_offset(&c->vue_map,
    246                                                        VERT_RESULT_EDGE)),
    247               brw_imm_f(0));
    248       brw_set_predicate_control(p, BRW_PREDICATE_NONE);
    249    }
    250    brw_ENDIF(p);
    251 }
    252 
    253 
    254 
    255 static void apply_one_offset( struct brw_clip_compile *c,
    256 			  struct brw_indirect vert )
    257 {
    258    struct brw_compile *p = &c->func;
    259    GLuint ndc_offset = brw_vert_result_to_offset(&c->vue_map,
    260                                                  BRW_VERT_RESULT_NDC);
    261    struct brw_reg z = deref_1f(vert, ndc_offset +
    262 			       2 * type_sz(BRW_REGISTER_TYPE_F));
    263 
    264    brw_ADD(p, z, z, vec1(c->reg.offset));
    265 }
    266 
    267 
    268 
    269 /***********************************************************************
    270  * Output clipped polygon as an unfilled primitive:
    271  */
    272 static void emit_lines(struct brw_clip_compile *c,
    273 		       bool do_offset)
    274 {
    275    struct brw_compile *p = &c->func;
    276    struct brw_indirect v0 = brw_indirect(0, 0);
    277    struct brw_indirect v1 = brw_indirect(1, 0);
    278    struct brw_indirect v0ptr = brw_indirect(2, 0);
    279    struct brw_indirect v1ptr = brw_indirect(3, 0);
    280 
    281    /* Need a seperate loop for offset:
    282     */
    283    if (do_offset) {
    284       brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    285       brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    286 
    287       brw_DO(p, BRW_EXECUTE_1);
    288       {
    289 	 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    290 	 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    291 
    292 	 apply_one_offset(c, v0);
    293 
    294 	 brw_set_conditionalmod(p, BRW_CONDITIONAL_G);
    295 	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    296       }
    297       brw_WHILE(p);
    298    }
    299 
    300    /* v1ptr = &inlist[nr_verts]
    301     * *v1ptr = v0
    302     */
    303    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    304    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    305    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
    306    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
    307    brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0));
    308 
    309    brw_DO(p, BRW_EXECUTE_1);
    310    {
    311       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    312       brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2));
    313       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    314 
    315       /* draw edge if edgeflag != 0 */
    316       brw_CMP(p,
    317 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
    318 	      deref_1f(v0, brw_vert_result_to_offset(&c->vue_map,
    319                                                      VERT_RESULT_EDGE)),
    320 	      brw_imm_f(0));
    321       brw_IF(p, BRW_EXECUTE_1);
    322       {
    323 	 brw_clip_emit_vue(c, v0, 1, 0,
    324                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
    325                            | URB_WRITE_PRIM_START);
    326 	 brw_clip_emit_vue(c, v1, 1, 0,
    327                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
    328                            | URB_WRITE_PRIM_END);
    329       }
    330       brw_ENDIF(p);
    331 
    332       brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
    333       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    334    }
    335    brw_WHILE(p);
    336 }
    337 
    338 
    339 
    340 static void emit_points(struct brw_clip_compile *c,
    341 			bool do_offset )
    342 {
    343    struct brw_compile *p = &c->func;
    344 
    345    struct brw_indirect v0 = brw_indirect(0, 0);
    346    struct brw_indirect v0ptr = brw_indirect(2, 0);
    347 
    348    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
    349    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
    350 
    351    brw_DO(p, BRW_EXECUTE_1);
    352    {
    353       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
    354       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
    355 
    356       /* draw if edgeflag != 0
    357        */
    358       brw_CMP(p,
    359 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
    360 	      deref_1f(v0, brw_vert_result_to_offset(&c->vue_map,
    361                                                      VERT_RESULT_EDGE)),
    362 	      brw_imm_f(0));
    363       brw_IF(p, BRW_EXECUTE_1);
    364       {
    365 	 if (do_offset)
    366 	    apply_one_offset(c, v0);
    367 
    368 	 brw_clip_emit_vue(c, v0, 1, 0,
    369                            (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT)
    370                            | URB_WRITE_PRIM_START | URB_WRITE_PRIM_END);
    371       }
    372       brw_ENDIF(p);
    373 
    374       brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
    375       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
    376    }
    377    brw_WHILE(p);
    378 }
    379 
    380 
    381 
    382 
    383 
    384 
    385 
    386 static void emit_primitives( struct brw_clip_compile *c,
    387 			     GLuint mode,
    388 			     bool do_offset )
    389 {
    390    switch (mode) {
    391    case CLIP_FILL:
    392       brw_clip_tri_emit_polygon(c);
    393       break;
    394 
    395    case CLIP_LINE:
    396       emit_lines(c, do_offset);
    397       break;
    398 
    399    case CLIP_POINT:
    400       emit_points(c, do_offset);
    401       break;
    402 
    403    case CLIP_CULL:
    404       assert(0);
    405       break;
    406    }
    407 }
    408 
    409 
    410 
    411 static void emit_unfilled_primitives( struct brw_clip_compile *c )
    412 {
    413    struct brw_compile *p = &c->func;
    414 
    415    /* Direction culling has already been done.
    416     */
    417    if (c->key.fill_ccw != c->key.fill_cw &&
    418        c->key.fill_ccw != CLIP_CULL &&
    419        c->key.fill_cw != CLIP_CULL)
    420    {
    421       brw_CMP(p,
    422 	      vec1(brw_null_reg()),
    423 	      BRW_CONDITIONAL_GE,
    424 	      get_element(c->reg.dir, 2),
    425 	      brw_imm_f(0));
    426 
    427       brw_IF(p, BRW_EXECUTE_1);
    428       {
    429 	 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
    430       }
    431       brw_ELSE(p);
    432       {
    433 	 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
    434       }
    435       brw_ENDIF(p);
    436    }
    437    else if (c->key.fill_cw != CLIP_CULL) {
    438       emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
    439    }
    440    else if (c->key.fill_ccw != CLIP_CULL) {
    441       emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
    442    }
    443 }
    444 
    445 
    446 
    447 
    448 static void check_nr_verts( struct brw_clip_compile *c )
    449 {
    450    struct brw_compile *p = &c->func;
    451 
    452    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3));
    453    brw_IF(p, BRW_EXECUTE_1);
    454    {
    455       brw_clip_kill_thread(c);
    456    }
    457    brw_ENDIF(p);
    458 }
    459 
    460 
    461 void brw_emit_unfilled_clip( struct brw_clip_compile *c )
    462 {
    463    struct brw_compile *p = &c->func;
    464 
    465    c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) ||
    466 			(c->key.fill_ccw != c->key.fill_cw) ||
    467 			c->key.fill_ccw == CLIP_CULL ||
    468 			c->key.fill_cw == CLIP_CULL ||
    469 			c->key.copy_bfc_cw ||
    470 			c->key.copy_bfc_ccw);
    471 
    472    brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
    473    brw_clip_tri_init_vertices(c);
    474    brw_clip_init_ff_sync(c);
    475 
    476    assert(brw_clip_have_vert_result(c, VERT_RESULT_EDGE));
    477 
    478    if (c->key.fill_ccw == CLIP_CULL &&
    479        c->key.fill_cw == CLIP_CULL) {
    480       brw_clip_kill_thread(c);
    481       return;
    482    }
    483 
    484    merge_edgeflags(c);
    485 
    486    /* Need to use the inlist indirection here:
    487     */
    488    if (c->need_direction)
    489       compute_tri_direction(c);
    490 
    491    if (c->key.fill_ccw == CLIP_CULL ||
    492        c->key.fill_cw == CLIP_CULL)
    493       cull_direction(c);
    494 
    495    if (c->key.offset_ccw ||
    496        c->key.offset_cw)
    497       compute_offset(c);
    498 
    499    if (c->key.copy_bfc_ccw ||
    500        c->key.copy_bfc_cw)
    501       copy_bfc(c);
    502 
    503    /* Need to do this whether we clip or not:
    504     */
    505    if (c->key.do_flat_shading)
    506       brw_clip_tri_flat_shade(c);
    507 
    508    brw_clip_init_clipmask(c);
    509    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
    510    brw_IF(p, BRW_EXECUTE_1);
    511    {
    512       brw_clip_init_planes(c);
    513       brw_clip_tri(c);
    514       check_nr_verts(c);
    515    }
    516    brw_ENDIF(p);
    517 
    518    emit_unfilled_primitives(c);
    519    brw_clip_kill_thread(c);
    520 }
    521 
    522 
    523 
    524