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