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:
48BZZZT!
49 */
50static 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
98static 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
126static 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*/
194static 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
217static 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
255static 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 */
272static 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
340static 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
386static 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
411static 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
448static 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
461void 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