xref: /aosp_15_r20/external/mesa3d/src/intel/compiler/elk/elk_clip_line.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 
elk_clip_line_alloc_regs(struct elk_clip_compile * c)35 static void elk_clip_line_alloc_regs( struct elk_clip_compile *c )
36 {
37    const struct intel_device_info *devinfo = c->func.devinfo;
38    GLuint i = 0,j;
39 
40    /* Register usage is static, precompute here:
41     */
42    c->reg.R0 = retype(elk_vec8_grf(i, 0), ELK_REGISTER_TYPE_UD); i++;
43 
44    if (c->key.nr_userclip) {
45       c->reg.fixed_planes = elk_vec4_grf(i, 0);
46       i += (6 + c->key.nr_userclip + 1) / 2;
47 
48       c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
49    }
50    else
51       c->prog_data.curb_read_length = 0;
52 
53 
54    /* Payload vertices plus space for more generated vertices:
55     */
56    for (j = 0; j < 4; j++) {
57       c->reg.vertex[j] = elk_vec4_grf(i, 0);
58       i += c->nr_regs;
59    }
60 
61    c->reg.t           = elk_vec1_grf(i, 0);
62    c->reg.t0          = elk_vec1_grf(i, 1);
63    c->reg.t1          = elk_vec1_grf(i, 2);
64    c->reg.planemask   = retype(elk_vec1_grf(i, 3), ELK_REGISTER_TYPE_UD);
65    c->reg.plane_equation = elk_vec4_grf(i, 4);
66    i++;
67 
68    c->reg.dp0         = elk_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
69    c->reg.dp1         = elk_vec1_grf(i, 4);
70    i++;
71 
72    if (!c->key.nr_userclip) {
73       c->reg.fixed_planes = elk_vec8_grf(i, 0);
74       i++;
75    }
76 
77    c->reg.vertex_src_mask = retype(elk_vec1_grf(i, 0), ELK_REGISTER_TYPE_UD);
78    c->reg.clipdistance_offset = retype(elk_vec1_grf(i, 1), ELK_REGISTER_TYPE_W);
79    i++;
80 
81    if (devinfo->ver == 5) {
82       c->reg.ff_sync = retype(elk_vec1_grf(i, 0), ELK_REGISTER_TYPE_UD);
83       i++;
84    }
85 
86    c->first_tmp = i;
87    c->last_tmp = i;
88 
89    c->prog_data.urb_read_length = c->nr_regs; /* ? */
90    c->prog_data.total_grf = i;
91 }
92 
93 
94 /* Line clipping, more or less following the following algorithm:
95  *
96  *  for (p=0;p<MAX_PLANES;p++) {
97  *     if (clipmask & (1 << p)) {
98  *        GLfloat dp0 = DOTPROD( vtx0, plane[p] );
99  *        GLfloat dp1 = DOTPROD( vtx1, plane[p] );
100  *
101  *        if (dp1 < 0.0f) {
102  *           GLfloat t = dp1 / (dp1 - dp0);
103  *           if (t > t1) t1 = t;
104  *        } else {
105  *           GLfloat t = dp0 / (dp0 - dp1);
106  *           if (t > t0) t0 = t;
107  *        }
108  *
109  *        if (t0 + t1 >= 1.0)
110  *           return;
111  *     }
112  *  }
113  *
114  *  interp( ctx, newvtx0, vtx0, vtx1, t0 );
115  *  interp( ctx, newvtx1, vtx1, vtx0, t1 );
116  *
117  */
clip_and_emit_line(struct elk_clip_compile * c)118 static void clip_and_emit_line( struct elk_clip_compile *c )
119 {
120    struct elk_codegen *p = &c->func;
121    struct elk_indirect vtx0     = elk_indirect(0, 0);
122    struct elk_indirect vtx1      = elk_indirect(1, 0);
123    struct elk_indirect newvtx0   = elk_indirect(2, 0);
124    struct elk_indirect newvtx1   = elk_indirect(3, 0);
125    struct elk_indirect plane_ptr = elk_indirect(4, 0);
126    struct elk_reg v1_null_ud = retype(vec1(elk_null_reg()), ELK_REGISTER_TYPE_UD);
127    GLuint hpos_offset = elk_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
128    GLint clipdist0_offset = c->key.nr_userclip
129       ? elk_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
130       : 0;
131 
132    elk_MOV(p, get_addr_reg(vtx0),      elk_address(c->reg.vertex[0]));
133    elk_MOV(p, get_addr_reg(vtx1),      elk_address(c->reg.vertex[1]));
134    elk_MOV(p, get_addr_reg(newvtx0),   elk_address(c->reg.vertex[2]));
135    elk_MOV(p, get_addr_reg(newvtx1),   elk_address(c->reg.vertex[3]));
136    elk_MOV(p, get_addr_reg(plane_ptr), elk_clip_plane0_address(c));
137 
138    /* Note: init t0, t1 together:
139     */
140    elk_MOV(p, vec2(c->reg.t0), elk_imm_f(0));
141 
142    elk_clip_init_planes(c);
143    elk_clip_init_clipmask(c);
144 
145    /* -ve rhw workaround */
146    if (p->devinfo->has_negative_rhw_bug) {
147       elk_AND(p, elk_null_reg(), get_element_ud(c->reg.R0, 2),
148               elk_imm_ud(1<<20));
149       elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
150       elk_OR(p, c->reg.planemask, c->reg.planemask, elk_imm_ud(0x3f));
151       elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
152    }
153 
154    /* Set the initial vertex source mask: The first 6 planes are the bounds
155     * of the view volume; the next 8 planes are the user clipping planes.
156     */
157    elk_MOV(p, c->reg.vertex_src_mask, elk_imm_ud(0x3fc0));
158 
159    /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
160     * We'll increment 6 times before we start hitting actual user clipping. */
161    elk_MOV(p, c->reg.clipdistance_offset, elk_imm_d(clipdist0_offset - 6*sizeof(float)));
162 
163    elk_DO(p, ELK_EXECUTE_1);
164    {
165       /* if (planemask & 1)
166        */
167       elk_AND(p, v1_null_ud, c->reg.planemask, elk_imm_ud(1));
168       elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
169 
170       elk_IF(p, ELK_EXECUTE_1);
171       {
172          elk_AND(p, v1_null_ud, c->reg.vertex_src_mask, elk_imm_ud(1));
173          elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
174          elk_IF(p, ELK_EXECUTE_1);
175          {
176             /* user clip distance: just fetch the correct float from each vertex */
177             struct elk_indirect temp_ptr = elk_indirect(7, 0);
178             elk_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx0), c->reg.clipdistance_offset);
179             elk_MOV(p, c->reg.dp0, deref_1f(temp_ptr, 0));
180             elk_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx1), c->reg.clipdistance_offset);
181             elk_MOV(p, c->reg.dp1, deref_1f(temp_ptr, 0));
182          }
183          elk_ELSE(p);
184          {
185             /* fixed plane: fetch the hpos, dp4 against the plane. */
186             if (c->key.nr_userclip)
187                elk_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
188             else
189                elk_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
190 
191             elk_DP4(p, vec4(c->reg.dp0), deref_4f(vtx0, hpos_offset), c->reg.plane_equation);
192             elk_DP4(p, vec4(c->reg.dp1), deref_4f(vtx1, hpos_offset), c->reg.plane_equation);
193          }
194          elk_ENDIF(p);
195 
196          elk_CMP(p, elk_null_reg(), ELK_CONDITIONAL_L, vec1(c->reg.dp1), elk_imm_f(0.0f));
197 
198          elk_IF(p, ELK_EXECUTE_1);
199          {
200              /*
201               * Both can be negative on GM965/G965 due to RHW workaround
202               * if so, this object should be rejected.
203               */
204              if (p->devinfo->has_negative_rhw_bug) {
205                  elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_LE, c->reg.dp0, elk_imm_f(0.0));
206                  elk_IF(p, ELK_EXECUTE_1);
207                  {
208                      elk_clip_kill_thread(c);
209                  }
210                  elk_ENDIF(p);
211              }
212 
213              elk_ADD(p, c->reg.t, c->reg.dp1, negate(c->reg.dp0));
214              elk_math_invert(p, c->reg.t, c->reg.t);
215              elk_MUL(p, c->reg.t, c->reg.t, c->reg.dp1);
216 
217              elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_G, c->reg.t, c->reg.t1 );
218              elk_MOV(p, c->reg.t1, c->reg.t);
219              elk_inst_set_pred_control(p->devinfo, elk_last_inst,
220                                        ELK_PREDICATE_NORMAL);
221 	 }
222 	 elk_ELSE(p);
223 	 {
224              /* Coming back in.  We know that both cannot be negative
225               * because the line would have been culled in that case.
226               */
227 
228              /* If both are positive, do nothing */
229              /* Only on GM965/G965 */
230              if (p->devinfo->has_negative_rhw_bug) {
231                  elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_L, c->reg.dp0, elk_imm_f(0.0));
232                  elk_IF(p, ELK_EXECUTE_1);
233              }
234 
235              {
236                  elk_ADD(p, c->reg.t, c->reg.dp0, negate(c->reg.dp1));
237                  elk_math_invert(p, c->reg.t, c->reg.t);
238                  elk_MUL(p, c->reg.t, c->reg.t, c->reg.dp0);
239 
240                  elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_G, c->reg.t, c->reg.t0 );
241                  elk_MOV(p, c->reg.t0, c->reg.t);
242                  elk_inst_set_pred_control(p->devinfo, elk_last_inst,
243                                            ELK_PREDICATE_NORMAL);
244              }
245 
246              if (p->devinfo->has_negative_rhw_bug) {
247                  elk_ENDIF(p);
248              }
249          }
250 	 elk_ENDIF(p);
251       }
252       elk_ENDIF(p);
253 
254       /* plane_ptr++;
255        */
256       elk_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), elk_clip_plane_stride(c));
257 
258       /* while (planemask>>=1) != 0
259        */
260       elk_SHR(p, c->reg.planemask, c->reg.planemask, elk_imm_ud(1));
261       elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
262       elk_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, elk_imm_ud(1));
263       elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
264       elk_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, elk_imm_w(sizeof(float)));
265       elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
266    }
267    elk_WHILE(p);
268    elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
269 
270    elk_ADD(p, c->reg.t, c->reg.t0, c->reg.t1);
271    elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_L, c->reg.t, elk_imm_f(1.0));
272    elk_IF(p, ELK_EXECUTE_1);
273    {
274       elk_clip_interp_vertex(c, newvtx0, vtx0, vtx1, c->reg.t0, false);
275       elk_clip_interp_vertex(c, newvtx1, vtx1, vtx0, c->reg.t1, false);
276 
277       elk_clip_emit_vue(c, newvtx0, ELK_URB_WRITE_ALLOCATE_COMPLETE,
278                         (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
279                         | URB_WRITE_PRIM_START);
280       elk_clip_emit_vue(c, newvtx1, ELK_URB_WRITE_EOT_COMPLETE,
281                         (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
282                         | URB_WRITE_PRIM_END);
283    }
284    elk_ENDIF(p);
285    elk_clip_kill_thread(c);
286 }
287 
288 
289 
elk_emit_line_clip(struct elk_clip_compile * c)290 void elk_emit_line_clip( struct elk_clip_compile *c )
291 {
292    elk_clip_line_alloc_regs(c);
293    elk_clip_init_ff_sync(c);
294 
295    if (c->key.contains_flat_varying) {
296       if (c->key.pv_first)
297          elk_clip_copy_flatshaded_attributes(c, 1, 0);
298       else
299          elk_clip_copy_flatshaded_attributes(c, 0, 1);
300    }
301 
302    clip_and_emit_line(c);
303 }
304