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 "util/u_math.h"
33 #include "util/u_memory.h"
34 #include "lp_setup_context.h"
37 #include "lp_state_fs.h"
38 #include "lp_state_setup.h"
39 #include "lp_context.h"
40 #include "tgsi/tgsi_scan.h"
41 #include "draw/draw_context.h"
43 #define NUM_CHANNELS 4
61 * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
64 constant_coef(struct lp_setup_context
*setup
,
65 struct point_info
*info
,
70 info
->a0
[slot
][i
] = value
;
71 info
->dadx
[slot
][i
] = 0.0f
;
72 info
->dady
[slot
][i
] = 0.0f
;
77 point_persp_coeff(struct lp_setup_context
*setup
,
78 const struct point_info
*info
,
83 * Fragment shader expects pre-multiplied w for LP_INTERP_PERSPECTIVE. A
84 * better stratergy would be to take the primitive in consideration when
85 * generating the fragment shader key, and therefore avoid the per-fragment
89 float w0
= info
->v0
[0][3];
93 info
->a0
[slot
][i
] = info
->v0
[slot
][i
]*w0
;
94 info
->dadx
[slot
][i
] = 0.0f
;
95 info
->dady
[slot
][i
] = 0.0f
;
100 * Setup automatic texcoord coefficients (for sprite rendering).
101 * \param slot the vertex attribute slot to setup
102 * \param i the attribute channel in [0,3]
103 * \param sprite_coord_origin one of PIPE_SPRITE_COORD_x
104 * \param perspective does the shader expects pre-multiplied w, i.e.,
105 * LP_INTERP_PERSPECTIVE is specified in the shader key
108 texcoord_coef(struct lp_setup_context
*setup
,
109 const struct point_info
*info
,
112 unsigned sprite_coord_origin
,
115 float w0
= info
->v0
[0][3];
120 float dadx
= FIXED_ONE
/ (float)info
->dx12
;
122 float x0
= info
->v0
[0][0] - setup
->pixel_offset
;
123 float y0
= info
->v0
[0][1] - setup
->pixel_offset
;
125 info
->dadx
[slot
][0] = dadx
;
126 info
->dady
[slot
][0] = dady
;
127 info
->a0
[slot
][0] = 0.5 - (dadx
* x0
+ dady
* y0
);
130 info
->dadx
[slot
][0] *= w0
;
131 info
->dady
[slot
][0] *= w0
;
132 info
->a0
[slot
][0] *= w0
;
137 float dady
= FIXED_ONE
/ (float)info
->dx12
;
138 float x0
= info
->v0
[0][0] - setup
->pixel_offset
;
139 float y0
= info
->v0
[0][1] - setup
->pixel_offset
;
141 if (sprite_coord_origin
== PIPE_SPRITE_COORD_LOWER_LEFT
) {
145 info
->dadx
[slot
][1] = dadx
;
146 info
->dady
[slot
][1] = dady
;
147 info
->a0
[slot
][1] = 0.5 - (dadx
* x0
+ dady
* y0
);
150 info
->dadx
[slot
][1] *= w0
;
151 info
->dady
[slot
][1] *= w0
;
152 info
->a0
[slot
][1] *= w0
;
156 info
->a0
[slot
][2] = 0.0f
;
157 info
->dadx
[slot
][2] = 0.0f
;
158 info
->dady
[slot
][2] = 0.0f
;
161 info
->a0
[slot
][3] = perspective
? w0
: 1.0f
;
162 info
->dadx
[slot
][3] = 0.0f
;
163 info
->dady
[slot
][3] = 0.0f
;
169 * Special coefficient setup for gl_FragCoord.
170 * X and Y are trivial
171 * Z and W are copied from position_coef which should have already been computed.
172 * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
175 setup_point_fragcoord_coef(struct lp_setup_context
*setup
,
176 struct point_info
*info
,
181 if (usage_mask
& TGSI_WRITEMASK_X
) {
182 info
->a0
[slot
][0] = 0.0;
183 info
->dadx
[slot
][0] = 1.0;
184 info
->dady
[slot
][0] = 0.0;
188 if (usage_mask
& TGSI_WRITEMASK_Y
) {
189 info
->a0
[slot
][1] = 0.0;
190 info
->dadx
[slot
][1] = 0.0;
191 info
->dady
[slot
][1] = 1.0;
195 if (usage_mask
& TGSI_WRITEMASK_Z
) {
196 constant_coef(setup
, info
, slot
, info
->v0
[0][2], 2);
200 if (usage_mask
& TGSI_WRITEMASK_W
) {
201 constant_coef(setup
, info
, slot
, info
->v0
[0][3], 3);
207 * Compute the point->coef[] array dadx, dady, a0 values.
210 setup_point_coefficients( struct lp_setup_context
*setup
,
211 struct point_info
*info
)
213 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
214 const struct lp_fragment_shader
*shader
= setup
->fs
.current
.variant
->shader
;
215 unsigned fragcoord_usage_mask
= TGSI_WRITEMASK_XYZ
;
218 /* setup interpolation for all the remaining attributes:
220 for (slot
= 0; slot
< key
->num_inputs
; slot
++) {
221 unsigned vert_attr
= key
->inputs
[slot
].src_index
;
222 unsigned usage_mask
= key
->inputs
[slot
].usage_mask
;
223 enum lp_interp interp
= key
->inputs
[slot
].interp
;
224 boolean perspective
= !!(interp
== LP_INTERP_PERSPECTIVE
);
227 if (perspective
&& usage_mask
) {
228 fragcoord_usage_mask
|= TGSI_WRITEMASK_W
;
232 case LP_INTERP_POSITION
:
234 * The generated pixel interpolators will pick up the coeffs from
235 * slot 0, so all need to ensure that the usage mask is covers all
238 fragcoord_usage_mask
|= usage_mask
;
241 case LP_INTERP_LINEAR
:
242 /* Sprite tex coords may use linear interpolation someday */
244 case LP_INTERP_PERSPECTIVE
: {
245 /* check if the sprite coord flag is set for this attribute.
246 * If so, set it up so it up so x and y vary from 0 to 1.
248 bool do_texcoord_coef
= false;
249 if (shader
->info
.base
.input_semantic_name
[slot
] == TGSI_SEMANTIC_PCOORD
) {
250 do_texcoord_coef
= true;
252 else if (shader
->info
.base
.input_semantic_name
[slot
] == TGSI_SEMANTIC_TEXCOORD
) {
253 unsigned semantic_index
= shader
->info
.base
.input_semantic_index
[slot
];
254 /* Note that sprite_coord enable is a bitfield of
255 * PIPE_MAX_SHADER_OUTPUTS bits.
257 if (semantic_index
< PIPE_MAX_SHADER_OUTPUTS
&&
258 (setup
->sprite_coord_enable
& (1u << semantic_index
))) {
259 do_texcoord_coef
= true;
262 if (do_texcoord_coef
) {
263 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
264 if (usage_mask
& (1 << i
)) {
265 texcoord_coef(setup
, info
, slot
+ 1, i
,
266 setup
->sprite_coord_origin
,
274 case LP_INTERP_CONSTANT
:
275 for (i
= 0; i
< NUM_CHANNELS
; i
++) {
276 if (usage_mask
& (1 << i
)) {
278 point_persp_coeff(setup
, info
, slot
+1, i
);
281 constant_coef(setup
, info
, slot
+1, info
->v0
[vert_attr
][i
], i
);
287 case LP_INTERP_FACING
:
288 for (i
= 0; i
< NUM_CHANNELS
; i
++)
289 if (usage_mask
& (1 << i
))
290 constant_coef(setup
, info
, slot
+1,
291 info
->frontfacing
? 1.0f
: -1.0f
, i
);
300 /* The internal position input is in slot zero:
302 setup_point_fragcoord_coef(setup
, info
, 0,
303 fragcoord_usage_mask
);
308 subpixel_snap(float a
)
310 return util_iround(FIXED_ONE
* a
);
314 * Print point vertex attribs (for debug).
317 print_point(struct lp_setup_context
*setup
,
318 const float (*v0
)[4],
321 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
324 debug_printf("llvmpipe point, width %f\n", size
);
325 for (i
= 0; i
< 1 + key
->num_inputs
; i
++) {
326 debug_printf(" v0[%d]: %f %f %f %f\n", i
,
327 v0
[i
][0], v0
[i
][1], v0
[i
][2], v0
[i
][3]);
333 try_setup_point( struct lp_setup_context
*setup
,
334 const float (*v0
)[4] )
336 struct llvmpipe_context
*lp_context
= (struct llvmpipe_context
*)setup
->pipe
;
337 /* x/y positions in fixed point */
338 const struct lp_setup_variant_key
*key
= &setup
->setup
.variant
->key
;
339 const int sizeAttr
= setup
->psize_slot
;
341 = (setup
->point_size_per_vertex
&& sizeAttr
> 0) ? v0
[sizeAttr
][0]
344 if (size
> LP_MAX_POINT_WIDTH
)
345 size
= LP_MAX_POINT_WIDTH
;
347 /* Yes this is necessary to accurately calculate bounding boxes
348 * with the two fill-conventions we support. GL (normally) ends
349 * up needing a bottom-left fill convention, which requires
350 * slightly different rounding.
352 int adj
= (setup
->bottom_edge_rule
!= 0) ? 1 : 0;
354 struct lp_scene
*scene
= setup
->scene
;
355 struct lp_rast_triangle
*point
;
358 unsigned nr_planes
= 4;
359 struct point_info info
;
360 unsigned viewport_index
= 0;
364 if (setup
->viewport_index_slot
> 0) {
365 unsigned *udata
= (unsigned*)v0
[setup
->viewport_index_slot
];
366 viewport_index
= lp_clamp_viewport_idx(*udata
);
368 if (setup
->layer_slot
> 0) {
369 layer
= *(unsigned*)v0
[setup
->layer_slot
];
370 layer
= MIN2(layer
, scene
->fb_max_layer
);
374 print_point(setup
, v0
, size
);
376 /* Bounding rectangle (in pixels) */
377 if (!lp_context
->rasterizer
||
378 lp_context
->rasterizer
->point_quad_rasterization
) {
380 * Rasterize points as quads.
383 /* Point size as fixed point integer, remove rounding errors
384 * and gives minimum width for very small points.
386 fixed_width
= MAX2(FIXED_ONE
, subpixel_snap(size
));
388 x0
= subpixel_snap(v0
[0][0] - setup
->pixel_offset
) - fixed_width
/2;
389 y0
= subpixel_snap(v0
[0][1] - setup
->pixel_offset
) - fixed_width
/2;
391 bbox
.x0
= (x0
+ (FIXED_ONE
-1)) >> FIXED_ORDER
;
392 bbox
.x1
= (x0
+ fixed_width
+ (FIXED_ONE
-1)) >> FIXED_ORDER
;
393 bbox
.y0
= (y0
+ (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
394 bbox
.y1
= (y0
+ fixed_width
+ (FIXED_ONE
-1) + adj
) >> FIXED_ORDER
;
396 /* Inclusive coordinates:
402 * OpenGL legacy rasterization rules for non-sprite points.
404 * Per OpenGL 2.1 spec, section 3.3.1, "Basic Point Rasterization".
406 * This type of point rasterization is only available in pre 3.0 contexts
407 * (or compatibilility contexts which we don't support) anyway.
410 const int x0
= subpixel_snap(v0
[0][0]);
411 const int y0
= subpixel_snap(v0
[0][1]) - adj
;
414 /* Point size as fixed point integer. For GL legacy points
415 * the point size is always a whole integer.
417 fixed_width
= MAX2(FIXED_ONE
,
418 (subpixel_snap(size
) + FIXED_ONE
/2 - 1) & ~(FIXED_ONE
-1));
419 int_width
= fixed_width
>> FIXED_ORDER
;
421 assert(setup
->pixel_offset
!= 0);
423 if (int_width
== 1) {
424 bbox
.x0
= x0
>> FIXED_ORDER
;
425 bbox
.y0
= y0
>> FIXED_ORDER
;
431 bbox
.x0
= (x0
>> FIXED_ORDER
) - (int_width
- 1)/2;
432 bbox
.y0
= (y0
>> FIXED_ORDER
) - (int_width
- 1)/2;
435 bbox
.x0
= ((x0
+ FIXED_ONE
/2) >> FIXED_ORDER
) - int_width
/2;
436 bbox
.y0
= ((y0
+ FIXED_ONE
/2) >> FIXED_ORDER
) - int_width
/2;
439 bbox
.x1
= bbox
.x0
+ int_width
- 1;
440 bbox
.y1
= bbox
.y0
+ int_width
- 1;
445 debug_printf(" bbox: (%i, %i) - (%i, %i)\n",
450 if (!u_rect_test_intersection(&setup
->draw_regions
[viewport_index
], &bbox
)) {
451 if (0) debug_printf("offscreen\n");
452 LP_COUNT(nr_culled_tris
);
456 u_rect_find_intersection(&setup
->draw_regions
[viewport_index
], &bbox
);
458 point
= lp_setup_alloc_triangle(scene
,
466 point
->v
[0][0] = v0
[0][0];
467 point
->v
[0][1] = v0
[0][1];
472 if (lp_context
->active_statistics_queries
) {
473 lp_context
->pipeline_statistics
.c_primitives
++;
476 if (draw_will_inject_frontface(lp_context
->draw
) &&
477 setup
->face_slot
> 0) {
478 point
->inputs
.frontfacing
= v0
[setup
->face_slot
][0];
480 point
->inputs
.frontfacing
= TRUE
;
485 info
.dx12
= fixed_width
;
486 info
.dy01
= fixed_width
;
488 info
.a0
= GET_A0(&point
->inputs
);
489 info
.dadx
= GET_DADX(&point
->inputs
);
490 info
.dady
= GET_DADY(&point
->inputs
);
491 info
.frontfacing
= point
->inputs
.frontfacing
;
493 /* Setup parameter interpolants:
495 setup_point_coefficients(setup
, &info
);
497 point
->inputs
.disable
= FALSE
;
498 point
->inputs
.opaque
= FALSE
;
499 point
->inputs
.layer
= layer
;
500 point
->inputs
.viewport_index
= viewport_index
;
503 struct lp_rast_plane
*plane
= GET_PLANES(point
);
505 plane
[0].dcdx
= ~0U << 8;
507 plane
[0].c
= (1-bbox
.x0
) << 8;
508 plane
[0].eo
= 1 << 8;
510 plane
[1].dcdx
= 1 << 8;
512 plane
[1].c
= (bbox
.x1
+1) << 8;
516 plane
[2].dcdy
= 1 << 8;
517 plane
[2].c
= (1-bbox
.y0
) << 8;
518 plane
[2].eo
= 1 << 8;
521 plane
[3].dcdy
= ~0U << 8;
522 plane
[3].c
= (bbox
.y1
+1) << 8;
526 return lp_setup_bin_triangle(setup
, point
, &bbox
, &bbox
, nr_planes
, viewport_index
);
531 lp_setup_point_discard(struct lp_setup_context
*setup
,
532 const float (*v0
)[4])
537 lp_setup_point(struct lp_setup_context
*setup
,
538 const float (*v0
)[4])
540 if (!try_setup_point(setup
, v0
)) {
541 if (!lp_setup_flush_and_restart(setup
))
544 if (!try_setup_point(setup
, v0
))
551 lp_setup_choose_point(struct lp_setup_context
*setup
)
553 if (setup
->rasterizer_discard
) {
554 setup
->point
= lp_setup_point_discard
;
556 setup
->point
= lp_setup_point
;