xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/llvmpipe/lp_setup_point.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /**************************************************************************
2  *
3  * Copyright 2010, VMware Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * 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, sub license, 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 portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 /*
29  * Binning code for points
30  */
31 
32 #include "util/u_math.h"
33 #include "util/u_memory.h"
34 #include "lp_setup_context.h"
35 #include "lp_perf.h"
36 #include "lp_rast.h"
37 #include "lp_state_fs.h"
38 #include "lp_state_setup.h"
39 #include "lp_context.h"
40 #include "draw/draw_context.h"
41 
42 #define NUM_CHANNELS 4
43 
44 struct point_info {
45    /* x,y deltas */
46    int dy01, dy12;
47    int dx01, dx12;
48 
49    const float (*v0)[4];
50 
51    float (*a0)[4];
52    float (*dadx)[4];
53    float (*dady)[4];
54 
55    bool frontfacing;
56 };
57 
58 
59 /**
60  * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
61  */
62 static void
constant_coef(struct lp_setup_context * setup,struct point_info * info,unsigned slot,const float value,unsigned i)63 constant_coef(struct lp_setup_context *setup,
64               struct point_info *info,
65               unsigned slot,
66               const float value,
67               unsigned i)
68 {
69    info->a0[slot][i] = value;
70    info->dadx[slot][i] = 0.0f;
71    info->dady[slot][i] = 0.0f;
72 }
73 
74 
75 static void
point_persp_coeff(struct lp_setup_context * setup,const struct point_info * info,unsigned slot,unsigned i)76 point_persp_coeff(struct lp_setup_context *setup,
77                   const struct point_info *info,
78                   unsigned slot,
79                   unsigned i)
80 {
81    /*
82     * Fragment shader expects pre-multiplied w for LP_INTERP_PERSPECTIVE. A
83     * better strategy would be to take the primitive in consideration when
84     * generating the fragment shader key, and therefore avoid the per-fragment
85     * perspective divide.
86     */
87 
88    float w0 = info->v0[0][3];
89 
90    assert(i < 4);
91 
92    info->a0[slot][i] = info->v0[slot][i]*w0;
93    info->dadx[slot][i] = 0.0f;
94    info->dady[slot][i] = 0.0f;
95 }
96 
97 
98 /**
99  * Setup automatic texcoord coefficients (for sprite rendering).
100  * \param slot  the vertex attribute slot to setup
101  * \param i  the attribute channel in [0,3]
102  * \param sprite_coord_origin  one of PIPE_SPRITE_COORD_x
103  * \param perspective  does the shader expects pre-multiplied w, i.e.,
104  *    LP_INTERP_PERSPECTIVE is specified in the shader key
105  */
106 static void
texcoord_coef(struct lp_setup_context * setup,const struct point_info * info,unsigned slot,unsigned i,unsigned sprite_coord_origin,bool perspective)107 texcoord_coef(struct lp_setup_context *setup,
108               const struct point_info *info,
109               unsigned slot,
110               unsigned i,
111               unsigned sprite_coord_origin,
112               bool perspective)
113 {
114    float w0 = info->v0[0][3];
115 
116    assert(i < 4);
117 
118    if (i == 0) {
119       float dadx = FIXED_ONE / (float)info->dx12;
120       float dady =  0.0f;
121       float x0 = info->v0[0][0] - setup->pixel_offset;
122       float y0 = info->v0[0][1] - setup->pixel_offset;
123 
124       info->dadx[slot][0] = dadx;
125       info->dady[slot][0] = dady;
126       info->a0[slot][0] = 0.5 - (dadx * x0 + dady * y0);
127 
128       if (perspective) {
129          info->dadx[slot][0] *= w0;
130          info->dady[slot][0] *= w0;
131          info->a0[slot][0] *= w0;
132       }
133    } else if (i == 1) {
134       float dadx = 0.0f;
135       float dady = FIXED_ONE / (float)info->dx12;
136       float x0 = info->v0[0][0] - setup->pixel_offset;
137       float y0 = info->v0[0][1] - setup->pixel_offset;
138 
139       if (sprite_coord_origin == PIPE_SPRITE_COORD_LOWER_LEFT) {
140          dady = -dady;
141       }
142 
143       info->dadx[slot][1] = dadx;
144       info->dady[slot][1] = dady;
145       info->a0[slot][1] = 0.5 - (dadx * x0 + dady * y0);
146 
147       if (perspective) {
148          info->dadx[slot][1] *= w0;
149          info->dady[slot][1] *= w0;
150          info->a0[slot][1] *= w0;
151       }
152    } else if (i == 2) {
153       info->a0[slot][2] = 0.0f;
154       info->dadx[slot][2] = 0.0f;
155       info->dady[slot][2] = 0.0f;
156    } else {
157       info->a0[slot][3] = perspective ? w0 : 1.0f;
158       info->dadx[slot][3] = 0.0f;
159       info->dady[slot][3] = 0.0f;
160    }
161 }
162 
163 
164 /**
165  * Special coefficient setup for gl_FragCoord.  X and Y are trivial.  Z and W
166  * are copied from position_coef which should have already been computed.  We
167  * could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
168  */
169 static void
setup_point_fragcoord_coef(struct lp_setup_context * setup,struct point_info * info,unsigned slot,unsigned usage_mask)170 setup_point_fragcoord_coef(struct lp_setup_context *setup,
171                            struct point_info *info,
172                            unsigned slot,
173                            unsigned usage_mask)
174 {
175    /*X*/
176    if (usage_mask & TGSI_WRITEMASK_X) {
177       info->a0[slot][0] = 0.0;
178       info->dadx[slot][0] = 1.0;
179       info->dady[slot][0] = 0.0;
180    }
181 
182    /*Y*/
183    if (usage_mask & TGSI_WRITEMASK_Y) {
184       info->a0[slot][1] = 0.0;
185       info->dadx[slot][1] = 0.0;
186       info->dady[slot][1] = 1.0;
187    }
188 
189    /*Z*/
190    if (usage_mask & TGSI_WRITEMASK_Z) {
191       constant_coef(setup, info, slot, info->v0[0][2], 2);
192    }
193 
194    /*W*/
195    if (usage_mask & TGSI_WRITEMASK_W) {
196       constant_coef(setup, info, slot, info->v0[0][3], 3);
197    }
198 }
199 
200 
201 /**
202  * Compute the point->coef[] array dadx, dady, a0 values.
203  */
204 static void
setup_point_coefficients(struct lp_setup_context * setup,struct point_info * info)205 setup_point_coefficients(struct lp_setup_context *setup,
206                          struct point_info *info)
207 {
208    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
209    const struct lp_fragment_shader *shader = setup->fs.current.variant->shader;
210    unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
211 
212    /* setup interpolation for all the remaining attributes:
213     */
214    for (unsigned slot = 0; slot < key->num_inputs; slot++) {
215       unsigned vert_attr = key->inputs[slot].src_index;
216       unsigned usage_mask = key->inputs[slot].usage_mask;
217       enum lp_interp interp = key->inputs[slot].interp;
218       bool perspective = !!(interp == LP_INTERP_PERSPECTIVE);
219       unsigned i;
220 
221       if (perspective && usage_mask) {
222          fragcoord_usage_mask |= TGSI_WRITEMASK_W;
223       }
224 
225       switch (interp) {
226       case LP_INTERP_POSITION:
227          /*
228           * The generated pixel interpolators will pick up the coeffs from
229           * slot 0, so all need to ensure that the usage mask is covers all
230           * usages.
231           */
232          fragcoord_usage_mask |= usage_mask;
233          break;
234       case LP_INTERP_LINEAR:
235          /* Sprite tex coords may use linear interpolation someday */
236          FALLTHROUGH;
237       case LP_INTERP_PERSPECTIVE: {
238          /* check if the sprite coord flag is set for this attribute.
239           * If so, set it up so it up so x and y vary from 0 to 1.
240           */
241          bool do_texcoord_coef = false;
242          if (shader->info.base.input_semantic_name[slot] ==
243              TGSI_SEMANTIC_PCOORD) {
244             do_texcoord_coef = true;
245          } else if (shader->info.base.input_semantic_name[slot] ==
246                   TGSI_SEMANTIC_TEXCOORD) {
247             unsigned semantic_index =
248                shader->info.base.input_semantic_index[slot];
249             /* Note that sprite_coord enable is a bitfield of
250              * PIPE_MAX_SHADER_OUTPUTS bits.
251              */
252             if (semantic_index < PIPE_MAX_SHADER_OUTPUTS &&
253                 (setup->sprite_coord_enable & (1u << semantic_index))) {
254                do_texcoord_coef = true;
255             }
256          }
257          if (do_texcoord_coef) {
258             for (i = 0; i < NUM_CHANNELS; i++) {
259                if (usage_mask & (1 << i)) {
260                   texcoord_coef(setup, info, slot + 1, i,
261                                 setup->sprite_coord_origin,
262                                 perspective);
263                }
264             }
265             break;
266          }
267       }
268          FALLTHROUGH;
269       case LP_INTERP_CONSTANT:
270          for (i = 0; i < NUM_CHANNELS; i++) {
271             if (usage_mask & (1 << i)) {
272                if (perspective) {
273                   point_persp_coeff(setup, info, slot+1, i);
274                } else {
275                   constant_coef(setup, info, slot+1, info->v0[vert_attr][i], i);
276                }
277             }
278          }
279          break;
280       case LP_INTERP_FACING:
281          for (i = 0; i < NUM_CHANNELS; i++)
282             if (usage_mask & (1 << i))
283                constant_coef(setup, info, slot+1,
284                              info->frontfacing ? 1.0f : -1.0f, i);
285          break;
286       default:
287          assert(0);
288          break;
289       }
290    }
291 
292    /* The internal position input is in slot zero:
293     */
294    setup_point_fragcoord_coef(setup, info, 0,
295                               fragcoord_usage_mask);
296 }
297 
298 
299 static inline int
subpixel_snap(float a)300 subpixel_snap(float a)
301 {
302    return util_iround(FIXED_ONE * a);
303 }
304 
305 
306 /**
307  * Print point vertex attribs (for debug).
308  */
309 static void
print_point(struct lp_setup_context * setup,const float (* v0)[4],const float size)310 print_point(struct lp_setup_context *setup,
311             const float (*v0)[4],
312             const float size)
313 {
314    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
315 
316    debug_printf("llvmpipe point, width %f\n", size);
317    for (unsigned i = 0; i < 1 + key->num_inputs; i++) {
318       debug_printf("  v0[%d]:  %f %f %f %f\n", i,
319                    v0[i][0], v0[i][1], v0[i][2], v0[i][3]);
320    }
321 }
322 
323 
324 static bool
try_setup_point(struct lp_setup_context * setup,const float (* v0)[4])325 try_setup_point(struct lp_setup_context *setup,
326                 const float (*v0)[4])
327 {
328    struct llvmpipe_context *lp_context = (struct llvmpipe_context *)setup->pipe;
329    /* x/y positions in fixed point */
330    const struct lp_setup_variant_key *key = &setup->setup.variant->key;
331    const int sizeAttr = setup->psize_slot;
332    float size
333       = (setup->point_size_per_vertex && sizeAttr > 0) ? v0[sizeAttr][0]
334       : setup->point_size;
335 
336    if (size > LP_MAX_POINT_WIDTH)
337       size = LP_MAX_POINT_WIDTH;
338 
339    /* Yes this is necessary to accurately calculate bounding boxes
340     * with the two fill-conventions we support.  GL (normally) ends
341     * up needing a bottom-left fill convention, which requires
342     * slightly different rounding.
343     */
344    const int adj = (setup->bottom_edge_rule != 0) ? 1 : 0;
345    const float pixel_offset = setup->multisample ? 0.0 : setup->pixel_offset;
346    struct lp_scene *scene = setup->scene;
347    int x[2], y[2];
348 
349    unsigned viewport_index = 0;
350    if (setup->viewport_index_slot > 0) {
351       unsigned *udata = (unsigned*)v0[setup->viewport_index_slot];
352       viewport_index = lp_clamp_viewport_idx(*udata);
353    }
354 
355    unsigned layer = 0;
356    if (setup->layer_slot > 0) {
357       layer = *(unsigned*)v0[setup->layer_slot];
358       layer = MIN2(layer, scene->fb_max_layer);
359    }
360 
361    int fixed_width;
362 
363    if (0)
364       print_point(setup, v0, size);
365 
366    /* Bounding rectangle (in pixels) */
367    struct u_rect bbox;
368    if (!setup->legacy_points) {
369       /*
370        * Rasterize points as quads.
371        */
372       int x0, y0;
373       /* Point size as fixed point integer, remove rounding errors
374        * and gives minimum width for very small points.
375        */
376       fixed_width = MAX2(FIXED_ONE, subpixel_snap(size));
377 
378       x0 = subpixel_snap(v0[0][0] - pixel_offset) - fixed_width/2;
379       y0 = subpixel_snap(v0[0][1] - pixel_offset) - fixed_width/2;
380 
381       x[0] = x0;
382       x[1] = x0 + fixed_width;
383       y[0] = y0;
384       y[1] = y0 + fixed_width;
385       bbox.x0 = x[0] >> FIXED_ORDER;
386       bbox.x1 = (x[1] + (FIXED_ONE-1)) >> FIXED_ORDER;
387       bbox.y0 = (y[0] + adj) >> FIXED_ORDER;
388       bbox.y1 = (y[1] + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
389 
390       /* Inclusive coordinates:
391        */
392       bbox.x1--;
393       bbox.y1--;
394    } else {
395       /*
396        * OpenGL legacy rasterization rules for non-sprite points.
397        *
398        * Per OpenGL 2.1 spec, section 3.3.1, "Basic Point Rasterization".
399        *
400        * This type of point rasterization is only available in pre 3.0 contexts
401        * (or compatibility contexts which we don't support) anyway.
402        */
403 
404       const int x0 = subpixel_snap(v0[0][0]);
405       const int y0 = subpixel_snap(v0[0][1]) - adj;
406 
407       /* Point size as fixed point integer. For GL legacy points
408        * the point size is always a whole integer.
409        */
410       fixed_width = MAX2(FIXED_ONE,
411                          (subpixel_snap(size) + FIXED_ONE/2 - 1) & ~(FIXED_ONE-1));
412       int int_width = fixed_width >> FIXED_ORDER;
413 
414       assert(setup->pixel_offset != 0);
415 
416       if (int_width == 1) {
417          bbox.x0 = x0 >> FIXED_ORDER;
418          bbox.y0 = y0 >> FIXED_ORDER;
419          bbox.x1 = bbox.x0;
420          bbox.y1 = bbox.y0;
421       } else {
422          if (int_width & 1) {
423             /* Odd width */
424             bbox.x0 = (x0 >> FIXED_ORDER) - (int_width - 1)/2;
425             bbox.y0 = (y0 >> FIXED_ORDER) - (int_width - 1)/2;
426          } else {
427             /* Even width */
428             bbox.x0 = ((x0 + FIXED_ONE/2) >> FIXED_ORDER) - int_width/2;
429             bbox.y0 = ((y0 + FIXED_ONE/2) >> FIXED_ORDER) - int_width/2;
430          }
431 
432          bbox.x1 = bbox.x0 + int_width - 1;
433          bbox.y1 = bbox.y0 + int_width - 1;
434       }
435 
436       x[0] = (bbox.x0 - 1) << 8;
437       x[1] = (bbox.x1 + 1) << 8;
438       y[0] = (bbox.y0 - 1) << 8;
439       y[1] = (bbox.y1 + 1) << 8;
440    }
441 
442    if (0) {
443       debug_printf("  bbox: (%i, %i) - (%i, %i)\n",
444                    bbox.x0, bbox.y0,
445                    bbox.x1, bbox.y1);
446    }
447 
448    if (lp_context->active_statistics_queries) {
449       lp_context->pipeline_statistics.c_primitives++;
450    }
451 
452    if (lp_setup_zero_sample_mask(setup)) {
453       if (0) debug_printf("zero sample mask\n");
454       LP_COUNT(nr_culled_tris);
455       return true;
456    }
457 
458    if (!u_rect_test_intersection(&setup->draw_regions[viewport_index], &bbox)) {
459       if (0) debug_printf("no intersection\n");
460       LP_COUNT(nr_culled_tris);
461       return true;
462    }
463 
464    u_rect_find_intersection(&setup->draw_regions[viewport_index], &bbox);
465 
466    /* We can't use rectangle reasterizer for non-legacy points for now. */
467    if (!setup->legacy_points || setup->multisample) {
468       struct lp_rast_triangle *point;
469       struct lp_rast_plane *plane;
470       unsigned nr_planes = 4;
471 
472       point = lp_setup_alloc_triangle(scene,
473                                       key->num_inputs,
474                                       nr_planes);
475      if (!point)
476         return false;
477 
478 #if MESA_DEBUG
479       point->v[0][0] = v0[0][0];
480       point->v[0][1] = v0[0][1];
481 #endif
482 
483       LP_COUNT(nr_tris);
484 
485       if (draw_will_inject_frontface(lp_context->draw) &&
486           setup->face_slot > 0) {
487          point->inputs.frontfacing = v0[setup->face_slot][0];
488       } else {
489          point->inputs.frontfacing = true;
490       }
491 
492       struct point_info info;
493       info.v0 = v0;
494       info.dx01 = 0;
495       info.dx12 = fixed_width;
496       info.dy01 = fixed_width;
497       info.dy12 = 0;
498       info.a0 = GET_A0(&point->inputs);
499       info.dadx = GET_DADX(&point->inputs);
500       info.dady = GET_DADY(&point->inputs);
501       info.frontfacing = point->inputs.frontfacing;
502 
503       /* Setup parameter interpolants:
504        */
505       setup_point_coefficients(setup, &info);
506 
507       point->inputs.disable = false;
508       point->inputs.is_blit = false;
509       point->inputs.layer = layer;
510       point->inputs.viewport_index = viewport_index;
511       point->inputs.view_index = setup->view_index;
512 
513       plane = GET_PLANES(point);
514 
515       plane[0].dcdx = ~0U << 8;
516       plane[0].dcdy = 0;
517       plane[0].c = -MAX2(x[0], bbox.x0 << 8);
518       plane[0].eo = 1 << 8;
519 
520       plane[1].dcdx = 1 << 8;
521       plane[1].dcdy = 0;
522       plane[1].c = MIN2(x[1], (bbox.x1 + 1) << 8);
523       plane[1].eo = 0;
524 
525       plane[2].dcdx = 0;
526       plane[2].dcdy = 1 << 8;
527       plane[2].c = -MAX2(y[0], (bbox.y0 << 8) - adj);
528       plane[2].eo = 1 << 8;
529 
530       plane[3].dcdx = 0;
531       plane[3].dcdy = ~0U << 8;
532       plane[3].c = MIN2(y[1], (bbox.y1 + 1) << 8);
533       plane[3].eo = 0;
534 
535       if (!setup->legacy_points) {
536          /* adjust for fill-rule*/
537          plane[0].c++; /* left */
538          if (setup->bottom_edge_rule == 0)
539             plane[2].c++; /* top-left */
540          else
541             plane[3].c++; /* bottom-left */
542       }
543 
544       int max_szorig = ((bbox.x1 - (bbox.x0 & ~3)) |
545                         (bbox.y1 - (bbox.y0 & ~3)));
546       bool use_32bits = max_szorig <= MAX_FIXED_LENGTH32;
547 
548       return lp_setup_bin_triangle(setup, point, use_32bits,
549                                    setup->fs.current.variant->opaque,
550                                    &bbox, nr_planes, viewport_index);
551 
552    } else {
553       struct lp_rast_rectangle *point =
554          lp_setup_alloc_rectangle(scene, key->num_inputs);
555       if (!point)
556          return false;
557 #if MESA_DEBUG
558       point->v[0][0] = v0[0][0];
559       point->v[0][1] = v0[0][1];
560 #endif
561 
562       point->box.x0 = bbox.x0;
563       point->box.x1 = bbox.x1;
564       point->box.y0 = bbox.y0;
565       point->box.y1 = bbox.y1;
566 
567       LP_COUNT(nr_tris);
568 
569       if (draw_will_inject_frontface(lp_context->draw) &&
570           setup->face_slot > 0) {
571          point->inputs.frontfacing = v0[setup->face_slot][0];
572       } else {
573          point->inputs.frontfacing = true;
574       }
575 
576       struct point_info info;
577       info.v0 = v0;
578       info.dx01 = 0;
579       info.dx12 = fixed_width;
580       info.dy01 = fixed_width;
581       info.dy12 = 0;
582       info.a0 = GET_A0(&point->inputs);
583       info.dadx = GET_DADX(&point->inputs);
584       info.dady = GET_DADY(&point->inputs);
585       info.frontfacing = point->inputs.frontfacing;
586 
587       /* Setup parameter interpolants:
588        */
589       setup_point_coefficients(setup, &info);
590 
591       point->inputs.disable = false;
592       point->inputs.is_blit = false;
593       point->inputs.layer = layer;
594       point->inputs.viewport_index = viewport_index;
595       point->inputs.view_index = setup->view_index;
596 
597       return lp_setup_bin_rectangle(setup, point,
598                                     setup->fs.current.variant->opaque);
599    }
600 }
601 
602 
603 static void
lp_setup_point_discard(struct lp_setup_context * setup,const float (* v0)[4])604 lp_setup_point_discard(struct lp_setup_context *setup,
605                        const float (*v0)[4])
606 {
607 }
608 
609 
610 static void
lp_setup_point(struct lp_setup_context * setup,const float (* v0)[4])611 lp_setup_point(struct lp_setup_context *setup,
612                const float (*v0)[4])
613 {
614    if (!try_setup_point(setup, v0)) {
615       if (!lp_setup_flush_and_restart(setup))
616          return;
617 
618       if (!try_setup_point(setup, v0))
619          return;
620    }
621 }
622 
623 
624 void
lp_setup_choose_point(struct lp_setup_context * setup)625 lp_setup_choose_point(struct lp_setup_context *setup)
626 {
627    if (setup->rasterizer_discard) {
628       setup->point = lp_setup_point_discard;
629    } else {
630       setup->point = lp_setup_point;
631    }
632 }
633 
634 
635