97f321966acca085891fbcf568d596a77a5aae23
[mesa.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->ndc_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