Merge remote branch 'origin/master' into nv50-compiler
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_emit.c
index 4ea7d4359ffde05e2a08fa17b1ab48105f014568..e706b7796f82249e451196a61a5494ae208d03f4 100644 (file)
   *   Keith Whitwell <keith@tungstengraphics.com>
   */
 
-#include "pipe/p_util.h"
+#include "util/u_memory.h"
 #include "draw/draw_context.h"
 #include "draw/draw_private.h"
 #include "draw/draw_vbuf.h"
 #include "draw/draw_vertex.h"
 #include "draw/draw_pt.h"
+#include "draw/draw_gs.h"
 #include "translate/translate.h"
 #include "translate/translate_cache.h"
 
@@ -90,7 +91,8 @@ struct fetch_emit_middle_end {
 
 static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
                                 unsigned prim,
-                               unsigned opt )
+                               unsigned opt,
+                                unsigned *max_vertices )
 {
    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    struct draw_context *draw = feme->draw;
@@ -99,9 +101,14 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
    boolean ok;
    struct translate_key key;
 
+   unsigned gs_out_prim = (draw->gs.geometry_shader ? 
+                           draw->gs.geometry_shader->output_primitive :
+                           prim);
+
+
 
    ok = draw->render->set_primitive( draw->render, 
-                                     prim );
+                                     gs_out_prim );
    if (!ok) {
       assert(0);
       return;
@@ -120,7 +127,7 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
    memset(&key, 0, sizeof(key));
 
    for (i = 0; i < vinfo->num_attribs; i++) {
-      const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->src_index[i]];
+      const struct pipe_vertex_element *src = &draw->pt.vertex_element[vinfo->attrib[i].src_index];
 
       unsigned emit_sz = 0;
       unsigned input_format = src->src_format;
@@ -128,40 +135,23 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
       unsigned input_offset = src->src_offset;
       unsigned output_format;
 
-      switch (vinfo->emit[i]) {
-      case EMIT_4F:
-        output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
-        emit_sz = 4 * sizeof(float);
-         break;
-      case EMIT_3F:
-        output_format = PIPE_FORMAT_R32G32B32_FLOAT;
-        emit_sz = 3 * sizeof(float);
-         break;
-      case EMIT_2F:
-        output_format = PIPE_FORMAT_R32G32_FLOAT;
-        emit_sz = 2 * sizeof(float);
-         break;
-      case EMIT_1F:
-        output_format = PIPE_FORMAT_R32_FLOAT;
-        emit_sz = 1 * sizeof(float);
-         break;
-      case EMIT_1F_PSIZE:
+      output_format = draw_translate_vinfo_format(vinfo->attrib[i].emit);
+      emit_sz = draw_translate_vinfo_size(vinfo->attrib[i].emit);
+
+      if (vinfo->attrib[i].emit == EMIT_OMIT)
+        continue;
+
+      if (vinfo->attrib[i].emit == EMIT_1F_PSIZE) {
         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);
-        output_format = PIPE_FORMAT_NONE;
-        emit_sz = 0;
-        continue;
       }
 
+      key.element[i].type = TRANSLATE_ELEMENT_NORMAL;
       key.element[i].input_format = input_format;
       key.element[i].input_buffer = input_buffer;
       key.element[i].input_offset = input_offset;
+      key.element[i].instance_divisor = src->instance_divisor;
       key.element[i].output_format = output_format;
       key.element[i].output_offset = dst_offset;
       
@@ -184,7 +174,8 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
       feme->translate->set_buffer(feme->translate, 
                                  draw->pt.nr_vertex_buffers, 
                                  &feme->point_size,
-                                 0);
+                                 0,
+                                 ~0);
    }
    
    feme->point_size = draw->rasterizer->point_size;
@@ -194,8 +185,12 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
                                   i, 
                                   ((char *)draw->pt.user.vbuffer[i] + 
                                    draw->pt.vertex_buffer[i].buffer_offset),
-                                  draw->pt.vertex_buffer[i].pitch );
+                                  draw->pt.vertex_buffer[i].stride,
+                                  draw->pt.vertex_buffer[i].max_index);
    }
+
+   *max_vertices = (draw->render->max_vertex_buffer_bytes / 
+                    (vinfo->size * 4));
 }
 
 
@@ -206,7 +201,8 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
                             const unsigned *fetch_elts,
                             unsigned fetch_count,
                             const ushort *draw_elts,
-                            unsigned draw_count )
+                            unsigned draw_count,
+                            unsigned prim_flags )
 {
    struct fetch_emit_middle_end *feme = (struct fetch_emit_middle_end *)middle;
    struct draw_context *draw = feme->draw;
@@ -216,9 +212,11 @@ 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->translate->key.output_stride,
-                                               (ushort)fetch_count );
+   draw->render->allocate_vertices( draw->render,
+                                    (ushort)feme->translate->key.output_stride,
+                                    (ushort)fetch_count );
+
+   hw_verts = draw->render->map_vertices( draw->render );
    if (!hw_verts) {
       assert(0);
       return;
@@ -230,6 +228,7 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
    feme->translate->run_elts( feme->translate, 
                              fetch_elts,
                              fetch_count,
+                              draw->instance_id,
                              hw_verts );
 
    if (0) {
@@ -241,23 +240,131 @@ static void fetch_emit_run( struct draw_pt_middle_end *middle,
       }
    }
 
+   draw->render->unmap_vertices( draw->render, 
+                                 0, 
+                                 (ushort)(fetch_count - 1) );
+
    /* XXX: Draw arrays path to avoid re-emitting index list again and
     * again.
     */
-   draw->render->draw( draw->render, 
-                       draw_elts, 
-                       draw_count );
+   draw->render->draw_elements( draw->render, 
+                                draw_elts, 
+                                draw_count );
 
    /* Done -- that was easy, wasn't it: 
     */
-   draw->render->release_vertices( draw->render, 
-                                   hw_verts, 
-                                   feme->translate->key.output_stride, 
-                                   fetch_count );
+   draw->render->release_vertices( draw->render );
 
 }
 
 
+static void fetch_emit_run_linear( struct draw_pt_middle_end *middle,
+                                   unsigned start,
+                                   unsigned count,
+                                   unsigned prim_flags )
+{
+   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 );
+
+   if (!draw->render->allocate_vertices( draw->render,
+                                         (ushort)feme->translate->key.output_stride,
+                                         (ushort)count )) 
+      goto fail;
+
+   hw_verts = draw->render->map_vertices( draw->render );
+   if (!hw_verts) 
+      goto fail;
+
+   /* Single routine to fetch vertices and emit HW verts.
+    */
+   feme->translate->run( feme->translate,
+                         start,
+                         count,
+                         draw->instance_id,
+                         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 );
+      }
+   }
+
+   draw->render->unmap_vertices( draw->render, 0, count - 1 );
+
+   /* XXX: Draw arrays path to avoid re-emitting index list again and
+    * again.
+    */
+   draw->render->draw_arrays( draw->render, 0, count );
+
+   /* Done -- that was easy, wasn't it:
+    */
+   draw->render->release_vertices( draw->render );
+   return;
+
+fail:
+   assert(0);
+   return;
+}
+
+
+static boolean fetch_emit_run_linear_elts( struct draw_pt_middle_end *middle,
+                                        unsigned start,
+                                        unsigned count,
+                                        const ushort *draw_elts,
+                                        unsigned draw_count,
+                                        unsigned prim_flags )
+{
+   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 );
+
+   if (!draw->render->allocate_vertices( draw->render,
+                                         (ushort)feme->translate->key.output_stride,
+                                         (ushort)count ))
+      return FALSE;
+
+   hw_verts = draw->render->map_vertices( draw->render );
+   if (!hw_verts) 
+      return FALSE;
+
+   /* Single routine to fetch vertices and emit HW verts.
+    */
+   feme->translate->run( feme->translate,
+                         start,
+                         count,
+                         draw->instance_id,
+                         hw_verts );
+
+   draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
+
+   /* XXX: Draw arrays path to avoid re-emitting index list again and
+    * again.
+    */
+   draw->render->draw_elements( draw->render, 
+                                draw_elts, 
+                                draw_count );
+
+   /* Done -- that was easy, wasn't it:
+    */
+   draw->render->release_vertices( draw->render );
+
+   return TRUE;
+}
+
+
+
 
 static void fetch_emit_finish( struct draw_pt_middle_end *middle )
 {
@@ -287,10 +394,12 @@ struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw )
       return NULL;
    }
 
-   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;
+   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.run_linear_elts = fetch_emit_run_linear_elts;
+   fetch_emit->base.finish     = fetch_emit_finish;
+   fetch_emit->base.destroy    = fetch_emit_destroy;
 
    fetch_emit->draw = draw;