Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_shade_emit.c
index 729c7db99995fefd4cb06d253acf395fddab5a12..44147aed9be33b0081452ba77461151d1e7d1588 100644 (file)
@@ -31,7 +31,8 @@
   */
 
 
-#include "pipe/p_util.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
 #include "draw/draw_context.h"
 #include "draw/draw_private.h"
 #include "draw/draw_vbuf.h"
@@ -70,13 +71,15 @@ struct fetch_shade_emit {
                               
 static void fse_prepare( struct draw_pt_middle_end *middle,
                          unsigned prim, 
-                         unsigned opt )
+                         unsigned opt,
+                         unsigned *max_vertices )
 {
    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    struct draw_context *draw = fse->draw;
    unsigned num_vs_inputs = draw->vs.vertex_shader->info.num_inputs;
    const struct vertex_info *vinfo;
    unsigned i;
+   unsigned nr_vbs = 0;
    
 
    if (!draw->render->set_primitive( draw->render, 
@@ -98,9 +101,10 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
    fse->key.nr_elements = MAX2(fse->key.nr_outputs,     /* outputs - translate to hw format */
                                fse->key.nr_inputs);     /* inputs - fetch from api format */
 
-   fse->key.viewport = !draw->identity_viewport;
+   fse->key.viewport = (!draw->rasterizer->bypass_vs_clip_and_viewport &&
+                        !draw->identity_viewport);
    fse->key.clip = !draw->bypass_clipping;
-   fse->key.pad = 0;
+   fse->key.const_vbuffers = 0;
 
    memset(fse->key.element, 0, 
           fse->key.nr_elements * sizeof(fse->key.element[0]));
@@ -114,16 +118,23 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
        */
       fse->key.element[i].in.buffer = src->vertex_buffer_index;
       fse->key.element[i].in.offset = src->src_offset;
+      nr_vbs = MAX2(nr_vbs, src->vertex_buffer_index + 1);
    }
    
+   for (i = 0; i < 5 && i < nr_vbs; i++) {
+      if (draw->pt.vertex_buffer[i].stride == 0)
+         fse->key.const_vbuffers |= (1<<i);
+   }
 
+   if (0) debug_printf("%s: lookup const_vbuffers: %x\n", __FUNCTION__, fse->key.const_vbuffers);
+   
    {
       unsigned dst_offset = 0;
 
       for (i = 0; i < vinfo->num_attribs; i++) {
          unsigned emit_sz = 0;
 
-         switch (vinfo->emit[i]) {
+         switch (vinfo->attrib[i].emit) {
          case EMIT_4F:
             emit_sz = 4 * sizeof(float);
             break;
@@ -151,8 +162,8 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
           * numbers, not to positions in the hw vertex description --
           * that's handled by the output_offset field.
           */
-         fse->key.element[i].out.format = vinfo->emit[i];
-         fse->key.element[i].out.vs_output = vinfo->src_index[i];
+         fse->key.element[i].out.format = vinfo->attrib[i].emit;
+         fse->key.element[i].out.vs_output = vinfo->attrib[i].src_index;
          fse->key.element[i].out.offset = dst_offset;
       
          dst_offset += emit_sz;
@@ -160,13 +171,7 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
       }
    }
 
-
-   /* Would normally look up a vertex shader and peruse its list of
-    * varients somehow.  We omitted that step and put all the
-    * hardcoded "shaders" into an array.  We're just making the
-    * assumption that this happens to be a matching shader...  ie
-    * you're running isosurf, aren't you?
-    */
+   
    fse->active = draw_vs_lookup_varient( draw->vs.vertex_shader, 
                                          &fse->key );
 
@@ -175,25 +180,39 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
       return ;
    }
 
+   if (0) debug_printf("%s: found const_vbuffers: %x\n", __FUNCTION__, 
+                       fse->active->key.const_vbuffers);
+
    /* Now set buffer pointers:
     */
-   for (i = 0; i < num_vs_inputs; i++) {
-      unsigned buf = draw->pt.vertex_element[i].vertex_buffer_index;
-
-      fse->active->set_input( fse->active, 
-                              i, 
-                              
-                              ((const ubyte *) draw->pt.user.vbuffer[buf] + 
-                               draw->pt.vertex_buffer[buf].buffer_offset),
-                              
-                              draw->pt.vertex_buffer[buf].pitch );
+   for (i = 0; i < draw->pt.nr_vertex_buffers; i++) {
+      fse->active->set_buffer( fse->active, 
+                               i, 
+                               ((const ubyte *) draw->pt.user.vbuffer[i] + 
+                                draw->pt.vertex_buffer[i].buffer_offset),
+                              draw->pt.vertex_buffer[i].stride );
    }
 
-   fse->active->set_constants( fse->active,
-                               (const float (*)[4])draw->pt.user.constants );
+   *max_vertices = (draw->render->max_vertex_buffer_bytes / 
+                    (vinfo->size * 4));
 
-   fse->active->set_viewport( fse->active,
-                              &draw->viewport );
+   /* Return an even number of verts.
+    * This prevents "parity" errors when splitting long triangle strips which
+    * can lead to front/back culling mix-ups.
+    * Every other triangle in a strip has an alternate front/back orientation
+    * so splitting at an odd position can cause the orientation of subsequent
+    * triangles to get reversed.
+    */
+   *max_vertices = *max_vertices & ~1;
+
+   /* Probably need to do this somewhere (or fix exec shader not to
+    * need it):
+    */
+   if (1) {
+      struct draw_vertex_shader *vs = draw->vs.vertex_shader;
+      vs->prepare(vs, draw);
+   }
+   
 
    //return TRUE;
 }
@@ -210,21 +229,23 @@ static void fse_run_linear( struct draw_pt_middle_end *middle,
 {
    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    struct draw_context *draw = fse->draw;
-   unsigned alloc_count = align(count, 4);
    char *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)fse->key.output_stride,
-                                               (ushort)alloc_count );
+   if (count >= UNDEFINED_VERTEX_ID) 
+      goto fail;
 
-   if (!hw_verts) {
-      assert(0);
-      return;
-   }
+   if (!draw->render->allocate_vertices( draw->render,
+                                         (ushort)fse->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, run shader and emit HW verts.
     * Clipping is done elsewhere -- either by the API or on hardware,
@@ -234,13 +255,7 @@ static void fse_run_linear( struct draw_pt_middle_end *middle,
                             start, count,
                             hw_verts );
 
-   /* Draw arrays path to avoid re-emitting index list again and
-    * again.
-    */
-   draw->render->draw_arrays( draw->render,
-                              0,
-                              count );
-   
+
    if (0) {
       unsigned i;
       for (i = 0; i < count; i++) {
@@ -252,12 +267,24 @@ static void fse_run_linear( struct draw_pt_middle_end *middle,
                                    (const uint8_t *)hw_verts + fse->key.output_stride * i );
       }
    }
+   
+   draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
+
+   /* Draw arrays path to avoid re-emitting index list again and
+    * again.
+    */
+   draw->render->draw_arrays( draw->render,
+                              0,
+                              count );
+   
 
+   draw->render->release_vertices( draw->render );
 
-   draw->render->release_vertices( draw->render, 
-                                  hw_verts, 
-                                  fse->key.output_stride, 
-                                  count );
+   return;
+
+fail:
+   assert(0);
+   return;
 }
 
 
@@ -270,20 +297,23 @@ fse_run(struct draw_pt_middle_end *middle,
 {
    struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
    struct draw_context *draw = fse->draw;
-   unsigned alloc_count = align(fetch_count, 4);
    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)fse->key.output_stride,
-                                               (ushort)alloc_count );
-   if (!hw_verts) {
-      assert(0);
-      return;
-   }
+   if (fetch_count >= UNDEFINED_VERTEX_ID) 
+      goto fail;
+
+   if (!draw->render->allocate_vertices( draw->render,
+                                         (ushort)fse->key.output_stride,
+                                         (ushort)fetch_count ))
+      goto fail;
+
+   hw_verts = draw->render->map_vertices( draw->render ); 
+   if (!hw_verts) 
+      goto fail;
          
                                        
    /* Single routine to fetch vertices, run shader and emit HW verts.
@@ -293,9 +323,6 @@ fse_run(struct draw_pt_middle_end *middle,
                           fetch_count,
                           hw_verts );
 
-   draw->render->draw( draw->render, 
-                       draw_elts, 
-                       draw_count );
 
    if (0) {
       unsigned i;
@@ -307,15 +334,72 @@ fse_run(struct draw_pt_middle_end *middle,
       }
    }
 
+   draw->render->unmap_vertices( draw->render, 0, (ushort)(fetch_count - 1) );
+   
+   draw->render->draw( draw->render, 
+                       draw_elts, 
+                       draw_count );
+
+
+   draw->render->release_vertices( draw->render );
+   return;
+
+fail:
+   assert(0);
+   return;
+}
+
+
+
+static boolean fse_run_linear_elts( struct draw_pt_middle_end *middle, 
+                                 unsigned start, 
+                                 unsigned count,
+                                 const ushort *draw_elts,
+                                 unsigned draw_count )
+{
+   struct fetch_shade_emit *fse = (struct fetch_shade_emit *)middle;
+   struct draw_context *draw = fse->draw;
+   char *hw_verts;
+
+   /* XXX: need to flush to get prim_vbuf.c to release its allocation??
+    */
+   draw_do_flush( draw, DRAW_FLUSH_BACKEND );
+
+   if (count >= UNDEFINED_VERTEX_ID)
+      return FALSE;
+
+   if (!draw->render->allocate_vertices( draw->render,
+                                         (ushort)fse->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, run shader and emit HW verts.
+    * Clipping is done elsewhere -- either by the API or on hardware,
+    * or for some other reason not required...
+    */
+   fse->active->run_linear( fse->active, 
+                            start, count,
+                            hw_verts );
+
+
+   draw->render->draw( draw->render, 
+                       draw_elts, 
+                       draw_count );
+   
+
+   draw->render->unmap_vertices( draw->render, 0, (ushort)(count - 1) );
 
-   draw->render->release_vertices( draw->render, 
-                                   hw_verts, 
-                                   fse->key.output_stride, 
-                                   fetch_count );
+   draw->render->release_vertices( draw->render );
 
+   return TRUE;
 }
 
 
+
 static void fse_finish( struct draw_pt_middle_end *middle )
 {
 }
@@ -336,6 +420,7 @@ struct draw_pt_middle_end *draw_pt_middle_fse( struct draw_context *draw )
    fse->base.prepare = fse_prepare;
    fse->base.run = fse_run;
    fse->base.run_linear = fse_run_linear;
+   fse->base.run_linear_elts = fse_run_linear_elts;
    fse->base.finish = fse_finish;
    fse->base.destroy = fse_destroy;
    fse->draw = draw;