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