Add support for using the clipdistance instead of clip plane.
Passes all piglit clipdistance tests.
v2: fixup some comments from Brian in review.
Signed-off-by: Dave Airlie <airlied@redhat.com>
/* const */ float (*plane)[4] = pvs->draw->plane;
const unsigned pos = draw_current_shader_position_output(pvs->draw);
const unsigned cv = draw_current_shader_clipvertex_output(pvs->draw);
+ unsigned cd[2];
const unsigned ef = pvs->draw->vs.edgeflag_output;
const unsigned ucp_enable = pvs->draw->rasterizer->clip_plane_enable;
const unsigned flags = (FLAGS);
unsigned need_pipeline = 0;
unsigned j;
unsigned i;
+ bool have_cd = false;
+ cd[0] = draw_current_shader_clipdistance_output(pvs->draw, 0);
+ cd[1] = draw_current_shader_clipdistance_output(pvs->draw, 1);
+
+ if (cd[0] != pos || cd[1] != pos)
+ have_cd = true;
for (j = 0; j < info->count; j++) {
float *position = out->data[pos];
if (flags & DO_CLIP_USER) {
unsigned ucp_mask = ucp_enable;
-
+ int num_written_clipdistance = pvs->draw->vs.vertex_shader->info.num_written_clipdistance;
while (ucp_mask) {
unsigned plane_idx = ffs(ucp_mask)-1;
ucp_mask &= ~(1 << plane_idx);
plane_idx += 6;
- if (dot4(clipvertex, plane[plane_idx]) < 0) {
- mask |= 1 << plane_idx;
+ /*
+ * for user clipping check if we have a clip distance output
+ * and the shader has written to it, otherwise use clipvertex
+ * to decide when the plane is clipping.
+ */
+ if (have_cd && num_written_clipdistance) {
+ float clipdist;
+ i = plane_idx - 6;
+ out->have_clipdist = 1;
+ /* first four clip distance in first vector etc. */
+ if (i < 4)
+ clipdist = out->data[cd[0]][i];
+ else
+ clipdist = out->data[cd[1]][i-4];
+ if (clipdist < 0)
+ mask |= 1 << plane_idx;
+ } else {
+ if (dot4(clipvertex, plane[plane_idx]) < 0)
+ mask |= 1 << plane_idx;
}
}
}
return draw->vs.clipvertex_output;
}
+uint
+draw_current_shader_clipdistance_output(const struct draw_context *draw, int index)
+{
+ return draw->vs.clipdistance_output[index];
+}
+
/**
* Return a pointer/handle for a driver/CSO rasterizer object which
* disabled culling, stippling, unfilled tris, etc.
const unsigned nr_attrs = draw_current_shader_outputs(clip->stage.draw);
const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw);
const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw);
+ unsigned clip_dist[2];
unsigned j;
+ clip_dist[0] = draw_current_shader_clipdistance_output(clip->stage.draw, 0);
+ clip_dist[1] = draw_current_shader_clipdistance_output(clip->stage.draw, 1);
+
/* Vertex header.
*/
dst->clipmask = 0;
dst->edgeflag = 0; /* will get overwritten later */
- dst->pad = 0;
+ dst->have_clipdist = in->have_clipdist;
dst->vertex_id = UNDEFINED_VERTEX_ID;
/* Interpolate the clip-space coords.
a[3] * b[3]);
}
+/*
+ * this function extracts the clip distance for the current plane,
+ * it first checks if the shader provided a clip distance, otherwise
+ * it works out the value using the clipvertex
+ */
+static INLINE float getclipdist(const struct clip_stage *clipper,
+ struct vertex_header *vert,
+ int plane_idx)
+{
+ const float *plane;
+ float dp;
+ if (vert->have_clipdist && plane_idx >= 6) {
+ /* pick the correct clipdistance element from the output vectors */
+ int _idx = plane_idx - 6;
+ int cdi = _idx >= 4;
+ int vidx = cdi ? _idx - 4 : _idx;
+ dp = vert->data[draw_current_shader_clipdistance_output(clipper->stage.draw, cdi)][vidx];
+ } else {
+ plane = clipper->plane[plane_idx];
+ dp = dot4(vert->clip, plane);
+ }
+ return dp;
+}
/* Clip a triangle against the viewport and user clip planes.
*/
while (clipmask && n >= 3) {
const unsigned plane_idx = ffs(clipmask)-1;
const boolean is_user_clip_plane = plane_idx >= 6;
- const float *plane = clipper->plane[plane_idx];
struct vertex_header *vert_prev = inlist[0];
boolean *edge_prev = &inEdges[0];
- float dp_prev = dot4( vert_prev->clip, plane );
+ float dp_prev;
unsigned outcount = 0;
+ dp_prev = getclipdist(clipper, vert_prev, plane_idx);
clipmask &= ~(1<<plane_idx);
assert(n < MAX_CLIPPED_VERTICES);
struct vertex_header *vert = inlist[i];
boolean *edge = &inEdges[i];
- float dp = dot4( vert->clip, plane );
+ float dp = getclipdist(clipper, vert, plane_idx);
if (!IS_NEGATIVE(dp_prev)) {
assert(outcount < MAX_CLIPPED_VERTICES);
const struct clip_stage *clipper = clip_stage( stage );
struct vertex_header *v0 = header->v[0];
struct vertex_header *v1 = header->v[1];
- const float *pos0 = v0->clip;
- const float *pos1 = v1->clip;
float t0 = 0.0F;
float t1 = 0.0F;
struct prim_header newprim;
while (clipmask) {
const unsigned plane_idx = ffs(clipmask)-1;
- const float *plane = clipper->plane[plane_idx];
- const float dp0 = dot4( pos0, plane );
- const float dp1 = dot4( pos1, plane );
+ const float dp0 = getclipdist(clipper, v0, plane_idx);
+ const float dp1 = getclipdist(clipper, v1, plane_idx);
if (dp1 < 0.0F) {
float t = dp1 / (dp1 - dp0);
struct vertex_header {
unsigned clipmask:DRAW_TOTAL_CLIP_PLANES;
unsigned edgeflag:1;
- unsigned pad:1;
+ unsigned have_clipdist:1;
unsigned vertex_id:16;
float clip[4];
uint position_output;
uint edgeflag_output;
uint clipvertex_output;
-
+ uint clipdistance_output[2];
/** TGSI program interpreter runtime state */
struct tgsi_exec_machine *machine;
uint draw_current_shader_outputs(const struct draw_context *draw);
uint draw_current_shader_position_output(const struct draw_context *draw);
uint draw_current_shader_clipvertex_output(const struct draw_context *draw);
+uint draw_current_shader_clipdistance_output(const struct draw_context *draw, int index);
int draw_alloc_extra_vertex_attrib(struct draw_context *draw,
uint semantic_name, uint semantic_index);
void draw_remove_extra_vertex_attribs(struct draw_context *draw);
#include "draw/draw_context.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
-
+#include "draw/draw_vs.h"
#define DO_CLIP_XY 0x1
#define DO_CLIP_FULL_Z 0x2
{
header->clipmask = 0;
header->edgeflag = 1;
- header->pad = 0;
+ header->have_clipdist = 0;
header->vertex_id = UNDEFINED_VERTEX_ID;
}
vs->info.output_semantic_index[i] == 0) {
found_clipvertex = TRUE;
vs->clipvertex_output = i;
+ } else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) {
+ if (vs->info.output_semantic_index[i] == 0)
+ vs->clipdistance_output[0] = i;
+ else
+ vs->clipdistance_output[1] = i;
}
}
if (!found_clipvertex)
draw->vs.position_output = dvs->position_output;
draw->vs.edgeflag_output = dvs->edgeflag_output;
draw->vs.clipvertex_output = dvs->clipvertex_output;
+ draw->vs.clipdistance_output[0] = dvs->clipdistance_output[0];
+ draw->vs.clipdistance_output[1] = dvs->clipdistance_output[1];
dvs->prepare( dvs, draw );
}
else {
unsigned position_output;
unsigned edgeflag_output;
unsigned clipvertex_output;
-
+ unsigned clipdistance_output[2];
/* Extracted from shader:
*/
const float (*immediates)[4];