redo the linear paths
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_emit.c
index d696afa1aacb7934c2b46860a206530d4a57f582..8df4241b82cc42e2133f37b9f5a93ebf46f4ae13 100644 (file)
@@ -36,6 +36,8 @@
 #include "draw/draw_vbuf.h"
 #include "draw/draw_vertex.h"
 #include "draw/draw_pt.h"
+#include "translate/translate.h"
+#include "translate/translate_cache.h"
 
 /* The simplest 'middle end' in the new vertex code.  
  * 
 struct fetch_emit_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 hw_vertex_size;
-};
-
-
-
-static void fetch_R32_FLOAT( const void *from,
-                             float *attrib )
-{
-   float *f = (float *) from;
-   attrib[0] = f[0];
-   attrib[1] = 0.0;
-   attrib[2] = 0.0;
-   attrib[3] = 1.0;
-}
-
-
-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;
-}
+   struct translate *translate;
+   const struct vertex_info *vinfo;
 
+   /* Cache point size somewhere it's address won't change:
+    */
+   float point_size;
 
-/**
- * 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_emit_middle_end *feme,
-                     void *out_ptr,
-                     const unsigned *fetch_elts,
-                     unsigned count )
-{
-   float *out = (float *)out_ptr;
-   uint i, j;
+   struct translate_cache *cache;
+};
 
-   for (i = 0; i < count; i++) {
-      unsigned elt = fetch_elts[i] & ~DRAW_PT_FLAG_MASK;
-      
-      for (j = 0; j < feme->nr_fetch; j++) {
-         float attrib[4];
-         const ubyte *from = (feme->fetch[j].ptr +
-                              feme->fetch[j].pitch * elt);
-         
-         feme->fetch[j].fetch( from, attrib );
-         feme->fetch[j].emit( attrib, &out );
-      }
-   }
-}
 
 
 
@@ -170,8 +95,9 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    struct draw_context *draw = feme->draw;
    const struct vertex_info *vinfo;
-   unsigned i;
+   unsigned i, dst_offset;
    boolean ok;
+   struct translate_key key;
 
 
    ok = draw->render->set_primitive( draw->render, 
@@ -183,54 +109,92 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
    
    /* Must do this after set_primitive() above:
     */
-   vinfo = draw->render->get_vertex_info(draw->render);
-
+   vinfo = feme->vinfo = draw->render->get_vertex_info(draw->render);
+   
+   
 
-   /* This is unique as it transforms straight from API vertex
-    * information to HW vertices.  All other cases go through our
-    * intermediate float[4] format.
+   /* Transform from API vertices to HW vertices, skipping the
+    * pipeline_vertex intermediate step.
     */
-   for (i = 0; i < vinfo->num_attribs; i++) {
-      unsigned src_element = vinfo->src_index[i];
-      unsigned src_buffer = draw->vertex_element[src_element].vertex_buffer_index;
-         
-      feme->fetch[i].ptr = ((const ubyte *)draw->user.vbuffer[src_buffer] + 
-                            draw->vertex_buffer[src_buffer].buffer_offset + 
-                            draw->vertex_element[src_element].src_offset);
+   dst_offset = 0;
+   memset(&key, 0, sizeof(key));
 
-      feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch;
-         
-      feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format);
+   for (i = 0; i < vinfo->num_attribs; i++) {
+      const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->src_index[i]];
 
+      unsigned emit_sz = 0;
+      unsigned input_format = src->src_format;
+      unsigned input_buffer = src->vertex_buffer_index;
+      unsigned input_offset = src->src_offset;
+      unsigned output_format;
 
       switch (vinfo->emit[i]) {
       case EMIT_4F:
-         feme->fetch[i].emit = emit_R32G32B32A32_FLOAT;
+        output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
+        emit_sz = 4 * sizeof(float);
          break;
       case EMIT_3F:
-         feme->fetch[i].emit = emit_R32G32B32_FLOAT;
+        output_format = PIPE_FORMAT_R32G32B32_FLOAT;
+        emit_sz = 3 * sizeof(float);
          break;
       case EMIT_2F:
-         feme->fetch[i].emit = emit_R32G32_FLOAT;
+        output_format = PIPE_FORMAT_R32G32_FLOAT;
+        emit_sz = 2 * sizeof(float);
          break;
       case EMIT_1F:
-         feme->fetch[i].emit = emit_R32_FLOAT;
+        output_format = PIPE_FORMAT_R32_FLOAT;
+        emit_sz = 1 * sizeof(float);
          break;
       case EMIT_1F_PSIZE:
-         feme->fetch[i].ptr = (const ubyte *)&feme->draw->rasterizer->point_size;
-         feme->fetch[i].pitch = 0;
-         feme->fetch[i].fetch = fetch_R32_FLOAT;
-         feme->fetch[i].emit = emit_R32_FLOAT;
+        input_format = PIPE_FORMAT_R32_FLOAT;
+        input_buffer = draw->pt.nr_vertex_buffers;
+        input_offset = 0;
+        output_format = PIPE_FORMAT_R32_FLOAT;
+        emit_sz = 1 * sizeof(float);
          break;
       default:
          assert(0);
-         feme->fetch[i].emit = NULL;
-         break;
+        output_format = PIPE_FORMAT_NONE;
+        emit_sz = 0;
+        continue;
       }
+
+      key.element[i].input_format = input_format;
+      key.element[i].input_buffer = input_buffer;
+      key.element[i].input_offset = input_offset;
+      key.element[i].output_format = output_format;
+      key.element[i].output_offset = dst_offset;
+      
+      dst_offset += emit_sz;
    }
 
-   feme->nr_fetch = vinfo->num_attribs;
-   feme->hw_vertex_size = vinfo->size * 4;
+   key.nr_elements = vinfo->num_attribs;
+   key.output_stride = vinfo->size * 4;
+
+   /* Don't bother with caching at this stage:
+    */
+   if (!feme->translate ||
+       memcmp(&feme->translate->key, &key, sizeof(key)) != 0) 
+   {
+      feme->translate = translate_cache_find(feme->cache,
+                                             &key);
+
+
+      feme->translate->set_buffer(feme->translate, 
+                                 draw->pt.nr_vertex_buffers, 
+                                 &feme->point_size,
+                                 0);
+   }
+   
+   feme->point_size = draw->rasterizer->point_size;
+
+   for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
+      feme->translate->set_buffer(feme->translate, 
+                                  i, 
+                                  ((char *)draw->pt.user.vbuffer[i] + 
+                                   draw->pt.vertex_buffer[i].buffer_offset),
+                                  draw->pt.vertex_buffer[i].pitch );
+   }
 }
 
 
@@ -252,7 +216,7 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
    draw_do_flush( draw, DRAW_FLUSH_BACKEND );
 
    hw_verts = draw->render->allocate_vertices( draw->render,
-                                               (ushort)feme->hw_vertex_size,
+                                               (ushort)feme->translate->key.output_stride,
                                                (ushort)fetch_count );
    if (!hw_verts) {
       assert(0);
@@ -262,10 +226,19 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
                                        
    /* Single routine to fetch vertices and emit HW verts.
     */
-   fetch_store_general( feme, 
-                        hw_verts,
-                        fetch_elts,
-                        fetch_count );
+   feme->translate->run_elts( feme->translate, 
+                             fetch_elts,
+                             fetch_count,
+                             hw_verts );
+
+   if (0) {
+      unsigned i;
+      for (i = 0; i < fetch_count; i++) {
+         debug_printf("\n\nvertex %d:\n", i);
+         draw_dump_emitted_vertex( feme->vinfo, 
+                                   (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
+      }
+   }
 
    /* XXX: Draw arrays path to avoid re-emitting index list again and
     * again.
@@ -278,12 +251,65 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
     */
    draw->render->release_vertices( draw->render, 
                                    hw_verts, 
-                                   feme->hw_vertex_size, 
+                                   feme->translate->key.output_stride, 
                                    fetch_count );
 
 }
 
 
+static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
+                                   unsigned start,
+                                   unsigned count )
+{
+   struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
+   struct draw_context *draw = feme->draw;
+   void *hw_verts;
+
+   /* XXX: need to flush to get prim_vbuf.c to release its allocation??
+    */
+   draw_do_flush( draw, DRAW_FLUSH_BACKEND );
+
+   hw_verts = draw->render->allocate_vertices( draw->render,
+                                               (ushort)feme->translate->key.output_stride,
+                                               (ushort)count );
+   if (!hw_verts) {
+      assert(0);
+      return;
+   }
+
+   /* Single routine to fetch vertices and emit HW verts.
+    */
+   feme->translate->run( feme->translate,
+                         start,
+                         count,
+                         hw_verts );
+
+   if (0) {
+      unsigned i;
+      for (i = 0; i < count; i++) {
+         debug_printf("\n\nvertex %d:\n", i);
+         draw_dump_emitted_vertex( feme->vinfo,
+                                   (const uint8_t *)hw_verts + feme->vinfo->size * 4 * i );
+      }
+   }
+
+   /* XXX: Draw arrays path to avoid re-emitting index list again and
+    * again.
+    */
+   draw->render->draw_arrays( draw->render,
+                              0, /*start*/
+                              count );
+
+   /* Done -- that was easy, wasn't it:
+    */
+   draw->render->release_vertices( draw->render,
+                                   hw_verts,
+                                   feme->translate->key.output_stride,
+                                   count );
+
+}
+
+
 
 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
 {
@@ -292,6 +318,10 @@ static void fetch_emit_finish( struct draw_pt_middle_end *middle )
 
 static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
 {
+   struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
+
+   translate_cache_destroy(feme->cache);
+
    FREE(middle);
 }
 
@@ -299,11 +329,20 @@ static void fetch_emit_destroy( struct draw_pt_middle_end *middle )
 struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
 {
    struct fetch_emit_middle_end *fetch_emit = CALLOC_STRUCT( fetch_emit_middle_end );
-   fetch_emit->base.prepare = fetch_emit_prepare;
-   fetch_emit->base.run     = fetch_emit_run;
-   fetch_emit->base.finish  = fetch_emit_finish;
-   fetch_emit->base.destroy = fetch_emit_destroy;
+   if (fetch_emit == NULL)
+      return NULL;
+
+   fetch_emit->cache = translate_cache_create();
+   if (!fetch_emit->cache) {
+      FREE(fetch_emit);
+      return NULL;
+   }
+
+   fetch_emit->base.prepare    = fetch_emit_prepare;
+   fetch_emit->base.run        = fetch_emit_run;
+   fetch_emit->base.run_linear = fetch_emit_run_linear;
+   fetch_emit->base.finish     = fetch_emit_finish;
+   fetch_emit->base.destroy    = fetch_emit_destroy;
 
    fetch_emit->draw = draw;