Mesa (master): llvmpipe: native point rasterization

Keith Whitwell keithw at kemper.freedesktop.org
Fri Aug 27 12:14:08 UTC 2010


Module: Mesa
Branch: master
Commit: 57d84d9ca4a645ca326b66ff3b82bee0db18ac97
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=57d84d9ca4a645ca326b66ff3b82bee0db18ac97

Author: Hui Qi Tay <hqtay at vmware.com>
Date:   Fri Aug 27 10:37:09 2010 +0100

llvmpipe: native point rasterization

Conflicts:

	src/gallium/drivers/llvmpipe/lp_setup_context.h
	src/gallium/drivers/llvmpipe/lp_setup_line.c
	src/gallium/drivers/llvmpipe/lp_setup_tri.c

---

 src/gallium/drivers/llvmpipe/lp_context.c          |    6 +-
 src/gallium/drivers/llvmpipe/lp_context.h          |    3 +
 src/gallium/drivers/llvmpipe/lp_setup.c            |   15 ++
 src/gallium/drivers/llvmpipe/lp_setup.h            |    4 +
 src/gallium/drivers/llvmpipe/lp_setup_context.h    |    2 +
 src/gallium/drivers/llvmpipe/lp_setup_point.c      |  225 +++++++++++++++++++-
 src/gallium/drivers/llvmpipe/lp_state_derived.c    |   10 +
 src/gallium/drivers/llvmpipe/lp_state_rasterizer.c |    2 +
 8 files changed, 262 insertions(+), 5 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_context.c b/src/gallium/drivers/llvmpipe/lp_context.c
index a6873ab..c52b17b 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.c
+++ b/src/gallium/drivers/llvmpipe/lp_context.c
@@ -155,8 +155,10 @@ llvmpipe_create_context( struct pipe_screen *screen, void *priv )
    draw_install_aapoint_stage(llvmpipe->draw, &llvmpipe->pipe);
    draw_install_pstipple_stage(llvmpipe->draw, &llvmpipe->pipe);
 
-   /* convert points and lines into triangles: */
-   draw_wide_point_threshold(llvmpipe->draw, 0.0);
+   /* convert points and lines into triangles: 
+    * (otherwise, draw points and lines natively)
+    */
+   draw_wide_point_threshold(llvmpipe->draw, 10000.0);
    draw_wide_line_threshold(llvmpipe->draw, 10000.0);
 
 #if USE_DRAW_STAGE_PSTIPPLE
diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h
index 50f9091..34fa20e 100644
--- a/src/gallium/drivers/llvmpipe/lp_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_context.h
@@ -101,6 +101,9 @@ struct llvmpipe_context {
    
    /** Vertex format */
    struct vertex_info vertex_info;
+   
+   /** Which vertex shader output slot contains point size */
+   int psize_slot;
 
    /** Fragment shader input interpolation info */
    unsigned num_inputs;
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c
index 4c82756..778bfb4 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup.c
@@ -494,6 +494,15 @@ lp_setup_set_line_state( struct lp_setup_context *setup,
    setup->line_width = line_width;
 }
 
+void 
+lp_setup_set_point_state( struct lp_setup_context *setup,
+                          float point_size)
+{
+   LP_DBG(DEBUG_SETUP, "%s\n", __FUNCTION__);
+
+   setup->point_size = point_size;
+}
+
 void
 lp_setup_set_fs_inputs( struct lp_setup_context *setup,
                         const struct lp_shader_input *input,
@@ -733,6 +742,12 @@ lp_setup_update_state( struct lp_setup_context *setup )
     */
    {
       struct llvmpipe_context *lp = llvmpipe_context(scene->pipe);
+
+      /* Will probably need to move this somewhere else, just need  
+       * to know about vertex shader point size attribute.
+       */
+      setup->psize = lp->psize_slot;
+
       if (lp->dirty) {
          llvmpipe_update_derived(lp);
       }
diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h
index 693550b..6b041e7 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup.h
@@ -104,6 +104,10 @@ void
 lp_setup_set_line_state( struct lp_setup_context *setup,
                          float line_width);
 
+void 
+lp_setup_set_point_state( struct lp_setup_context *setup,
+                          float point_size);
+
 void
 lp_setup_set_fs_inputs( struct lp_setup_context *setup,
                         const struct lp_shader_input *interp,
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h
index 97919c0..7d486af 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_context.h
+++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h
@@ -92,6 +92,8 @@ struct lp_setup_context
    unsigned cullmode;
    float pixel_offset;
    float line_width;
+   float point_size;
+   float psize;
 
    struct pipe_framebuffer_state fb;
    struct u_rect framebuffer;
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c
index 709c3e2..07a28fc 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_point.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2010, VMware Inc.
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -18,7 +18,7 @@
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -30,10 +30,229 @@
  */
 
 #include "lp_setup_context.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+#include "lp_perf.h"
+#include "lp_setup_context.h"
+#include "lp_rast.h"
+#include "lp_state_fs.h"
+
+#define NUM_CHANNELS 4
+
+struct point_info {
+   /* x,y deltas */
+   int dy01, dy12;
+   int dx01, dx12;
+
+   const float (*v0)[4];
+};   
+
+
+/**
+ * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
+ */
+static void constant_coef( struct lp_setup_context *setup,
+                           struct lp_rast_triangle *point,
+                           unsigned slot,
+                           const float value,
+                           unsigned i )
+{
+   point->inputs.a0[slot][i] = value;
+   point->inputs.dadx[slot][i] = 0.0f;
+   point->inputs.dady[slot][i] = 0.0f;
+}
+
+/**
+ * Special coefficient setup for gl_FragCoord.
+ * X and Y are trivial
+ * Z and W are copied from position_coef which should have already been computed.
+ * We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
+ */
+static void
+setup_point_fragcoord_coef(struct lp_setup_context *setup,
+                           struct lp_rast_triangle *point,
+                           const struct point_info *info,
+                           unsigned slot,
+                           unsigned usage_mask)
+{
+   /*X*/
+   if (usage_mask & TGSI_WRITEMASK_X) {
+      point->inputs.a0[slot][0] = 0.0;
+      point->inputs.dadx[slot][0] = 1.0;
+      point->inputs.dady[slot][0] = 0.0;
+   }
+
+   /*Y*/
+   if (usage_mask & TGSI_WRITEMASK_Y) {
+      point->inputs.a0[slot][1] = 0.0;
+      point->inputs.dadx[slot][1] = 0.0;
+      point->inputs.dady[slot][1] = 1.0;
+   }
+
+   /*Z*/
+   if (usage_mask & TGSI_WRITEMASK_Z) {
+      constant_coef(setup, point, slot, info->v0[0][2], 2);
+   }
+
+   /*W*/
+   if (usage_mask & TGSI_WRITEMASK_W) {
+      constant_coef(setup, point, slot, info->v0[0][3], 3);
+   }
+}
+
+/**
+ * Compute the point->coef[] array dadx, dady, a0 values.
+ */
+static void   
+setup_point_coefficients( struct lp_setup_context *setup,
+                          struct lp_rast_triangle *point,
+                          const struct point_info *info)
+{
+   unsigned fragcoord_usage_mask = TGSI_WRITEMASK_XYZ;
+   unsigned slot;
+
+   /* setup interpolation for all the remaining attributes:
+    */
+   for (slot = 0; slot < setup->fs.nr_inputs; slot++) {
+      unsigned vert_attr = setup->fs.input[slot].src_index;
+      unsigned usage_mask = setup->fs.input[slot].usage_mask;
+      unsigned i;
+      
+      switch (setup->fs.input[slot].interp) {
+      case LP_INTERP_POSITION:
+         /*
+          * The generated pixel interpolators will pick up the coeffs from
+          * slot 0, so all need to ensure that the usage mask is covers all
+          * usages.
+          */
+         fragcoord_usage_mask |= usage_mask;
+         break;
+
+      default:
+         for (i = 0; i < NUM_CHANNELS; i++) {
+            if (usage_mask & (1 << i))
+               constant_coef(setup, point, slot+1, info->v0[vert_attr][i], i);
+         }
+      }
+   }
+
+   /* The internal position input is in slot zero:
+    */
+   setup_point_fragcoord_coef(setup, point, info, 0,
+                              fragcoord_usage_mask);
+}
+
+static INLINE int
+subpixel_snap(float a)
+{
+   return util_iround(FIXED_ONE * a);
+}
+
 
 static void lp_setup_point( struct lp_setup_context *setup,
-                       const float (*v0)[4] )
+                            const float (*v0)[4] )
 {
+   /* x/y positions in fixed point */
+   const int sizeAttr = setup->psize;
+   const float size
+      = sizeAttr > 0 ? v0[sizeAttr][0]
+      : setup->point_size;
+   const float half_width = 0.5F * size;
+ 
+   const int x0 = subpixel_snap(v0[0][0] - half_width - setup->pixel_offset);
+   const int x1 = subpixel_snap(v0[0][0] - half_width - setup->pixel_offset);
+   const int x2 = subpixel_snap(v0[0][0] + half_width - setup->pixel_offset);
+   const int y0 = subpixel_snap(v0[0][1] - half_width - setup->pixel_offset);
+   const int y1 = subpixel_snap(v0[0][1] + half_width - setup->pixel_offset);
+   const int y2 = subpixel_snap(v0[0][1] + half_width - setup->pixel_offset);
+   struct lp_scene *scene = lp_setup_get_current_scene(setup);
+   struct lp_rast_triangle *point;
+   unsigned bytes;
+   struct u_rect bbox;
+   unsigned nr_planes = 4;
+   struct point_info info;
+
+
+   /* Bounding rectangle (in pixels) */
+   {
+      /* Yes this is necessary to accurately calculate bounding boxes
+       * with the two fill-conventions we support.  GL (normally) ends
+       * up needing a bottom-left fill convention, which requires
+       * slightly different rounding.
+       */
+      int adj = (setup->pixel_offset != 0) ? 1 : 0;
+
+      bbox.x0 = (MIN3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER;
+      bbox.x1 = (MAX3(x0, x1, x2) + (FIXED_ONE-1)) >> FIXED_ORDER;
+      bbox.y0 = (MIN3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
+      bbox.y1 = (MAX3(y0, y1, y2) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
+
+      /* Inclusive coordinates:
+       */
+      bbox.x1--;
+      bbox.y1--;
+   }
+   
+   if (!u_rect_test_intersection(&setup->draw_region, &bbox)) {
+      if (0) debug_printf("offscreen\n");
+      LP_COUNT(nr_culled_tris);
+      return;
+   }
+
+   u_rect_find_intersection(&setup->draw_region, &bbox);
+
+   point = lp_setup_alloc_triangle(scene,
+                                   setup->fs.nr_inputs,
+                                   nr_planes,
+                                   &bytes);
+   if (!point)
+      return;
+
+#ifdef DEBUG
+   point->v[0][0] = v0[0][0];
+   point->v[0][1] = v0[0][1];
+#endif
+
+   info.v0 = v0;
+   info.dx01 = x1 - x0;
+   info.dx12 = x2 - x1;
+   info.dy01 = y1 - y0;
+   info.dy12 = y2 - y1;
+   
+   /* Setup parameter interpolants:
+    */
+   setup_point_coefficients(setup, point, &info);
+
+   point->inputs.facing = 1.0F;
+   point->inputs.state = setup->fs.stored;
+
+   {
+      point->plane[0].dcdx = -1;
+      point->plane[0].dcdy = 0;
+      point->plane[0].c = 1-bbox.x0;
+      point->plane[0].ei = 0;
+      point->plane[0].eo = 1;
+
+      point->plane[1].dcdx = 1;
+      point->plane[1].dcdy = 0;
+      point->plane[1].c = bbox.x1+1;
+      point->plane[1].ei = -1;
+      point->plane[1].eo = 0;
+
+      point->plane[2].dcdx = 0;
+      point->plane[2].dcdy = 1;
+      point->plane[2].c = 1-bbox.y0;
+      point->plane[2].ei = 0;
+      point->plane[2].eo = 1;
+
+      point->plane[3].dcdx = 0;
+      point->plane[3].dcdy = -1;
+      point->plane[3].c = bbox.y1+1;
+      point->plane[3].ei = -1;
+      point->plane[3].eo = 0;
+   }
+
+   lp_setup_bin_triangle(setup, point, &bbox, nr_planes);
 }
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c
index 77bec46..9ef9983 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_derived.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c
@@ -125,6 +125,16 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe)
       inputs[i].src_index = vinfo->num_attribs;
       draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_PERSPECTIVE, vs_index);
    }
+
+   /* Figure out if we need pointsize as well.
+    */
+   llvmpipe->psize_slot = draw_find_shader_output(llvmpipe->draw,
+                                                  TGSI_SEMANTIC_PSIZE, 0);
+   if (llvmpipe->psize_slot > 0) {
+      draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT,
+                            llvmpipe->psize_slot);
+   }
+
    llvmpipe->num_inputs = lpfs->info.num_inputs;
 
    draw_compute_vertex_size(vinfo);
diff --git a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
index 67b985a..f845a0c 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
@@ -75,6 +75,8 @@ llvmpipe_bind_rasterizer_state(struct pipe_context *pipe, void *handle)
                    llvmpipe->rasterizer->flatshade_first);
       lp_setup_set_line_state( llvmpipe->setup,
                    llvmpipe->rasterizer->line_width);
+      lp_setup_set_point_state( llvmpipe->setup,
+                   llvmpipe->rasterizer->point_size);
    }
 
    llvmpipe->dirty |= LP_NEW_RASTERIZER;




More information about the mesa-commit mailing list