Merge branch 'mesa_7_5_branch'
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_shade_pipeline.c
index 557cd43f5b15b299d0940f4a74dc4777068681bb..df6c265b7ec9026a95cd6383b1d70adb242efcbb 100644 (file)
  *
  **************************************************************************/
 
-#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"
 #include "draw/draw_vertex.h"
 #include "draw/draw_pt.h"
+#include "draw/draw_vs.h"
+#include "translate/translate.h"
+
 
 struct fetch_pipeline_middle_end {
    struct draw_pt_middle_end base;
    struct draw_context *draw;
 
-   const ubyte *input_buf[2];
-
-   struct {
-      const ubyte **input_buf;
-      unsigned input_offset;
-      unsigned output_offset;
-
-      void (*emit)( const float *attrib, void *ptr );
-   } translate[PIPE_MAX_ATTRIBS];
-   unsigned nr_translate;
+   struct pt_emit *emit;
+   struct pt_fetch *fetch;
+   struct pt_post_vs *post_vs;
 
-   unsigned pipeline_vertex_size;
-   unsigned hw_vertex_size;
+   unsigned vertex_data_offset;
+   unsigned vertex_size;
    unsigned prim;
+   unsigned opt;
 };
 
 
-static void emit_NULL( const float *attrib,
-                      void *ptr )
-{
-}
-
-static void emit_R32_FLOAT( const float *attrib,
-                            void *ptr )
-{
-   float *out = (float *)ptr;
-   out[0] = attrib[0];
-}
-
-static void emit_R32G32_FLOAT( const float *attrib,
-                               void *ptr )
-{
-   float *out = (float *)ptr;
-   out[0] = attrib[0];
-   out[1] = attrib[1];
-}
-
-static void emit_R32G32B32_FLOAT( const float *attrib,
-                                  void *ptr )
-{
-   float *out = (float *)ptr;
-   out[0] = attrib[0];
-   out[1] = attrib[1];
-   out[2] = attrib[2];
-}
-
-static void emit_R32G32B32A32_FLOAT( const float *attrib,
-                                     void *ptr )
-{
-   float *out = (float *)ptr;
-   out[0] = attrib[0];
-   out[1] = attrib[1];
-   out[2] = attrib[2];
-   out[3] = attrib[3];
-}
-
 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
-                                    unsigned prim )
+                                    unsigned prim,
+                                   unsigned opt,
+                                    unsigned *max_vertices )
 {
    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    struct draw_context *draw = fpme->draw;
-   unsigned i;
-   boolean ok;
-   const struct vertex_info *vinfo;
-   unsigned dst_offset;
+   struct draw_vertex_shader *vs = draw->vs.vertex_shader;
 
-   fpme->prim = prim;
+   /* Add one to num_outputs because the pipeline occasionally tags on
+    * an additional texcoord, eg for AA lines.
+    */
+   unsigned nr = MAX2( vs->info.num_inputs,
+                      vs->info.num_outputs + 1 );
 
-   ok = draw->render->set_primitive(draw->render, prim);
-   if (!ok) {
-      assert(0);
-      return;
-   }
+   fpme->prim = prim;
+   fpme->opt = opt;
 
-   /* Must do this after set_primitive() above:
+   /* Always leave room for the vertex header whether we need it or
+    * not.  It's hard to get rid of it in particular because of the
+    * viewport code in draw_pt_post_vs.c.  
     */
-   vinfo = draw->render->get_vertex_info(draw->render);
+   fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
 
+   
 
-   /* In passthrough mode, need to translate from vertex shader
-    * outputs to hw vertices.
+   draw_pt_fetch_prepare( fpme->fetch, 
+                          vs->info.num_inputs,
+                         fpme->vertex_size );
+   /* XXX: it's not really gl rasterization rules we care about here,
+    * but gl vs dx9 clip spaces.
     */
-   dst_offset = 0;
-   for (i = 0; i < vinfo->num_attribs; i++) {
-      unsigned emit_sz = 0;
-      unsigned src_buffer = 0;
-      unsigned src_offset = (sizeof(struct vertex_header) + 
-                            vinfo->src_index[i] * 4 * sizeof(float) );
-
-
-         
-      switch (vinfo->emit[i]) {
-      case EMIT_4F:
-         fpme->translate[i].emit = emit_R32G32B32A32_FLOAT;
-        emit_sz = 4 * sizeof(float);
-         break;
-      case EMIT_3F:
-         fpme->translate[i].emit = emit_R32G32B32_FLOAT;
-        emit_sz = 3 * sizeof(float);
-         break;
-      case EMIT_2F:
-         fpme->translate[i].emit = emit_R32G32_FLOAT;
-        emit_sz = 2 * sizeof(float);
-         break;
-      case EMIT_1F:
-         fpme->translate[i].emit = emit_R32_FLOAT;
-        emit_sz = 1 * sizeof(float);
-         break;
-      case EMIT_1F_PSIZE:
-         fpme->translate[i].emit = emit_R32_FLOAT;
-        emit_sz = 1 * sizeof(float);
-         src_buffer = 1;
-        src_offset = 0;
-         break;
-      default:
-         assert(0);
-         fpme->translate[i].emit = emit_NULL;
-        emit_sz = 0;
-         break;
-      }
-
-      fpme->translate[i].input_buf = &fpme->input_buf[src_buffer];
-      fpme->translate[i].input_offset = src_offset;
-      fpme->translate[i].output_offset = dst_offset;
-      dst_offset += emit_sz;
+   draw_pt_post_vs_prepare( fpme->post_vs,
+                           (boolean)draw->bypass_clipping,
+                           (boolean)(draw->identity_viewport ||
+                                      draw->rasterizer->bypass_vs_clip_and_viewport),
+                           (boolean)draw->rasterizer->gl_rasterization_rules );
+                           
+
+   if (!(opt & PT_PIPELINE)) {
+      draw_pt_emit_prepare( fpme->emit, 
+                           prim,
+                            max_vertices );
+
+      *max_vertices = MAX2( *max_vertices,
+                            DRAW_PIPE_MAX_VERTICES );
+   }
+   else {
+      *max_vertices = DRAW_PIPE_MAX_VERTICES; 
    }
 
-   fpme->nr_translate = vinfo->num_attribs;
-   fpme->hw_vertex_size = vinfo->size * 4;
+   /* return even number */
+   *max_vertices = *max_vertices & ~1;
 
-   //fpme->pipeline_vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
-   fpme->pipeline_vertex_size = MAX_VERTEX_ALLOCATION;
-   fpme->hw_vertex_size = vinfo->size * 4;
+   /* No need to prepare the shader.
+    */
+   vs->prepare(vs, draw);
 }
 
 
 
-
 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
                                 const unsigned *fetch_elts,
                                 unsigned fetch_count,
@@ -182,83 +119,219 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
 {
    struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
    struct draw_context *draw = fpme->draw;
-   struct draw_vertex_shader *shader = draw->vertex_shader;
-   char *pipeline_verts;
+   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
+   unsigned opt = fpme->opt;
+   unsigned alloc_count = align( fetch_count, 4 );
 
-   pipeline_verts = MALLOC(fpme->pipeline_vertex_size *
-                          fetch_count);
+   struct vertex_header *pipeline_verts = 
+      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
 
    if (!pipeline_verts) {
+      /* Not much we can do here - just skip the rendering.
+       */
       assert(0);
       return;
    }
 
+   /* Fetch into our vertex buffer
+    */
+   draw_pt_fetch_run( fpme->fetch,
+                     fetch_elts, 
+                     fetch_count,
+                     (char *)pipeline_verts );
+
+   /* Run the shader, note that this overwrites the data[] parts of
+    * the pipeline verts.  If there is no shader, eg if
+    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
+    * already in the correct place.
+    */
+   if (opt & PT_SHADE)
+   {
+      shader->run_linear(shader, 
+                        (const float (*)[4])pipeline_verts->data,
+                        (      float (*)[4])pipeline_verts->data,
+                        (const float (*)[4])draw->pt.user.constants,
+                        fetch_count,
+                        fpme->vertex_size,
+                        fpme->vertex_size);
+   }
+
+   if (draw_pt_post_vs_run( fpme->post_vs,
+                           pipeline_verts,
+                           fetch_count,
+                           fpme->vertex_size ))
+   {
+      opt |= PT_PIPELINE;
+   }
 
-   /* Shade
+   /* Do we need to run the pipeline?
     */
-   shader->prepare(shader, draw);
-   if (shader->run(shader, draw, fetch_elts, fetch_count, pipeline_verts,
-                   fpme->pipeline_vertex_size)) {
-      /* Run the pipeline */
-      draw_pt_run_pipeline( fpme->draw,
-                            fpme->prim,
-                            pipeline_verts,
-                            fpme->pipeline_vertex_size,
-                            fetch_count,
-                            draw_elts,
-                            draw_count );
-   } else {
-      unsigned i, j;
-      void *hw_verts;
-      char *out_buf;
-
-      /* XXX: need to flush to get prim_vbuf.c to release its allocation?? 
+   if (opt & PT_PIPELINE) {
+      draw_pipeline_run( fpme->draw,
+                         fpme->prim,
+                         pipeline_verts,
+                         fetch_count,
+                         fpme->vertex_size,
+                         draw_elts,
+                         draw_count );
+   }
+   else {
+      draw_pt_emit( fpme->emit,
+                   (const float (*)[4])pipeline_verts->data,
+                   fetch_count,
+                   fpme->vertex_size,
+                   draw_elts,
+                   draw_count );
+   }
+
+
+   FREE(pipeline_verts);
+}
+
+
+static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
+                                       unsigned start,
+                                       unsigned count)
+{
+   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
+   struct draw_context *draw = fpme->draw;
+   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
+   unsigned opt = fpme->opt;
+   unsigned alloc_count = align( count, 4 );
+
+   struct vertex_header *pipeline_verts =
+      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
+
+   if (!pipeline_verts) {
+      /* Not much we can do here - just skip the rendering.
        */
-      draw_do_flush( draw, DRAW_FLUSH_BACKEND );
+      assert(0);
+      return;
+   }
 
-      hw_verts = draw->render->allocate_vertices(draw->render,
-                                                 (ushort)fpme->hw_vertex_size,
-                                                 (ushort)fetch_count);
-      if (!hw_verts) {
-         assert(0);
-         return;
-      }
+   /* Fetch into our vertex buffer
+    */
+   draw_pt_fetch_run_linear( fpme->fetch,
+                             start,
+                             count,
+                             (char *)pipeline_verts );
+
+   /* Run the shader, note that this overwrites the data[] parts of
+    * the pipeline verts.  If there is no shader, ie if
+    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
+    * already in the correct place.
+    */
+   if (opt & PT_SHADE)
+   {
+      shader->run_linear(shader,
+                        (const float (*)[4])pipeline_verts->data,
+                        (      float (*)[4])pipeline_verts->data,
+                        (const float (*)[4])draw->pt.user.constants,
+                        count,
+                        fpme->vertex_size,
+                        fpme->vertex_size);
+   }
 
-      out_buf = (char *)hw_verts;
-      fpme->input_buf[0] = (const ubyte *)pipeline_verts;
-      fpme->input_buf[1] = (const ubyte *)&fpme->draw->rasterizer->point_size;
+   if (draw_pt_post_vs_run( fpme->post_vs,
+                           pipeline_verts,
+                           count,
+                           fpme->vertex_size ))
+   {
+      opt |= PT_PIPELINE;
+   }
 
-      for (i = 0; i < fetch_count; i++) {
+   /* Do we need to run the pipeline?
+    */
+   if (opt & PT_PIPELINE) {
+      draw_pipeline_run_linear( fpme->draw,
+                                fpme->prim,
+                                pipeline_verts,
+                                count,
+                                fpme->vertex_size);
+   }
+   else {
+      draw_pt_emit_linear( fpme->emit,
+                           (const float (*)[4])pipeline_verts->data,
+                           fpme->vertex_size,
+                           count );
+   }
 
-         for (j = 0; j < fpme->nr_translate; j++) {
+   FREE(pipeline_verts);
+}
 
-            const float *attrib = (const float *)( (*fpme->translate[i].input_buf) + 
-                                                  fpme->translate[i].input_offset );
 
-           char *dest = out_buf + fpme->translate[i].output_offset;
 
-            /*debug_printf("emiting [%f, %f, %f, %f]\n",
-                         attrib[0], attrib[1],
-                         attrib[2], attrib[3]);*/
+static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
+                                            unsigned start,
+                                            unsigned 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;
+   struct draw_vertex_shader *shader = draw->vs.vertex_shader;
+   unsigned opt = fpme->opt;
+   unsigned alloc_count = align( count, 4 );
 
-            fpme->translate[j].emit(attrib, dest);
-         }
+   struct vertex_header *pipeline_verts =
+      (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
 
-        fpme->input_buf[0] += fpme->pipeline_vertex_size;
-      }
+   if (!pipeline_verts) 
+      return FALSE;
 
-      draw->render->draw(draw->render,
-                         draw_elts,
-                         draw_count);
+   /* Fetch into our vertex buffer
+    */
+   draw_pt_fetch_run_linear( fpme->fetch,
+                             start,
+                             count,
+                             (char *)pipeline_verts );
+
+   /* Run the shader, note that this overwrites the data[] parts of
+    * the pipeline verts.  If there is no shader, ie if
+    * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
+    * already in the correct place.
+    */
+   if (opt & PT_SHADE)
+   {
+      shader->run_linear(shader,
+                        (const float (*)[4])pipeline_verts->data,
+                        (      float (*)[4])pipeline_verts->data,
+                        (const float (*)[4])draw->pt.user.constants,
+                        count,
+                        fpme->vertex_size,
+                        fpme->vertex_size);
+   }
 
-      draw->render->release_vertices(draw->render,
-                                     hw_verts,
-                                     fpme->hw_vertex_size,
-                                     fetch_count);
+   if (draw_pt_post_vs_run( fpme->post_vs,
+                           pipeline_verts,
+                           count,
+                           fpme->vertex_size ))
+   {
+      opt |= PT_PIPELINE;
    }
 
+   /* Do we need to run the pipeline?
+    */
+   if (opt & PT_PIPELINE) {
+      draw_pipeline_run( fpme->draw,
+                         fpme->prim,
+                         pipeline_verts,
+                         count,
+                         fpme->vertex_size,
+                         draw_elts,
+                         draw_count );
+   }
+   else {
+      draw_pt_emit( fpme->emit,
+                   (const float (*)[4])pipeline_verts->data,
+                   count,
+                   fpme->vertex_size,
+                   draw_elts,
+                   draw_count );
+   }
 
    FREE(pipeline_verts);
+   return TRUE;
 }
 
 
@@ -270,20 +343,53 @@ static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
 
 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
 {
+   struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
+
+   if (fpme->fetch)
+      draw_pt_fetch_destroy( fpme->fetch );
+
+   if (fpme->emit)
+      draw_pt_emit_destroy( fpme->emit );
+
+   if (fpme->post_vs)
+      draw_pt_post_vs_destroy( fpme->post_vs );
+
    FREE(middle);
 }
 
 
 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
 {
-   struct fetch_pipeline_middle_end *fetch_pipeline = CALLOC_STRUCT( fetch_pipeline_middle_end );
+   struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
+   if (!fpme)
+      goto fail;
+
+   fpme->base.prepare        = fetch_pipeline_prepare;
+   fpme->base.run            = fetch_pipeline_run;
+   fpme->base.run_linear     = fetch_pipeline_linear_run;
+   fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
+   fpme->base.finish         = fetch_pipeline_finish;
+   fpme->base.destroy        = fetch_pipeline_destroy;
+
+   fpme->draw = draw;
+
+   fpme->fetch = draw_pt_fetch_create( draw );
+   if (!fpme->fetch)
+      goto fail;
+
+   fpme->post_vs = draw_pt_post_vs_create( draw );
+   if (!fpme->post_vs)
+      goto fail;
+
+   fpme->emit = draw_pt_emit_create( draw );
+   if (!fpme->emit) 
+      goto fail;
 
-   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;
+   return &fpme->base;
 
-   fetch_pipeline->draw = draw;
+ fail:
+   if (fpme)
+      fetch_pipeline_destroy( &fpme->base );
 
-   return &fetch_pipeline->base;
+   return NULL;
 }