draw: add passthrough path to the pipeline
authorKeith Whitwell <keith@tungstengraphics.com>
Thu, 3 Apr 2008 11:21:30 +0000 (12:21 +0100)
committerKeith Whitwell <keith@tungstengraphics.com>
Thu, 3 Apr 2008 11:21:30 +0000 (12:21 +0100)
This handles the case where bypass_vs is set, but vertices need to go
through the pipeline for some reason - eg unfilled polygon mode.

Demonstrates how to drive the pipeline from inside one of these things.

src/gallium/auxiliary/draw/Makefile
src/gallium/auxiliary/draw/SConscript
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_pt.c
src/gallium/auxiliary/draw/draw_pt.h
src/gallium/auxiliary/draw/draw_pt_fetch_emit.c
src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c [new file with mode: 0644]
src/gallium/auxiliary/draw/draw_vertex_fetch.c

index a0db2e4555e76b6120c20af72d3ed14b333eaaf7..b28e516396e1b86dce31f4ba845f4289c639041b 100644 (file)
@@ -18,6 +18,7 @@ C_SOURCES = \
        draw_pt.c \
        draw_pt_vcache.c \
        draw_pt_fetch_emit.c \
+       draw_pt_fetch_pipeline.c \
        draw_pt_elts.c \
        draw_prim.c \
        draw_pstipple.c \
index 981225a8c2cdfebbbcbeedcb5d9698841612165e..9ca4197441286452cfd9283aef7a48c78e4134dc 100644 (file)
@@ -17,6 +17,7 @@ draw = env.ConvenienceLibrary(
                'draw_pt.c',
                'draw_pt_vcache.c',
                'draw_pt_fetch_emit.c',
+               'draw_pt_fetch_pipeline.c',
                'draw_pt_elts.c',
                'draw_prim.c',
                'draw_pstipple.c',
index 9a9b25297f1d91cf1d7e9afbf4f3318120f32012..0c9f9c2e0365fa46e6ab30a1936ea51d632a4dfb 100644 (file)
@@ -160,6 +160,11 @@ struct draw_vertex_shader {
 /* Internal function for vertex fetch.
  */
 typedef void (*fetch_func)(const void *ptr, float *attrib);
+
+fetch_func draw_get_fetch_func( enum pipe_format format );
+
+
+
 typedef void (*full_fetch_func)( struct draw_context *draw,
                                 struct tgsi_exec_machine *machine,
                                 const unsigned *elts,
@@ -211,6 +216,7 @@ struct draw_context
 
       struct {
          struct draw_pt_middle_end *fetch_emit;
+         struct draw_pt_middle_end *fetch_pipeline;
          struct draw_pt_middle_end *fetch_shade_emit;
          struct draw_pt_middle_end *fetch_shade_cliptest_pipeline_or_emit;
       } middle;
index c3baf5b7da7be27e29bcf9b27b884c53b09c34f0..f59fb86f781d4f8c061d1ced56aadfc23e50a528 100644 (file)
@@ -73,7 +73,6 @@ draw_pt_arrays(struct draw_context *draw,
     */
 
 
-#if 0
    if (!cliptest && !pipeline && !shading) {
       /* This is the 'passthrough' path:
        */
@@ -81,6 +80,14 @@ draw_pt_arrays(struct draw_context *draw,
        */
       middle = draw->pt.middle.fetch_emit;
    }
+   else if (!cliptest && !shading) {
+      /* This is the 'passthrough' path targetting the pipeline backend.
+       */
+      /* Fetch user verts, emit pipeline verts, run pipeline:
+       */
+      middle = draw->pt.middle.fetch_pipeline;
+   }
+#if 0
    else if (!cliptest && !pipeline) {
       /* Fetch user verts, run vertex shader, emit hw verts:
        */
@@ -117,10 +124,9 @@ draw_pt_arrays(struct draw_context *draw,
       middle = draw->pt.middle.fetch_shade_cliptest_pipeline;
    }
 #else
-   if (cliptest || pipeline || shading)
+   else {
       return FALSE;
-
-   middle = draw->pt.middle.fetch_emit;
+   }
 #endif
 
 
@@ -190,6 +196,10 @@ boolean draw_pt_init( struct draw_context *draw )
    if (!draw->pt.middle.fetch_emit)
       return FALSE;
 
+   draw->pt.middle.fetch_pipeline = draw_pt_fetch_pipeline( draw );
+   if (!draw->pt.middle.fetch_pipeline)
+      return FALSE;
+
    draw->pt.front.vcache = draw_pt_vcache( draw );
    if (!draw->pt.front.vcache)
       return FALSE;
@@ -205,6 +215,11 @@ void draw_pt_destroy( struct draw_context *draw )
       draw->pt.middle.fetch_emit = NULL;
    }
 
+   if (draw->pt.middle.fetch_pipeline) {
+      draw->pt.middle.fetch_pipeline->destroy( draw->pt.middle.fetch_pipeline );
+      draw->pt.middle.fetch_pipeline = NULL;
+   }
+
    if (draw->pt.front.vcache) {
       draw->pt.front.vcache->destroy( draw->pt.front.vcache );
       draw->pt.front.vcache = NULL;
index 428b1e0e6bcba5416e2efdab47da3e097a14ea1c..800072c5115ea1218aa764a0469cd584facbf228 100644 (file)
@@ -112,6 +112,7 @@ const void *draw_pt_elt_ptr( struct draw_context *draw,
  */
 struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw );
 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw );
+struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw );
 
 
 
index f863a46d9cc26591c470c8d30716795c85702d06..39f0b40838f19eab11253631882c8607ff7f87f1 100644 (file)
@@ -85,45 +85,6 @@ struct fetch_emit_middle_end {
 };
 
 
-static void fetch_B8G8R8A8_UNORM( const void *from,
-                                  float *attrib )
-{
-   ubyte *ub = (ubyte *) from;
-   attrib[2] = UBYTE_TO_FLOAT(ub[0]);
-   attrib[1] = UBYTE_TO_FLOAT(ub[1]);
-   attrib[0] = UBYTE_TO_FLOAT(ub[2]);
-   attrib[3] = UBYTE_TO_FLOAT(ub[3]);
-}
-
-static void fetch_R32G32B32A32_FLOAT( const void *from,
-                                  float *attrib )
-{
-   float *f = (float *) from;
-   attrib[0] = f[0];
-   attrib[1] = f[1];
-   attrib[2] = f[2];
-   attrib[3] = f[3];
-}
-
-static void fetch_R32G32B32_FLOAT( const void *from,
-                                   float *attrib )
-{
-   float *f = (float *) from;
-   attrib[0] = f[0];
-   attrib[1] = f[1];
-   attrib[2] = f[2];
-   attrib[3] = 1.0;
-}
-
-static void fetch_R32G32_FLOAT( const void *from,
-                                float *attrib )
-{
-   float *f = (float *) from;
-   attrib[0] = f[0];
-   attrib[1] = f[1];
-   attrib[2] = 0.0;
-   attrib[3] = 1.0;
-}
 
 static void fetch_R32_FLOAT( const void *from,
                              float *attrib )
@@ -235,28 +196,9 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
 
       feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch;
          
-      switch (draw->vertex_element[src_element].src_format) {
-      case PIPE_FORMAT_B8G8R8A8_UNORM:
-         feme->fetch[i].fetch = fetch_B8G8R8A8_UNORM;
-         break;
-      case PIPE_FORMAT_R32G32B32A32_FLOAT:
-         feme->fetch[i].fetch = fetch_R32G32B32A32_FLOAT;
-         break;
-      case PIPE_FORMAT_R32G32B32_FLOAT:
-         feme->fetch[i].fetch = fetch_R32G32B32_FLOAT;
-         break;
-      case PIPE_FORMAT_R32G32_FLOAT:
-         feme->fetch[i].fetch = fetch_R32G32_FLOAT;
-         break;
-      case PIPE_FORMAT_R32_FLOAT:
-         feme->fetch[i].fetch = fetch_R32_FLOAT;
-         break;
-      default:
-         assert(0);
-         feme->fetch[i].fetch = NULL;
-         break;
-      }
-         
+      feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format);
+
+
       switch (vinfo->emit[i]) {
       case EMIT_4F:
          feme->fetch[i].emit = emit_R32G32B32A32_FLOAT;
diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c
new file mode 100644 (file)
index 0000000..94e7d01
--- /dev/null
@@ -0,0 +1,391 @@
+/**************************************************************************
+ * 
+ * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ * 
+ * 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
+ * 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.
+ * 
+ **************************************************************************/
+
+ /*
+  * Authors:
+  *   Keith Whitwell <keith@tungstengraphics.com>
+  */
+
+#include "pipe/p_util.h"
+#include "draw/draw_context.h"
+#include "draw/draw_private.h"
+#include "draw/draw_vertex.h"
+#include "draw/draw_pt.h"
+
+/* The simplest 'middle end' in the new vertex code.  
+ * 
+ * The responsibilities of a middle end are to:
+ *  - perform vertex fetch using
+ *       - draw vertex element/buffer state
+ *       - a list of fetch indices we received as an input
+ *  - run the vertex shader
+ *  - cliptest, 
+ *  - clip coord calculation 
+ *  - viewport transformation
+ *  - if necessary, run the primitive pipeline, passing it:
+ *       - a linear array of vertex_header vertices constructed here
+ *       - a set of draw indices we received as an input
+ *  - otherwise, drive the hw backend,
+ *       - allocate space for hardware format vertices
+ *       - translate the vertex-shader output vertices to hw format
+ *       - calling the backend draw functions.
+ *
+ * For convenience, we provide a helper function to drive the hardware
+ * backend given similar inputs to those required to run the pipeline.
+ *
+ * In the case of passthrough mode, many of these actions are disabled
+ * or noops, so we end up doing:
+ *
+ *  - perform vertex fetch
+ *  - drive the hw backend
+ *
+ * IE, basically just vertex fetch to post-vs-format vertices,
+ * followed by a call to the backend helper function.
+ */
+
+
+struct fetch_pipeline_middle_end {
+   struct draw_pt_middle_end base;
+   struct draw_context *draw;
+
+   struct {
+      const ubyte *ptr;
+      unsigned pitch;
+      void (*fetch)( const void *from, float *attrib);
+      void (*emit)( const float *attrib, float **out );
+   } fetch[PIPE_MAX_ATTRIBS];
+   
+   unsigned nr_fetch;
+   unsigned pipeline_vertex_size;
+   unsigned prim;
+};
+
+
+static void fetch_NULL( const void *from,
+                        float *attrib )
+{
+}
+
+
+
+static void emit_R32_FLOAT( const float *attrib,
+                            float **out )
+{
+   (*out)[0] = attrib[0];
+   (*out) += 1;
+}
+
+static void emit_R32G32_FLOAT( const float *attrib,
+                               float **out )
+{
+   (*out)[0] = attrib[0];
+   (*out)[1] = attrib[1];
+   (*out) += 2;
+}
+
+static void emit_R32G32B32_FLOAT( const float *attrib,
+                                  float **out )
+{
+   (*out)[0] = attrib[0];
+   (*out)[1] = attrib[1];
+   (*out)[2] = attrib[2];
+   (*out) += 3;
+}
+
+static void emit_R32G32B32A32_FLOAT( const float *attrib,
+                                     float **out )
+{
+   (*out)[0] = attrib[0];
+   (*out)[1] = attrib[1];
+   (*out)[2] = attrib[2];
+   (*out)[3] = attrib[3];
+   (*out) += 4;
+}
+
+static void emit_header( const float *attrib,
+                         float **out )
+{
+   (*out)[0] = 0;
+   (*out)[1] = 0;
+   (*out)[2] = 0;
+   (*out)[3] = 0;
+   (*out)[3] = 1;
+   (*out) += 5;
+}
+
+/**
+ * General-purpose fetch from user's vertex arrays, emit to driver's
+ * vertex buffer.
+ *
+ * XXX this is totally temporary.
+ */
+static void
+fetch_store_general( struct fetch_pipeline_middle_end *fpme,
+                     void *out_ptr,
+                     const unsigned *fetch_elts,
+                     unsigned count )
+{
+   float *out = (float *)out_ptr;
+   uint i, j;
+
+   for (i = 0; i < count; i++) {
+      unsigned elt = fetch_elts[i];
+      
+      for (j = 0; j < fpme->nr_fetch; j++) {
+         float attrib[4];
+         const ubyte *from = (fpme->fetch[j].ptr +
+                              fpme->fetch[j].pitch * elt);
+         
+         fpme->fetch[j].fetch( from, attrib );
+         fpme->fetch[j].emit( attrib, &out );
+      }
+   }
+}
+
+
+/* We aren't running a vertex shader, but are running the pipeline.
+ * That means the vertices we need to build look like:
+ *
+ * dw0: vertex header (zero?)
+ * dw1: clip coord 0
+ * dw2: clip coord 1
+ * dw3: clip coord 2
+ * dw4: clip coord 4
+ * dw5: screen coord 0
+ * dw6: screen coord 0
+ * dw7: screen coord 0
+ * dw8: screen coord 0
+ * dw9: other attribs...
+ *
+ */
+static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
+                                    unsigned prim )
+{
+   static const float zero = 0;
+   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
+   struct draw_context *draw = fpme->draw;
+   unsigned i, nr = 0;
+
+   fpme->prim = prim;
+
+   /* Emit the vertex header and empty clipspace coord field:
+    */
+   {
+      fpme->fetch[nr].ptr = NULL;
+      fpme->fetch[nr].pitch = 0;
+      fpme->fetch[nr].fetch = fetch_NULL;
+      fpme->fetch[nr].emit = emit_header;
+      nr++;
+   }
+   
+
+   /* Need to look at vertex shader inputs (we know it is a
+    * passthrough shader, so these define the outputs too).  If we
+    * were running a shader, we'd still be looking at the inputs at
+    * this point.
+    */
+   for (i = 0; i < draw->vertex_shader->info.num_inputs; i++) {
+      unsigned buf = draw->vertex_element[i].vertex_buffer_index;
+      enum pipe_format format  = draw->vertex_element[i].src_format;
+
+      fpme->fetch[nr].ptr = ((const ubyte *) draw->user.vbuffer[buf] + 
+                            draw->vertex_buffer[buf].buffer_offset + 
+                            draw->vertex_element[i].src_offset);
+
+      fpme->fetch[nr].pitch = draw->vertex_buffer[buf].pitch;
+      fpme->fetch[nr].fetch = draw_get_fetch_func( format );
+
+      /* Always do this -- somewhat redundant...
+       */
+      fpme->fetch[nr].emit = emit_R32G32B32A32_FLOAT;
+      nr++;
+   }
+
+   fpme->nr_fetch = nr;
+   fpme->pipeline_vertex_size = (5 + (nr-1) * 4) * sizeof(float);
+}
+
+
+
+/**
+ * Add a point to the primitive queue.
+ * \param i0  index into user's vertex arrays
+ */
+static void do_point( struct draw_context *draw,
+                     const char *v0 )
+{
+   struct prim_header prim;
+   
+   prim.reset_line_stipple = 0;
+   prim.edgeflags = 1;
+   prim.pad = 0;
+   prim.v[0] = (struct vertex_header *)v0;
+
+   draw->pipeline.first->point( draw->pipeline.first, &prim );
+}
+
+
+/**
+ * Add a line to the primitive queue.
+ * \param i0  index into user's vertex arrays
+ * \param i1  index into user's vertex arrays
+ */
+static void do_line( struct draw_context *draw,
+                    const char *v0,
+                    const char *v1 )
+{
+   struct prim_header prim;
+   
+   prim.reset_line_stipple = 1; /* fixme */
+   prim.edgeflags = 1;
+   prim.pad = 0;
+   prim.v[0] = (struct vertex_header *)v0;
+   prim.v[1] = (struct vertex_header *)v1;
+
+   draw->pipeline.first->line( draw->pipeline.first, &prim );
+}
+
+/**
+ * Add a triangle to the primitive queue.
+ */
+static void do_triangle( struct draw_context *draw,
+                        char *v0,
+                        char *v1,
+                        char *v2 )
+{
+   struct prim_header prim;
+   
+//   _mesa_printf("tri %d %d %d\n", i0, i1, i2);
+   prim.reset_line_stipple = 1;
+   prim.edgeflags = ~0;
+   prim.pad = 0;
+   prim.v[0] = (struct vertex_header *)v0;
+   prim.v[1] = (struct vertex_header *)v1;
+   prim.v[2] = (struct vertex_header *)v2;
+
+   draw->pipeline.first->tri( draw->pipeline.first, &prim );
+}
+
+
+static void run_pipeline( struct fetch_pipeline_middle_end *fpme,
+                          char *verts,
+                          const ushort *elts,
+                          unsigned count )
+{
+   struct draw_context *draw = fpme->draw;
+   unsigned stride = fpme->pipeline_vertex_size;
+   unsigned i;
+   
+   switch (fpme->prim) {
+   case PIPE_PRIM_POINTS:
+      for (i = 0; i < count; i++) 
+         do_point( draw, 
+                   verts + stride * elts[i] );
+      break;
+   case PIPE_PRIM_LINES:
+      for (i = 0; i+1 < count; i += 2) 
+         do_line( draw, 
+                  verts + stride * elts[i+0],
+                  verts + stride * elts[i+1]);
+      break;
+   case PIPE_PRIM_TRIANGLES:
+      for (i = 0; i+2 < count; i += 3)
+         do_triangle( draw, 
+                      verts + stride * elts[i+0],
+                      verts + stride * elts[i+1],
+                      verts + stride * elts[i+2]);
+      break;
+   }
+}
+
+
+
+
+static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
+                            const unsigned *fetch_elts,
+                            unsigned fetch_count,
+                            const ushort *draw_elts,
+                            unsigned draw_count )
+{
+   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
+   struct draw_context *draw = fpme->draw;
+   char *pipeline_verts;
+   
+   pipeline_verts = MALLOC( fpme->pipeline_vertex_size * 
+                            fetch_count );
+   if (!pipeline_verts) {
+      assert(0);
+      return;
+   }
+         
+                                       
+   /* Single routine to fetch vertices and emit pipeline verts.
+    */
+   fetch_store_general( fpme, 
+                        pipeline_verts,
+                        fetch_elts,
+                        fetch_count );
+
+   
+   run_pipeline( fpme,
+                 pipeline_verts,
+                 draw_elts,
+                 draw_count );
+                 
+
+   /* Done -- that was easy, wasn't it: 
+    */
+   FREE( pipeline_verts );
+}
+
+
+
+static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
+{
+   /* nothing to do */
+}
+
+static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
+{
+   FREE(middle);
+}
+
+
+struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw )
+{
+   struct fetch_pipeline_middle_end *fetch_pipeline = CALLOC_STRUCT( fetch_pipeline_middle_end );
+   fetch_pipeline->base.prepare = fetch_pipeline_prepare;
+   fetch_pipeline->base.run     = fetch_pipeline_run;
+   fetch_pipeline->base.finish  = fetch_pipeline_finish;
+   fetch_pipeline->base.destroy = fetch_pipeline_destroy;
+
+   fetch_pipeline->draw = draw;
+     
+   return &fetch_pipeline->base;
+}
+
index 11f99babf654612dc5e6caf159fdd2d2ca755467..9041041006ec58864da49bad3df1c1da94a1578f 100644 (file)
@@ -166,7 +166,7 @@ fetch_B8G8R8A8_UNORM(const void *ptr, float *attrib)
 }
 
 
-static fetch_func get_fetch_func( enum pipe_format format )
+fetch_func draw_get_fetch_func( enum pipe_format format )
 {
 #if 0
    {
@@ -502,7 +502,7 @@ void draw_update_vertex_fetch( struct draw_context *draw )
                                                       draw->vertex_element[i].src_offset;
 
       draw->vertex_fetch.pitch[i] = draw->vertex_buffer[buf].pitch;
-      draw->vertex_fetch.fetch[i] = get_fetch_func( format );
+      draw->vertex_fetch.fetch[i] = draw_get_fetch_func( format );
    }
 
    draw->vertex_fetch.nr_attrs = nr_attrs;