1 /**************************************************************************
3 * Copyright 2010, VMware Inc.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 * Binning code for points
32 #include "lp_setup_context.h"
33 #include "util/u_math.h"
34 #include "util/u_memory.h"
37 #include "lp_state_fs.h"
38 #include "tgsi/tgsi_scan.h"
40 #define NUM_CHANNELS 4
56 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
59 constant_coef(struct lp_setup_context
*setup
,
60 struct point_info
*info
,
65 info
->a0
[slot
][i
] = value
;
66 info
->dadx
[slot
][i
] = 0.0f
;
67 info
->dady
[slot
][i
] = 0.0f
;
72 point_persp_coeff(struct lp_setup_context
*setup
,
73 const struct point_info
*info
,
78 * Fragment shader expects pre-multiplied w for LP_INTERP_PERSPECTIVE. A
79 * better stratergy would be to take the primitive in consideration when
80 * generating the fragment shader key, and therefore avoid the per-fragment
84 float w0
= info
->v0
[0][3];
88 info
->a0
[slot
][i
] = info
->v0
[slot
][i
]*w0
;
89 info
->dadx
[slot
][i
] = 0.0f
;
90 info
->dady
[slot
][i
] = 0.0f
;
95 * Setup automatic texcoord coefficients (for sprite rendering).
96 * \param slot the vertex attribute slot to setup
97 * \param i the attribute channel in [0,3]
98 * \param sprite_coord_origin one of PIPE_SPRITE_COORD_x
99 * \param perspective does the shader expects pre-multiplied w, i.e.,
100 * LP_INTERP_PERSPECTIVE is specified in the shader key
103 texcoord_coef(struct lp_setup_context
*setup
,
104 const struct point_info
*info
,
107 unsigned sprite_coord_origin
,
110 float w0
= info
->v0
[0][3];
115 float dadx
= FIXED_ONE
/ (float)info
->dx12
;
117 float x0
= info
->v0
[0][0] - setup
->pixel_offset
;
118 float y0
= info
->v0
[0][1] - setup
->pixel_offset
;
120 info
->dadx
[slot
][0] = dadx
;
121 info
->dady
[slot
][0] = dady
;
122 info
->a0
[slot
][0] = 0.5 - (dadx
* x0
+ dady
* y0
);
125 info
->dadx
[slot
][0] *= w0
;
126 info
->dady
[slot
][0] *= w0
;
127 info
->a0
[slot
][0] *= w0
;
132 float dady
= FIXED_ONE
/ (float)info
->dx12
;
133 float x0
= info
->v0
[0][0] - setup
->pixel_offset
;
134 float y0
= info
->v0
[0][1] - setup
->pixel_offset
;
136 if (sprite_coord_origin
== PIPE_SPRITE_COORD_LOWER_LEFT
) {
140 info
->dadx
[slot
][1] = dadx
;
141 info
->dady
[slot
][1] = dady
;
142 info
->a0
[slot
][1] = 0.5 - (dadx
* x0
+ dady
* y0
);
145 info
->dadx
[slot
][1] *= w0
;
146 info
->dady
[slot
][1] *= w0
;
147 info
->a0
[slot
][1] *= w0
;
151 info
->a0
[slot
][2] = 0.0f
;
152 info
->dadx
[slot
][2] = 0.0f
;
153 info
->dady
[slot
][2] = 0.0f
;
156 info
->a0
[slot
][3] = perspective
? w0
: 1.0f
;
157 info
->dadx
[slot
][3] = 0.0f
;
158 info
->dady
[slot
][3] = 0.0f
;
164 * Special coefficient setup for gl_FragCoord.
165 * X and Y are trivial
166 * Z and W are copied from position_coef which should have already been computed.
167 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
170 setup_point_fragcoord_coef(struct lp_setup_context
*setup
,
171 struct point_info
*info
,
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;
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;
190 if (usage_mask
& TGSI_WRITEMASK_Z
) {
191 constant_coef(setup
, info
, slot
, info
->v0
[0][2], 2);
195 if (usage_mask
& TGSI_WRITEMASK_W
) {
196 constant_coef(setup
, info
, slot
, info
->v0
[0][3], 3);
202 * Compute the point->coef[] array dadx, dady, a0 values.
205 setup_point_coefficients( struct lp_setup_context
*setup
,
206 struct point_info
*info
)
208 const struct lp_fragment_shader
*shader
= setup
->fs
.current
.variant
->shader
;
209 unsigned fragcoord_usage_mask
= TGSI_WRITEMASK_XYZ
;
212 /* setup interpolation for all the remaining attributes:
214 for (slot
= 0; slot
< setup
->fs
.nr_inputs
; slot
++) {
215 enum lp_interp interp
= setup
->fs
.input
[slot
].interp
;
216 boolean perspective
= !!(interp
== LP_INTERP_PERSPECTIVE
);
217 unsigned vert_attr
= setup
->fs
.input
[slot
].src_index
;
218 unsigned usage_mask
= setup
->fs
.input
[slot
].usage_mask
;
221 if (perspective
& usage_mask
) {
222 fragcoord_usage_mask
|= TGSI_WRITEMASK_W
;
226 case LP_INTERP_POSITION
:
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
232 fragcoord_usage_mask
|= usage_mask
;
235 case LP_INTERP_LINEAR
:
236 /* Sprite tex coords may use linear interpolation someday */
238 case LP_INTERP_PERSPECTIVE
:
239 /* check if the sprite coord flag is set for this attribute.
240 * If so, set it up so it up so x and y vary from 0 to 1.
242 if (shader
->info
.base
.input_semantic_name
[slot
] == TGSI_SEMANTIC_GENERIC
) {
243 unsigned semantic_index
= shader
->info
.base
.input_semantic_index
[slot
];
244 /* Note that sprite_coord enable is a bitfield of
245 * PIPE_MAX_SHADER_OUTPUTS bits.
247 if (semantic_index
< PIPE_MAX_SHADER_OUTPUTS
&&
248 (setup
->sprite_coord_enable
& (1 << semantic_index
))) {
249 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
250 if (usage_mask
& (1 << i
)) {
251 texcoord_coef(setup
, info
, slot
+ 1, i
,
252 setup
->sprite_coord_origin
,
260 case LP_INTERP_CONSTANT
:
261 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
262 if (usage_mask
& (1 << i
)) {
264 point_persp_coeff(setup
, info
, slot
+1, i
);
267 constant_coef(setup
, info
, slot
+1, info
->v0
[vert_attr
][i
], i
);
273 case LP_INTERP_FACING
:
274 for (i
= 0; i
< NUM_CHANNELS
; i
++)
275 if (usage_mask
& (1 << i
))
276 constant_coef(setup
, info
, slot
+1, 1.0, i
);
285 /* The internal position input is in slot zero:
287 setup_point_fragcoord_coef(setup
, info
, 0,
288 fragcoord_usage_mask
);
293 subpixel_snap(float a
)
295 return util_iround(FIXED_ONE
* a
);
300 try_setup_point( struct lp_setup_context
*setup
,
301 const float (*v0
)[4] )
303 /* x/y positions in fixed point */
304 const int sizeAttr
= setup
->psize
;
306 = (setup
->point_size_per_vertex
&& sizeAttr
> 0) ? v0
[sizeAttr
][0]
309 /* Point size as fixed point integer, remove rounding errors
310 * and gives minimum width for very small points
312 int fixed_width
= MAX2(FIXED_ONE
,
313 (subpixel_snap(size
) + FIXED_ONE
/2 - 1) & ~(FIXED_ONE
-1));
315 const int x0
= subpixel_snap(v0
[0][0] - setup
->pixel_offset
) - fixed_width
/2;
316 const int y0
= subpixel_snap(v0
[0][1] - setup
->pixel_offset
) - fixed_width
/2;
318 struct lp_scene
*scene
= setup
->scene
;
319 struct lp_rast_triangle
*point
;
322 unsigned nr_planes
= 4;
323 struct point_info info
;
326 /* Bounding rectangle (in pixels) */
328 /* Yes this is necessary to accurately calculate bounding boxes
329 * with the two fill-conventions we support. GL (normally) ends
330 * up needing a bottom-left fill convention, which requires
331 * slightly different rounding.
333 int adj
= (setup
->pixel_offset
!= 0) ? 1 : 0;
335 bbox
.x0
= (x0
+ (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
336 bbox
.x1
= (x0
+ fixed_width
+ (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
337 bbox
.y0
= (y0
+ (FIXED_ONE
-1)) >> FIXED_ORDER
;
338 bbox
.y1
= (y0
+ fixed_width
+ (FIXED_ONE
-1)) >> FIXED_ORDER
;
340 /* Inclusive coordinates:
346 if (!u_rect_test_intersection(&setup
->draw_region
, &bbox
)) {
347 if (0) debug_printf("offscreen\n");
348 LP_COUNT(nr_culled_tris
);
352 u_rect_find_intersection(&setup
->draw_region
, &bbox
);
354 point
= lp_setup_alloc_triangle(scene
,
362 point
->v
[0][0] = v0
[0][0];
363 point
->v
[0][1] = v0
[0][1];
368 info
.dx12
= fixed_width
;
369 info
.dy01
= fixed_width
;
371 info
.a0
= GET_A0(&point
->inputs
);
372 info
.dadx
= GET_DADX(&point
->inputs
);
373 info
.dady
= GET_DADY(&point
->inputs
);
375 /* Setup parameter interpolants:
377 setup_point_coefficients(setup
, &info
);
379 point
->inputs
.frontfacing
= TRUE
;
380 point
->inputs
.disable
= FALSE
;
381 point
->inputs
.opaque
= FALSE
;
384 struct lp_rast_plane
*plane
= GET_PLANES(point
);
388 plane
[0].c
= 1-bbox
.x0
;
393 plane
[1].c
= bbox
.x1
+1;
398 plane
[2].c
= 1-bbox
.y0
;
403 plane
[3].c
= bbox
.y1
+1;
407 return lp_setup_bin_triangle(setup
, point
, &bbox
, nr_planes
);
412 lp_setup_point(struct lp_setup_context
*setup
,
413 const float (*v0
)[4])
415 if (!try_setup_point( setup
, v0
))
417 if (!lp_setup_flush_and_restart(setup
))
420 if (!try_setup_point( setup
, v0
))
427 lp_setup_choose_point( struct lp_setup_context
*setup
)
429 setup
->point
= lp_setup_point
;