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