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