1 /**************************************************************************
3 * Copyright 2007 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 * \brief Clipping stage
31 * \author Keith Whitwell <keithw@vmware.com>
35 #include "util/u_bitcast.h"
36 #include "util/u_memory.h"
37 #include "util/u_math.h"
39 #include "pipe/p_shader_tokens.h"
42 #include "draw_pipe.h"
47 /** Set to 1 to enable printing of coords before/after clipping */
50 #define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)
55 struct draw_stage stage
; /**< base class */
58 boolean have_clipdist
;
61 /* List of the attributes to be constant interpolated. */
62 uint num_const_attribs
;
63 uint8_t const_attribs
[PIPE_MAX_SHADER_OUTPUTS
];
64 /* List of the attributes to be linear interpolated. */
65 uint num_linear_attribs
;
66 uint8_t linear_attribs
[PIPE_MAX_SHADER_OUTPUTS
];
67 /* List of the attributes to be perspective interpolated. */
68 uint num_perspect_attribs
;
69 uint8_t perspect_attribs
[PIPE_MAX_SHADER_OUTPUTS
];
76 static inline struct clip_stage
*clip_stage(struct draw_stage
*stage
)
78 return (struct clip_stage
*)stage
;
81 static inline unsigned
82 draw_viewport_index(struct draw_context
*draw
,
83 const struct vertex_header
*leading_vertex
)
85 if (draw_current_shader_uses_viewport_index(draw
)) {
86 unsigned viewport_index_output
=
87 draw_current_shader_viewport_index_output(draw
);
88 unsigned viewport_index
=
89 u_bitcast_f2u(leading_vertex
->data
[viewport_index_output
][0]);
90 return draw_clamp_viewport_idx(viewport_index
);
97 #define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))
100 /* All attributes are float[4], so this is easy:
102 static void interp_attr(float dst
[4],
107 dst
[0] = LINTERP( t
, out
[0], in
[0] );
108 dst
[1] = LINTERP( t
, out
[1], in
[1] );
109 dst
[2] = LINTERP( t
, out
[2], in
[2] );
110 dst
[3] = LINTERP( t
, out
[3], in
[3] );
115 * Copy flat shaded attributes src vertex to dst vertex.
117 static void copy_flat(struct draw_stage
*stage
,
118 struct vertex_header
*dst
,
119 const struct vertex_header
*src
)
121 const struct clip_stage
*clipper
= clip_stage(stage
);
123 for (i
= 0; i
< clipper
->num_const_attribs
; i
++) {
124 const uint attr
= clipper
->const_attribs
[i
];
125 COPY_4FV(dst
->data
[attr
], src
->data
[attr
]);
129 /* Interpolate between two vertices to produce a third.
131 static void interp(const struct clip_stage
*clip
,
132 struct vertex_header
*dst
,
134 const struct vertex_header
*out
,
135 const struct vertex_header
*in
,
136 unsigned viewport_index
)
138 const unsigned pos_attr
= clip
->pos_attr
;
145 dst
->edgeflag
= 0; /* will get overwritten later */
147 dst
->vertex_id
= UNDEFINED_VERTEX_ID
;
149 /* Interpolate the clip-space coords.
151 if (clip
->cv_attr
>= 0) {
152 interp_attr(dst
->data
[clip
->cv_attr
], t
,
153 in
->data
[clip
->cv_attr
], out
->data
[clip
->cv_attr
]);
155 /* interpolate the clip-space position */
156 interp_attr(dst
->clip_pos
, t
, in
->clip_pos
, out
->clip_pos
);
158 /* Do the projective divide and viewport transformation to get
159 * new window coordinates:
162 const float *pos
= dst
->clip_pos
;
164 clip
->stage
.draw
->viewports
[viewport_index
].scale
;
166 clip
->stage
.draw
->viewports
[viewport_index
].translate
;
167 const float oow
= 1.0f
/ pos
[3];
169 dst
->data
[pos_attr
][0] = pos
[0] * oow
* scale
[0] + trans
[0];
170 dst
->data
[pos_attr
][1] = pos
[1] * oow
* scale
[1] + trans
[1];
171 dst
->data
[pos_attr
][2] = pos
[2] * oow
* scale
[2] + trans
[2];
172 dst
->data
[pos_attr
][3] = oow
;
176 /* interp perspective attribs */
177 for (j
= 0; j
< clip
->num_perspect_attribs
; j
++) {
178 const unsigned attr
= clip
->perspect_attribs
[j
];
179 interp_attr(dst
->data
[attr
], t
, in
->data
[attr
], out
->data
[attr
]);
183 * Compute the t in screen-space instead of 3d space to use
184 * for noperspective interpolation.
186 * The points can be aligned with the X axis, so in that case try
187 * the Y. When both points are at the same screen position, we can
188 * pick whatever value (the interpolated point won't be in front
189 * anyway), so just use the 3d t.
191 if (clip
->num_linear_attribs
) {
194 /* find either in.x != out.x or in.y != out.y */
195 for (k
= 0; k
< 2; k
++) {
196 if (in
->clip_pos
[k
] != out
->clip_pos
[k
]) {
197 /* do divide by W, then compute linear interpolation factor */
198 float in_coord
= in
->clip_pos
[k
] / in
->clip_pos
[3];
199 float out_coord
= out
->clip_pos
[k
] / out
->clip_pos
[3];
200 float dst_coord
= dst
->clip_pos
[k
] / dst
->clip_pos
[3];
201 t_nopersp
= (dst_coord
- out_coord
) / (in_coord
- out_coord
);
205 for (j
= 0; j
< clip
->num_linear_attribs
; j
++) {
206 const unsigned attr
= clip
->linear_attribs
[j
];
207 interp_attr(dst
->data
[attr
], t_nopersp
, in
->data
[attr
], out
->data
[attr
]);
213 * Emit a post-clip polygon to the next pipeline stage. The polygon
214 * will be convex and the provoking vertex will always be vertex[0].
216 static void emit_poly(struct draw_stage
*stage
,
217 struct vertex_header
**inlist
,
218 const boolean
*edgeflags
,
220 const struct prim_header
*origPrim
)
222 const struct clip_stage
*clipper
= clip_stage(stage
);
223 struct prim_header header
;
225 ushort edge_first
, edge_middle
, edge_last
;
227 if (stage
->draw
->rasterizer
->flatshade_first
) {
228 edge_first
= DRAW_PIPE_EDGE_FLAG_0
;
229 edge_middle
= DRAW_PIPE_EDGE_FLAG_1
;
230 edge_last
= DRAW_PIPE_EDGE_FLAG_2
;
233 edge_first
= DRAW_PIPE_EDGE_FLAG_2
;
234 edge_middle
= DRAW_PIPE_EDGE_FLAG_0
;
235 edge_last
= DRAW_PIPE_EDGE_FLAG_1
;
241 /* later stages may need the determinant, but only the sign matters */
242 header
.det
= origPrim
->det
;
243 header
.flags
= DRAW_PIPE_RESET_STIPPLE
| edge_first
| edge_middle
;
246 for (i
= 2; i
< n
; i
++, header
.flags
= edge_middle
) {
247 /* order the triangle verts to respect the provoking vertex mode */
248 if (stage
->draw
->rasterizer
->flatshade_first
) {
249 header
.v
[0] = inlist
[0]; /* the provoking vertex */
250 header
.v
[1] = inlist
[i
-1];
251 header
.v
[2] = inlist
[i
];
254 header
.v
[0] = inlist
[i
-1];
255 header
.v
[1] = inlist
[i
];
256 header
.v
[2] = inlist
[0]; /* the provoking vertex */
259 if (!edgeflags
[i
-1]) {
260 header
.flags
&= ~edge_middle
;
263 if (i
== n
- 1 && edgeflags
[i
])
264 header
.flags
|= edge_last
;
268 debug_printf("Clipped tri: (flat-shade-first = %d)\n",
269 stage
->draw
->rasterizer
->flatshade_first
);
270 for (j
= 0; j
< 3; j
++) {
271 debug_printf(" Vert %d: clip pos: %f %f %f %f\n", j
,
272 header
.v
[j
]->clip_pos
[0],
273 header
.v
[j
]->clip_pos
[1],
274 header
.v
[j
]->clip_pos
[2],
275 header
.v
[j
]->clip_pos
[3]);
276 if (clipper
->cv_attr
>= 0) {
277 debug_printf(" Vert %d: cv: %f %f %f %f\n", j
,
278 header
.v
[j
]->data
[clipper
->cv_attr
][0],
279 header
.v
[j
]->data
[clipper
->cv_attr
][1],
280 header
.v
[j
]->data
[clipper
->cv_attr
][2],
281 header
.v
[j
]->data
[clipper
->cv_attr
][3]);
283 for (k
= 0; k
< draw_num_shader_outputs(stage
->draw
); k
++) {
284 debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j
, k
,
285 header
.v
[j
]->data
[k
][0],
286 header
.v
[j
]->data
[k
][1],
287 header
.v
[j
]->data
[k
][2],
288 header
.v
[j
]->data
[k
][3]);
292 stage
->next
->tri(stage
->next
, &header
);
298 dot4(const float *a
, const float *b
)
300 return (a
[0] * b
[0] +
307 * this function extracts the clip distance for the current plane,
308 * it first checks if the shader provided a clip distance, otherwise
309 * it works out the value using the clipvertex
311 static inline float getclipdist(const struct clip_stage
*clipper
,
312 struct vertex_header
*vert
,
318 /* ordinary xyz view volume clipping uses pos output */
319 plane
= clipper
->plane
[plane_idx
];
320 dp
= dot4(vert
->clip_pos
, plane
);
322 else if (clipper
->have_clipdist
) {
323 /* pick the correct clipdistance element from the output vectors */
324 int _idx
= plane_idx
- 6;
326 int vidx
= cdi
? _idx
- 4 : _idx
;
327 dp
= vert
->data
[draw_current_shader_ccdistance_output(clipper
->stage
.draw
, cdi
)][vidx
];
330 * legacy user clip planes or gl_ClipVertex
332 plane
= clipper
->plane
[plane_idx
];
333 if (clipper
->cv_attr
>= 0) {
334 dp
= dot4(vert
->data
[clipper
->cv_attr
], plane
);
337 dp
= dot4(vert
->clip_pos
, plane
);
343 /* Clip a triangle against the viewport and user clip planes.
346 do_clip_tri(struct draw_stage
*stage
,
347 struct prim_header
*header
,
350 struct clip_stage
*clipper
= clip_stage( stage
);
351 struct vertex_header
*a
[MAX_CLIPPED_VERTICES
];
352 struct vertex_header
*b
[MAX_CLIPPED_VERTICES
];
353 struct vertex_header
**inlist
= a
;
354 struct vertex_header
**outlist
= b
;
355 struct vertex_header
*prov_vertex
;
359 boolean aEdges
[MAX_CLIPPED_VERTICES
];
360 boolean bEdges
[MAX_CLIPPED_VERTICES
];
361 boolean
*inEdges
= aEdges
;
362 boolean
*outEdges
= bEdges
;
363 int viewport_index
= 0;
365 inlist
[0] = header
->v
[0];
366 inlist
[1] = header
->v
[1];
367 inlist
[2] = header
->v
[2];
370 * For d3d10, we need to take this from the leading (first) vertex.
371 * For GL, we could do anything (as long as we advertize
372 * GL_UNDEFINED_VERTEX for the VIEWPORT_INDEX_PROVOKING_VERTEX query),
373 * but it needs to be consistent with what other parts (i.e. driver)
374 * will do, and that seems easier with GL_PROVOKING_VERTEX logic.
376 if (stage
->draw
->rasterizer
->flatshade_first
) {
377 prov_vertex
= inlist
[0];
380 prov_vertex
= inlist
[2];
382 viewport_index
= draw_viewport_index(clipper
->stage
.draw
, prov_vertex
);
385 const float *v0
= header
->v
[0]->clip_pos
;
386 const float *v1
= header
->v
[1]->clip_pos
;
387 const float *v2
= header
->v
[2]->clip_pos
;
388 debug_printf("Clip triangle pos:\n");
389 debug_printf(" %f, %f, %f, %f\n", v0
[0], v0
[1], v0
[2], v0
[3]);
390 debug_printf(" %f, %f, %f, %f\n", v1
[0], v1
[1], v1
[2], v1
[3]);
391 debug_printf(" %f, %f, %f, %f\n", v2
[0], v2
[1], v2
[2], v2
[3]);
392 if (clipper
->cv_attr
>= 0) {
393 const float *v0
= header
->v
[0]->data
[clipper
->cv_attr
];
394 const float *v1
= header
->v
[1]->data
[clipper
->cv_attr
];
395 const float *v2
= header
->v
[2]->data
[clipper
->cv_attr
];
396 debug_printf("Clip triangle cv:\n");
397 debug_printf(" %f, %f, %f, %f\n", v0
[0], v0
[1], v0
[2], v0
[3]);
398 debug_printf(" %f, %f, %f, %f\n", v1
[0], v1
[1], v1
[2], v1
[3]);
399 debug_printf(" %f, %f, %f, %f\n", v2
[0], v2
[1], v2
[2], v2
[3]);
404 * Note: at this point we can't just use the per-vertex edge flags.
405 * We have to observe the edge flag bits set in header->flags which
406 * were set during primitive decomposition. Put those flags into
407 * an edge flags array which parallels the vertex array.
408 * Later, in the 'unfilled' pipeline stage we'll draw the edge if both
409 * the header.flags bit is set AND the per-vertex edgeflag field is set.
411 inEdges
[0] = !!(header
->flags
& DRAW_PIPE_EDGE_FLAG_0
);
412 inEdges
[1] = !!(header
->flags
& DRAW_PIPE_EDGE_FLAG_1
);
413 inEdges
[2] = !!(header
->flags
& DRAW_PIPE_EDGE_FLAG_2
);
415 while (clipmask
&& n
>= 3) {
416 const unsigned plane_idx
= ffs(clipmask
)-1;
417 const boolean is_user_clip_plane
= plane_idx
>= 6;
418 struct vertex_header
*vert_prev
= inlist
[0];
419 boolean
*edge_prev
= &inEdges
[0];
421 unsigned outcount
= 0;
423 dp_prev
= getclipdist(clipper
, vert_prev
, plane_idx
);
424 clipmask
&= ~(1<<plane_idx
);
426 if (util_is_inf_or_nan(dp_prev
))
427 return; //discard nan
429 assert(n
< MAX_CLIPPED_VERTICES
);
430 if (n
>= MAX_CLIPPED_VERTICES
)
432 inlist
[n
] = inlist
[0]; /* prevent rotation of vertices */
433 inEdges
[n
] = inEdges
[0];
435 for (i
= 1; i
<= n
; i
++) {
436 struct vertex_header
*vert
= inlist
[i
];
437 boolean
*edge
= &inEdges
[i
];
438 boolean different_sign
;
440 float dp
= getclipdist(clipper
, vert
, plane_idx
);
442 if (util_is_inf_or_nan(dp
))
443 return; //discard nan
445 if (dp_prev
>= 0.0f
) {
446 assert(outcount
< MAX_CLIPPED_VERTICES
);
447 if (outcount
>= MAX_CLIPPED_VERTICES
)
449 outEdges
[outcount
] = *edge_prev
;
450 outlist
[outcount
++] = vert_prev
;
451 different_sign
= dp
< 0.0f
;
453 different_sign
= !(dp
< 0.0f
);
456 if (different_sign
) {
457 struct vertex_header
*new_vert
;
460 assert(tmpnr
< MAX_CLIPPED_VERTICES
+ 1);
461 if (tmpnr
>= MAX_CLIPPED_VERTICES
+ 1)
463 new_vert
= clipper
->stage
.tmp
[tmpnr
++];
465 assert(outcount
< MAX_CLIPPED_VERTICES
);
466 if (outcount
>= MAX_CLIPPED_VERTICES
)
469 new_edge
= &outEdges
[outcount
];
470 outlist
[outcount
++] = new_vert
;
473 /* Going out of bounds. Avoid division by zero as we
474 * know dp != dp_prev from different_sign, above.
476 float t
= dp
/ (dp
- dp_prev
);
477 interp( clipper
, new_vert
, t
, vert
, vert_prev
, viewport_index
);
479 /* Whether or not to set edge flag for the new vert depends
480 * on whether it's a user-defined clipping plane. We're
481 * copying NVIDIA's behaviour here.
483 if (is_user_clip_plane
) {
484 /* we want to see an edge along the clip plane */
486 new_vert
->edgeflag
= TRUE
;
489 /* we don't want to see an edge along the frustum clip plane */
490 *new_edge
= *edge_prev
;
491 new_vert
->edgeflag
= FALSE
;
497 float t
= dp_prev
/ (dp_prev
- dp
);
498 interp( clipper
, new_vert
, t
, vert_prev
, vert
, viewport_index
);
500 /* Copy starting vert's edgeflag:
502 new_vert
->edgeflag
= vert_prev
->edgeflag
;
503 *new_edge
= *edge_prev
;
512 /* swap in/out lists */
514 struct vertex_header
**tmp
= inlist
;
520 boolean
*tmp
= inEdges
;
527 /* If constant interpolated, copy provoking vertex attrib to polygon vertex[0]
530 if (clipper
->num_const_attribs
) {
531 if (stage
->draw
->rasterizer
->flatshade_first
) {
532 if (inlist
[0] != header
->v
[0]) {
533 assert(tmpnr
< MAX_CLIPPED_VERTICES
+ 1);
534 if (tmpnr
>= MAX_CLIPPED_VERTICES
+ 1)
536 inlist
[0] = dup_vert(stage
, inlist
[0], tmpnr
++);
537 copy_flat(stage
, inlist
[0], header
->v
[0]);
541 if (inlist
[0] != header
->v
[2]) {
542 assert(tmpnr
< MAX_CLIPPED_VERTICES
+ 1);
543 if (tmpnr
>= MAX_CLIPPED_VERTICES
+ 1)
545 inlist
[0] = dup_vert(stage
, inlist
[0], tmpnr
++);
546 copy_flat(stage
, inlist
[0], header
->v
[2]);
551 /* Emit the polygon as triangles to the setup stage:
553 emit_poly(stage
, inlist
, inEdges
, n
, header
);
558 /* Clip a line against the viewport and user clip planes.
561 do_clip_line(struct draw_stage
*stage
,
562 struct prim_header
*header
,
565 const struct clip_stage
*clipper
= clip_stage(stage
);
566 struct vertex_header
*v0
= header
->v
[0];
567 struct vertex_header
*v1
= header
->v
[1];
568 struct vertex_header
*prov_vertex
;
571 struct prim_header newprim
;
574 newprim
.flags
= header
->flags
;
576 if (stage
->draw
->rasterizer
->flatshade_first
) {
582 viewport_index
= draw_viewport_index(clipper
->stage
.draw
, prov_vertex
);
585 const unsigned plane_idx
= ffs(clipmask
)-1;
586 const float dp0
= getclipdist(clipper
, v0
, plane_idx
);
587 const float dp1
= getclipdist(clipper
, v1
, plane_idx
);
589 if (util_is_inf_or_nan(dp0
) || util_is_inf_or_nan(dp1
))
590 return; //discard nan
593 float t
= dp1
/ (dp1
- dp0
);
598 float t
= dp0
/ (dp0
- dp1
);
603 return; /* discard */
605 clipmask
&= ~(1 << plane_idx
); /* turn off this plane's bit */
609 interp( clipper
, stage
->tmp
[0], t0
, v0
, v1
, viewport_index
);
610 if (stage
->draw
->rasterizer
->flatshade_first
) {
611 copy_flat(stage
, stage
->tmp
[0], v0
); /* copy v0 color to tmp[0] */
614 copy_flat(stage
, stage
->tmp
[0], v1
); /* copy v1 color to tmp[0] */
616 newprim
.v
[0] = stage
->tmp
[0];
623 interp( clipper
, stage
->tmp
[1], t1
, v1
, v0
, viewport_index
);
624 if (stage
->draw
->rasterizer
->flatshade_first
) {
625 copy_flat(stage
, stage
->tmp
[1], v0
); /* copy v0 color to tmp[1] */
628 copy_flat(stage
, stage
->tmp
[1], v1
); /* copy v1 color to tmp[1] */
630 newprim
.v
[1] = stage
->tmp
[1];
636 stage
->next
->line( stage
->next
, &newprim
);
641 clip_point(struct draw_stage
*stage
, struct prim_header
*header
)
643 if (header
->v
[0]->clipmask
== 0)
644 stage
->next
->point( stage
->next
, header
);
649 * Clip points but ignore the first 4 (xy) clip planes.
650 * (Because the generated clip mask is completely unaffacted by guard band,
651 * we still need to manually evaluate the x/y planes if they are outside
652 * the guard band and not just outside the vp.)
655 clip_point_guard_xy(struct draw_stage
*stage
, struct prim_header
*header
)
657 unsigned clipmask
= header
->v
[0]->clipmask
;
658 if ((clipmask
& 0xffffffff) == 0)
659 stage
->next
->point(stage
->next
, header
);
660 else if ((clipmask
& 0xfffffff0) == 0) {
662 const unsigned plane_idx
= ffs(clipmask
)-1;
663 clipmask
&= ~(1 << plane_idx
); /* turn off this plane's bit */
664 /* TODO: this should really do proper guardband clipping,
665 * currently just throw out infs/nans.
666 * Also note that vertices with negative w values MUST be tossed
667 * out (not sure if proper guardband clipping would do this
668 * automatically). These would usually be captured by depth clip
669 * too but this can be disabled.
671 if (header
->v
[0]->clip_pos
[3] <= 0.0f
||
672 util_is_inf_or_nan(header
->v
[0]->clip_pos
[0]) ||
673 util_is_inf_or_nan(header
->v
[0]->clip_pos
[1]))
676 stage
->next
->point(stage
->next
, header
);
682 clip_first_point(struct draw_stage
*stage
, struct prim_header
*header
)
684 stage
->point
= stage
->draw
->guard_band_points_xy
? clip_point_guard_xy
: clip_point
;
685 stage
->point(stage
, header
);
690 clip_line(struct draw_stage
*stage
, struct prim_header
*header
)
692 unsigned clipmask
= (header
->v
[0]->clipmask
|
693 header
->v
[1]->clipmask
);
696 /* no clipping needed */
697 stage
->next
->line( stage
->next
, header
);
699 else if ((header
->v
[0]->clipmask
&
700 header
->v
[1]->clipmask
) == 0) {
701 do_clip_line(stage
, header
, clipmask
);
703 /* else, totally clipped */
708 clip_tri(struct draw_stage
*stage
, struct prim_header
*header
)
710 unsigned clipmask
= (header
->v
[0]->clipmask
|
711 header
->v
[1]->clipmask
|
712 header
->v
[2]->clipmask
);
715 /* no clipping needed */
716 stage
->next
->tri( stage
->next
, header
);
718 else if ((header
->v
[0]->clipmask
&
719 header
->v
[1]->clipmask
&
720 header
->v
[2]->clipmask
) == 0) {
721 do_clip_tri(stage
, header
, clipmask
);
727 find_interp(const struct draw_fragment_shader
*fs
, int *indexed_interp
,
728 uint semantic_name
, uint semantic_index
)
731 /* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
732 * from the array we've filled before. */
733 if ((semantic_name
== TGSI_SEMANTIC_COLOR
||
734 semantic_name
== TGSI_SEMANTIC_BCOLOR
) &&
735 semantic_index
< 2) {
736 interp
= indexed_interp
[semantic_index
];
737 } else if (semantic_name
== TGSI_SEMANTIC_POSITION
||
738 semantic_name
== TGSI_SEMANTIC_CLIPVERTEX
) {
739 /* these inputs are handled specially always */
742 /* Otherwise, search in the FS inputs, with a decent default
743 * if we don't find it.
744 * This probably only matters for layer, vpindex, culldist, maybe
748 if (semantic_name
== TGSI_SEMANTIC_LAYER
||
749 semantic_name
== TGSI_SEMANTIC_VIEWPORT_INDEX
) {
750 interp
= TGSI_INTERPOLATE_CONSTANT
;
753 interp
= TGSI_INTERPOLATE_PERSPECTIVE
;
756 for (j
= 0; j
< fs
->info
.num_inputs
; j
++) {
757 if (semantic_name
== fs
->info
.input_semantic_name
[j
] &&
758 semantic_index
== fs
->info
.input_semantic_index
[j
]) {
759 interp
= fs
->info
.input_interpolate
[j
];
768 /* Update state. Could further delay this until we hit the first
769 * primitive that really requires clipping.
772 clip_init_state(struct draw_stage
*stage
)
774 struct clip_stage
*clipper
= clip_stage(stage
);
775 const struct draw_context
*draw
= stage
->draw
;
776 const struct draw_fragment_shader
*fs
= draw
->fs
.fragment_shader
;
777 const struct tgsi_shader_info
*info
= draw_get_shader_info(draw
);
779 int indexed_interp
[2];
781 clipper
->pos_attr
= draw_current_shader_position_output(draw
);
782 clipper
->have_clipdist
= draw_current_shader_num_written_clipdistances(draw
) > 0;
783 if (draw_current_shader_clipvertex_output(draw
) != clipper
->pos_attr
) {
784 clipper
->cv_attr
= (int)draw_current_shader_clipvertex_output(draw
);
787 clipper
->cv_attr
= -1;
790 /* We need to know for each attribute what kind of interpolation is
791 * done on it (flat, smooth or noperspective). But the information
792 * is not directly accessible for outputs, only for inputs. So we
793 * have to match semantic name and index between the VS (or GS/ES)
794 * outputs and the FS inputs to get to the interpolation mode.
796 * The only hitch is with gl_FrontColor/gl_BackColor which map to
797 * gl_Color, and their Secondary versions. First there are (up to)
798 * two outputs for one input, so we tuck the information in a
799 * specific array. Second if they don't have qualifiers, the
800 * default value has to be picked from the global shade mode.
802 * Of course, if we don't have a fragment shader in the first
803 * place, defaults should be used.
806 /* First pick up the interpolation mode for
807 * gl_Color/gl_SecondaryColor, with the correct default.
809 indexed_interp
[0] = indexed_interp
[1] = draw
->rasterizer
->flatshade
?
810 TGSI_INTERPOLATE_CONSTANT
: TGSI_INTERPOLATE_PERSPECTIVE
;
813 for (i
= 0; i
< fs
->info
.num_inputs
; i
++) {
814 if (fs
->info
.input_semantic_name
[i
] == TGSI_SEMANTIC_COLOR
&&
815 fs
->info
.input_semantic_index
[i
] < 2) {
816 if (fs
->info
.input_interpolate
[i
] != TGSI_INTERPOLATE_COLOR
)
817 indexed_interp
[fs
->info
.input_semantic_index
[i
]] = fs
->info
.input_interpolate
[i
];
822 /* Then resolve the interpolation mode for every output attribute. */
824 clipper
->num_const_attribs
= 0;
825 clipper
->num_linear_attribs
= 0;
826 clipper
->num_perspect_attribs
= 0;
827 for (i
= 0; i
< info
->num_outputs
; i
++) {
828 /* Find the interpolation mode for a specific attribute */
829 int interp
= find_interp(fs
, indexed_interp
,
830 info
->output_semantic_name
[i
],
831 info
->output_semantic_index
[i
]);
833 case TGSI_INTERPOLATE_CONSTANT
:
834 clipper
->const_attribs
[clipper
->num_const_attribs
] = i
;
835 clipper
->num_const_attribs
++;
837 case TGSI_INTERPOLATE_LINEAR
:
838 clipper
->linear_attribs
[clipper
->num_linear_attribs
] = i
;
839 clipper
->num_linear_attribs
++;
841 case TGSI_INTERPOLATE_PERSPECTIVE
:
842 clipper
->perspect_attribs
[clipper
->num_perspect_attribs
] = i
;
843 clipper
->num_perspect_attribs
++;
845 case TGSI_INTERPOLATE_COLOR
:
846 if (draw
->rasterizer
->flatshade
) {
847 clipper
->const_attribs
[clipper
->num_const_attribs
] = i
;
848 clipper
->num_const_attribs
++;
850 clipper
->perspect_attribs
[clipper
->num_perspect_attribs
] = i
;
851 clipper
->num_perspect_attribs
++;
855 assert(interp
== -1);
859 /* Search the extra vertex attributes */
860 for (j
= 0; j
< draw
->extra_shader_outputs
.num
; j
++) {
861 /* Find the interpolation mode for a specific attribute */
862 int interp
= find_interp(fs
, indexed_interp
,
863 draw
->extra_shader_outputs
.semantic_name
[j
],
864 draw
->extra_shader_outputs
.semantic_index
[j
]);
866 case TGSI_INTERPOLATE_CONSTANT
:
867 clipper
->const_attribs
[clipper
->num_const_attribs
] = i
+ j
;
868 clipper
->num_const_attribs
++;
870 case TGSI_INTERPOLATE_LINEAR
:
871 clipper
->linear_attribs
[clipper
->num_linear_attribs
] = i
+ j
;
872 clipper
->num_linear_attribs
++;
874 case TGSI_INTERPOLATE_PERSPECTIVE
:
875 clipper
->perspect_attribs
[clipper
->num_perspect_attribs
] = i
+ j
;
876 clipper
->num_perspect_attribs
++;
879 assert(interp
== -1);
884 stage
->tri
= clip_tri
;
885 stage
->line
= clip_line
;
890 static void clip_first_tri(struct draw_stage
*stage
,
891 struct prim_header
*header
)
893 clip_init_state( stage
);
894 stage
->tri( stage
, header
);
897 static void clip_first_line(struct draw_stage
*stage
,
898 struct prim_header
*header
)
900 clip_init_state( stage
);
901 stage
->line( stage
, header
);
905 static void clip_flush(struct draw_stage
*stage
, unsigned flags
)
907 stage
->tri
= clip_first_tri
;
908 stage
->line
= clip_first_line
;
909 stage
->next
->flush( stage
->next
, flags
);
913 static void clip_reset_stipple_counter(struct draw_stage
*stage
)
915 stage
->next
->reset_stipple_counter( stage
->next
);
919 static void clip_destroy(struct draw_stage
*stage
)
921 draw_free_temp_verts( stage
);
927 * Allocate a new clipper stage.
928 * \return pointer to new stage object
930 struct draw_stage
*draw_clip_stage(struct draw_context
*draw
)
932 struct clip_stage
*clipper
= CALLOC_STRUCT(clip_stage
);
936 clipper
->stage
.draw
= draw
;
937 clipper
->stage
.name
= "clipper";
938 clipper
->stage
.point
= clip_first_point
;
939 clipper
->stage
.line
= clip_first_line
;
940 clipper
->stage
.tri
= clip_first_tri
;
941 clipper
->stage
.flush
= clip_flush
;
942 clipper
->stage
.reset_stipple_counter
= clip_reset_stipple_counter
;
943 clipper
->stage
.destroy
= clip_destroy
;
945 clipper
->plane
= draw
->plane
;
947 if (!draw_alloc_temp_verts( &clipper
->stage
, MAX_CLIPPED_VERTICES
+1 ))
950 return &clipper
->stage
;
954 clipper
->stage
.destroy( &clipper
->stage
);