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 "lp_setup_context.h"
33#include "util/u_math.h"
34#include "util/u_memory.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 "tgsi/tgsi_scan.h"
40
41#define NUM_CHANNELS 4
42
43struct point_info {
44   /* x,y deltas */
45   int dy01, dy12;
46   int dx01, dx12;
47
48   const float (*v0)[4];
49
50   float (*a0)[4];
51   float (*dadx)[4];
52   float (*dady)[4];
53};
54
55
56/**
57 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
58 */
59static void
60constant_coef(struct lp_setup_context *setup,
61              struct point_info *info,
62              unsigned slot,
63              const float value,
64              unsigned i)
65{
66   info->a0[slot][i] = value;
67   info->dadx[slot][i] = 0.0f;
68   info->dady[slot][i] = 0.0f;
69}
70
71
72static void
73point_persp_coeff(struct lp_setup_context *setup,
74                  const struct point_info *info,
75                  unsigned slot,
76                  unsigned i)
77{
78   /*
79    * Fragment shader expects pre-multiplied w for LP_INTERP_PERSPECTIVE. A
80    * better stratergy would be to take the primitive in consideration when
81    * generating the fragment shader key, and therefore avoid the per-fragment
82    * perspective divide.
83    */
84
85   float w0 = info->v0[0][3];
86
87   assert(i < 4);
88
89   info->a0[slot][i] = info->v0[slot][i]*w0;
90   info->dadx[slot][i] = 0.0f;
91   info->dady[slot][i] = 0.0f;
92}
93
94
95/**
96 * Setup automatic texcoord coefficients (for sprite rendering).
97 * \param slot  the vertex attribute slot to setup
98 * \param i  the attribute channel in [0,3]
99 * \param sprite_coord_origin  one of PIPE_SPRITE_COORD_x
100 * \param perspective  does the shader expects pre-multiplied w, i.e.,
101 *    LP_INTERP_PERSPECTIVE is specified in the shader key
102 */
103static void
104texcoord_coef(struct lp_setup_context *setup,
105              const struct point_info *info,
106              unsigned slot,
107              unsigned i,
108              unsigned sprite_coord_origin,
109              boolean perspective)
110{
111   float w0 = info->v0[0][3];
112
113   assert(i < 4);
114
115   if (i == 0) {
116      float dadx = FIXED_ONE / (float)info->dx12;
117      float dady =  0.0f;
118      float x0 = info->v0[0][0] - setup->pixel_offset;
119      float y0 = info->v0[0][1] - setup->pixel_offset;
120
121      info->dadx[slot][0] = dadx;
122      info->dady[slot][0] = dady;
123      info->a0[slot][0] = 0.5 - (dadx * x0 + dady * y0);
124
125      if (perspective) {
126         info->dadx[slot][0] *= w0;
127         info->dady[slot][0] *= w0;
128         info->a0[slot][0] *= w0;
129      }
130   }
131   else if (i == 1) {
132      float dadx = 0.0f;
133      float dady = FIXED_ONE / (float)info->dx12;
134      float x0 = info->v0[0][0] - setup->pixel_offset;
135      float y0 = info->v0[0][1] - setup->pixel_offset;
136
137      if (sprite_coord_origin == PIPE_SPRITE_COORD_LOWER_LEFT) {
138         dady = -dady;
139      }
140
141      info->dadx[slot][1] = dadx;
142      info->dady[slot][1] = dady;
143      info->a0[slot][1] = 0.5 - (dadx * x0 + dady * y0);
144
145      if (perspective) {
146         info->dadx[slot][1] *= w0;
147         info->dady[slot][1] *= w0;
148         info->a0[slot][1] *= w0;
149      }
150   }
151   else if (i == 2) {
152      info->a0[slot][2] = 0.0f;
153      info->dadx[slot][2] = 0.0f;
154      info->dady[slot][2] = 0.0f;
155   }
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.
166 * X and Y are trivial
167 * Z and W are copied from position_coef which should have already been computed.
168 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
169 */
170static void
171setup_point_fragcoord_coef(struct lp_setup_context *setup,
172                           struct point_info *info,
173                           unsigned slot,
174                           unsigned usage_mask)
175{
176   /*X*/
177   if (usage_mask & TGSI_WRITEMASK_X) {
178      info->a0[slot][0] = 0.0;
179      info->dadx[slot][0] = 1.0;
180      info->dady[slot][0] = 0.0;
181   }
182
183   /*Y*/
184   if (usage_mask & TGSI_WRITEMASK_Y) {
185      info->a0[slot][1] = 0.0;
186      info->dadx[slot][1] = 0.0;
187      info->dady[slot][1] = 1.0;
188   }
189
190   /*Z*/
191   if (usage_mask & TGSI_WRITEMASK_Z) {
192      constant_coef(setup, info, slot, info->v0[0][2], 2);
193   }
194
195   /*W*/
196   if (usage_mask & TGSI_WRITEMASK_W) {
197      constant_coef(setup, info, slot, info->v0[0][3], 3);
198   }
199}
200
201
202/**
203 * Compute the point->coef[] array dadx, dady, a0 values.
204 */
205static void
206setup_point_coefficients( struct lp_setup_context *setup,
207                          struct point_info *info)
208{
209   const struct lp_setup_variant_key *key = &setup->setup.variant->key;
210   const struct lp_fragment_shader *shader = setup->fs.current.variant->shader;
211   unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
212   unsigned slot;
213
214   /* setup interpolation for all the remaining attributes:
215    */
216   for (slot = 0; slot < key->num_inputs; slot++) {
217      unsigned vert_attr = key->inputs[slot].src_index;
218      unsigned usage_mask = key->inputs[slot].usage_mask;
219      enum lp_interp interp = key->inputs[slot].interp;
220      boolean perspective = !!(interp == LP_INTERP_PERSPECTIVE);
221      unsigned i;
222
223      if (perspective & usage_mask) {
224         fragcoord_usage_mask |= TGSI_WRITEMASK_W;
225      }
226
227      switch (interp) {
228      case LP_INTERP_POSITION:
229         /*
230          * The generated pixel interpolators will pick up the coeffs from
231          * slot 0, so all need to ensure that the usage mask is covers all
232          * usages.
233          */
234         fragcoord_usage_mask |= usage_mask;
235         break;
236
237      case LP_INTERP_LINEAR:
238         /* Sprite tex coords may use linear interpolation someday */
239         /* fall-through */
240      case LP_INTERP_PERSPECTIVE:
241         /* check if the sprite coord flag is set for this attribute.
242          * If so, set it up so it up so x and y vary from 0 to 1.
243          */
244         if (shader->info.base.input_semantic_name[slot] == TGSI_SEMANTIC_GENERIC) {
245            unsigned semantic_index = shader->info.base.input_semantic_index[slot];
246            /* Note that sprite_coord enable is a bitfield of
247             * PIPE_MAX_SHADER_OUTPUTS bits.
248             */
249            if (semantic_index < PIPE_MAX_SHADER_OUTPUTS &&
250                (setup->sprite_coord_enable & (1 << semantic_index))) {
251               for (i = 0; i < NUM_CHANNELS; i++) {
252                  if (usage_mask & (1 << i)) {
253                     texcoord_coef(setup, info, slot + 1, i,
254                                   setup->sprite_coord_origin,
255                                   perspective);
256                  }
257               }
258               break;
259            }
260         }
261         /* fall-through */
262      case LP_INTERP_CONSTANT:
263         for (i = 0; i < NUM_CHANNELS; i++) {
264            if (usage_mask & (1 << i)) {
265               if (perspective) {
266                  point_persp_coeff(setup, info, slot+1, i);
267               }
268               else {
269                  constant_coef(setup, info, slot+1, info->v0[vert_attr][i], i);
270               }
271            }
272         }
273         break;
274
275      case LP_INTERP_FACING:
276         for (i = 0; i < NUM_CHANNELS; i++)
277            if (usage_mask & (1 << i))
278               constant_coef(setup, info, slot+1, 1.0, i);
279         break;
280
281      default:
282         assert(0);
283         break;
284      }
285   }
286
287   /* The internal position input is in slot zero:
288    */
289   setup_point_fragcoord_coef(setup, info, 0,
290                              fragcoord_usage_mask);
291}
292
293
294static INLINE int
295subpixel_snap(float a)
296{
297   return util_iround(FIXED_ONE * a);
298}
299
300
301static boolean
302try_setup_point( struct lp_setup_context *setup,
303                 const float (*v0)[4] )
304{
305   /* x/y positions in fixed point */
306   const struct lp_setup_variant_key *key = &setup->setup.variant->key;
307   const int sizeAttr = setup->psize;
308   const float size
309      = (setup->point_size_per_vertex && sizeAttr > 0) ? v0[sizeAttr][0]
310      : setup->point_size;
311
312   /* Point size as fixed point integer, remove rounding errors
313    * and gives minimum width for very small points
314    */
315   int fixed_width = MAX2(FIXED_ONE,
316                          (subpixel_snap(size) + FIXED_ONE/2 - 1) & ~(FIXED_ONE-1));
317
318   const int x0 = subpixel_snap(v0[0][0] - setup->pixel_offset) - fixed_width/2;
319   const int y0 = subpixel_snap(v0[0][1] - setup->pixel_offset) - fixed_width/2;
320
321   struct lp_scene *scene = setup->scene;
322   struct lp_rast_triangle *point;
323   unsigned bytes;
324   struct u_rect bbox;
325   unsigned nr_planes = 4;
326   struct point_info info;
327
328
329   /* Bounding rectangle (in pixels) */
330   {
331      /* Yes this is necessary to accurately calculate bounding boxes
332       * with the two fill-conventions we support.  GL (normally) ends
333       * up needing a bottom-left fill convention, which requires
334       * slightly different rounding.
335       */
336      int adj = (setup->pixel_offset != 0) ? 1 : 0;
337
338      bbox.x0 = (x0 + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
339      bbox.x1 = (x0 + fixed_width + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
340      bbox.y0 = (y0 + (FIXED_ONE-1)) >> FIXED_ORDER;
341      bbox.y1 = (y0 + fixed_width + (FIXED_ONE-1)) >> FIXED_ORDER;
342
343      /* Inclusive coordinates:
344       */
345      bbox.x1--;
346      bbox.y1--;
347   }
348
349   if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
350      if (0) debug_printf("offscreen\n");
351      LP_COUNT(nr_culled_tris);
352      return TRUE;
353   }
354
355   u_rect_find_intersection(&setup->draw_region, &bbox);
356
357   point = lp_setup_alloc_triangle(scene,
358                                   key->num_inputs,
359                                   nr_planes,
360                                   &bytes);
361   if (!point)
362      return FALSE;
363
364#ifdef DEBUG
365   point->v[0][0] = v0[0][0];
366   point->v[0][1] = v0[0][1];
367#endif
368
369   info.v0 = v0;
370   info.dx01 = 0;
371   info.dx12 = fixed_width;
372   info.dy01 = fixed_width;
373   info.dy12 = 0;
374   info.a0 = GET_A0(&point->inputs);
375   info.dadx = GET_DADX(&point->inputs);
376   info.dady = GET_DADY(&point->inputs);
377
378   /* Setup parameter interpolants:
379    */
380   setup_point_coefficients(setup, &info);
381
382   point->inputs.frontfacing = TRUE;
383   point->inputs.disable = FALSE;
384   point->inputs.opaque = FALSE;
385
386   {
387      struct lp_rast_plane *plane = GET_PLANES(point);
388
389      plane[0].dcdx = -1;
390      plane[0].dcdy = 0;
391      plane[0].c = 1-bbox.x0;
392      plane[0].eo = 1;
393
394      plane[1].dcdx = 1;
395      plane[1].dcdy = 0;
396      plane[1].c = bbox.x1+1;
397      plane[1].eo = 0;
398
399      plane[2].dcdx = 0;
400      plane[2].dcdy = 1;
401      plane[2].c = 1-bbox.y0;
402      plane[2].eo = 1;
403
404      plane[3].dcdx = 0;
405      plane[3].dcdy = -1;
406      plane[3].c = bbox.y1+1;
407      plane[3].eo = 0;
408   }
409
410   return lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
411}
412
413
414static void
415lp_setup_point(struct lp_setup_context *setup,
416               const float (*v0)[4])
417{
418   if (!try_setup_point( setup, v0 ))
419   {
420      if (!lp_setup_flush_and_restart(setup))
421         return;
422
423      if (!try_setup_point( setup, v0 ))
424         return;
425   }
426}
427
428
429void
430lp_setup_choose_point( struct lp_setup_context *setup )
431{
432   setup->point = lp_setup_point;
433}
434
435
436