draw: clean up d3d style point clipping
authorRoland Scheidegger <sroland@vmware.com>
Fri, 17 Jan 2014 18:39:19 +0000 (19:39 +0100)
committerRoland Scheidegger <sroland@vmware.com>
Mon, 20 Jan 2014 16:45:53 +0000 (17:45 +0100)
Instead of skipping x/y clipping completely if there's point_tri_clip points
use guard band clipping. This should be easier (previously we could not disable
generating the x/y bits in the clip mask for llvm path, hence requiring custom
clip path), and it also allows us to enable this for tris-as-points more easily
too (this would require custom tri clip filtering too otherwise). Moreover,
some unexpected things could have happen if there's a NaN or just a huge number
in some tri-turned-point, as the driver's rasterizer would need to deal with it
and that might well lead to undefined behavior in typical rasterizers (which
need to convert these numbers to fixed point). Using a guardband should hence
be more robust, while "usually" guaranteeing the same results. (Only "usually"
because unlike hw guardbands draw guardband is always just twice the vp size,
hence small vp but large points could still lead to different results.)
Unfortunately because the clipmask generated is completely unaffected by guard
band clipping, we still need a custom clip stage for points (but not for tris,
as the actual clipping there takes guard band into account).

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_pipe_clip.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c

index baebc16036c028d4c7028e4f40201e8caeace163..da1e958900cd74b3fa1acd0bd31923fff3114f07 100644 (file)
@@ -262,10 +262,10 @@ static void update_clip_flags( struct draw_context *draw )
                    draw->rasterizer && draw->rasterizer->depth_clip);
    draw->clip_user = draw->rasterizer &&
                      draw->rasterizer->clip_plane_enable != 0;
-   draw->clip_points_xy = draw->clip_xy &&
-                          (!draw->driver.bypass_clip_points ||
-                          (draw->rasterizer &&
-                          !draw->rasterizer->point_tri_clip));
+   draw->guard_band_points_xy = draw->guard_band_xy ||
+                                (draw->driver.bypass_clip_points &&
+                                (draw->rasterizer &&
+                                 draw->rasterizer->point_tri_clip));
 }
 
 /**
index b0794583e96868da9bde753314c78196cd544e16..8bdb882218b0f935e19a6340924bb7e07e200d64 100644 (file)
@@ -615,19 +615,33 @@ clip_point( struct draw_stage *stage,
       stage->next->point( stage->next, header );
 }
 
+
 /*
  * Clip points but ignore the first 4 (xy) clip planes.
- * (This is necessary because we don't generate a different shader variant
- * just for points hence xy clip bits are still generated. This is not really
- * optimal because of the extra calculations both in generating clip masks
- * and executing the clip stage but it gets the job done.)
+ * (Because the generated clip mask is completely unaffacted by guard band,
+ * we still need to manually evaluate the x/y planes if they are outside
+ * the guard band and not just outside the vp.)
  */
 static void
-clip_point_no_xy( struct draw_stage *stage,
-                  struct prim_header *header )
+clip_point_guard_xy( struct draw_stage *stage,
+                     struct prim_header *header )
 {
-   if ((header->v[0]->clipmask & 0xfffffff0) == 0)
-      stage->next->point( stage->next, header );
+   unsigned clipmask = header->v[0]->clipmask;
+   if ((clipmask & 0xffffffff) == 0)
+      stage->next->point(stage->next, header);
+   else if ((clipmask & 0xfffffff0) == 0) {
+      while (clipmask) {
+         const unsigned plane_idx = ffs(clipmask)-1;
+         clipmask &= ~(1 << plane_idx);  /* turn off this plane's bit */
+         /* TODO: this should really do proper guardband clipping,
+          * currently just throw out infs/nans.
+          */
+         if (util_is_inf_or_nan(header->v[0]->clip[0]) ||
+             util_is_inf_or_nan(header->v[0]->clip[1]))
+            return;
+      }
+      stage->next->point(stage->next, header);
+   }
 }
 
 
@@ -636,7 +650,7 @@ static void
 clip_first_point( struct draw_stage *stage,
                   struct prim_header *header )
 {
-   stage->point = stage->draw->clip_points_xy ? clip_point : clip_point_no_xy;
+   stage->point = stage->draw->guard_band_points_xy ? clip_point_guard_xy : clip_point;
    stage->point(stage, header);
 }
 
@@ -662,7 +676,7 @@ clip_line( struct draw_stage *stage,
 
 static void
 clip_tri( struct draw_stage *stage,
-         struct prim_header *header )
+          struct prim_header *header )
 {
    unsigned clipmask = (header->v[0]->clipmask | 
                         header->v[1]->clipmask | 
index bbc22dc091e63b683f25cdba956b05228984c3b6..801d00909080021bb10b20ea9f2af1dc5cf5ccb6 100644 (file)
@@ -232,7 +232,7 @@ struct draw_context
    boolean clip_z;
    boolean clip_user;
    boolean guard_band_xy;
-   boolean clip_points_xy;
+   boolean guard_band_points_xy;
 
    boolean force_passthrough; /**< never clip or shade */
 
index 2a2e13b84588d3998910933fe0e0ffbed9ad07f3..a3dc8bed6fc5c8c9b2c3394c13bdd4d08ea2784a 100644 (file)
@@ -60,7 +60,7 @@ struct fetch_pipeline_middle_end {
  */
 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
                                     unsigned prim,
-                                   unsigned opt,
+                                    unsigned opt,
                                     unsigned *max_vertices )
 {
    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
@@ -72,8 +72,10 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
 
    const unsigned gs_out_prim = (gs ? gs->output_primitive :
                                  u_assembled_prim(prim));
-   unsigned nr = MAX2( vs->info.num_inputs,
-                      draw_total_vs_outputs(draw) );
+   unsigned nr = MAX2(vs->info.num_inputs,
+                      draw_total_vs_outputs(draw));
+   unsigned point_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
+                         gs_out_prim == PIPE_PRIM_POINTS;
 
    if (gs) {
       nr = MAX2(nr, gs->info.num_outputs + 1);
@@ -97,18 +99,17 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
     */
    fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
 
-   
 
    draw_pt_fetch_prepare( fpme->fetch, 
                           vs->info.num_inputs,
                           fpme->vertex_size,
                           instance_id_index );
    draw_pt_post_vs_prepare( fpme->post_vs,
-                            gs_out_prim == PIPE_PRIM_POINTS ?
-                                           draw->clip_points_xy : draw->clip_xy,
+                            draw->clip_xy,
                             draw->clip_z,
                             draw->clip_user,
-                            draw->guard_band_xy,
+                            point_clip ? draw->guard_band_points_xy :
+                                         draw->guard_band_xy,
                             draw->identity_viewport,
                             draw->rasterizer->clip_halfz,
                             (draw->vs.edgeflag_output ? TRUE : FALSE) );
index 4789cda931fbe88e1fe1d771dc4e7d356f19c4c2..65cb26dadb56f58170cb285c6962e4898ab425cd 100644 (file)
@@ -143,6 +143,8 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
       u_assembled_prim(in_prim);
    const unsigned nr = MAX2(vs->info.num_inputs,
                             draw_total_vs_outputs(draw));
+   unsigned point_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
+                         out_prim == PIPE_PRIM_POINTS;
 
    fpme->input_prim = in_prim;
    fpme->opt = opt;
@@ -155,11 +157,11 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
 
 
    draw_pt_post_vs_prepare( fpme->post_vs,
-                            out_prim == PIPE_PRIM_POINTS ?
-                                        draw->clip_points_xy : draw->clip_xy,
+                            draw->clip_xy,
                             draw->clip_z,
                             draw->clip_user,
-                            draw->guard_band_xy,
+                            point_clip ? draw->guard_band_points_xy :
+                                         draw->guard_band_xy,
                             draw->identity_viewport,
                             draw->rasterizer->clip_halfz,
                             (draw->vs.edgeflag_output ? TRUE : FALSE) );