geometry shaders: make gs work with changable primitives and variable number of vertices
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_varray.c
index 59a9569270c5da4282e997e33112df4399e4ff11..5ea833032f322da20762a4da5988a6b36f458711 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_pt.h"
 
 #define FETCH_MAX 256
-#define DRAW_MAX (16*FETCH_MAX)
+#define DRAW_MAX (FETCH_MAX+8)
 
 struct varray_frontend {
    struct draw_pt_front_end base;
@@ -40,10 +42,8 @@ struct varray_frontend {
    ushort draw_elts[DRAW_MAX];
    unsigned fetch_elts[FETCH_MAX];
 
-   unsigned draw_count;
-   unsigned fetch_count;
-
-   unsigned fetch_start;
+   unsigned driver_fetch_max;
+   unsigned fetch_max;
 
    struct draw_pt_middle_end *middle;
 
@@ -51,245 +51,111 @@ struct varray_frontend {
    unsigned output_prim;
 };
 
-static void varray_flush(struct varray_frontend *varray)
-{
-   if (varray->draw_count) {
-#if 0
-      debug_printf("FLUSH fc = %d, dc = %d\n",
-                   varray->fetch_count,
-                   varray->draw_count);
-      debug_printf("\telt0 = %d, eltx = %d, draw0 = %d, drawx = %d\n",
-                   varray->fetch_elts[0],
-                   varray->fetch_elts[varray->fetch_count-1],
-                   varray->draw_elts[0],
-                   varray->draw_elts[varray->draw_count-1]);
-#endif
-      varray->middle->run(varray->middle,
-                          varray->fetch_elts,
-                          varray->fetch_count,
-                          varray->draw_elts,
-                          varray->draw_count);
-   }
-
-   varray->fetch_count = 0;
-   varray->draw_count = 0;
-}
 
 static void varray_flush_linear(struct varray_frontend *varray,
                                 unsigned start, unsigned count)
 {
    if (count) {
-#if 0
-      debug_printf("FLUSH LINEAR start = %d, count = %d\n",
-                   start,
-                   count);
-#endif
       assert(varray->middle->run_linear);
       varray->middle->run_linear(varray->middle, start, count);
    }
 }
 
-static INLINE void fetch_init(struct varray_frontend *varray,
-                              unsigned count)
+static void varray_line_loop_segment(struct varray_frontend *varray,
+                                     unsigned start,
+                                     unsigned segment_start,
+                                     unsigned segment_count,
+                                     boolean end )
 {
-   unsigned idx;
-#if 0
-      debug_printf("FETCH INIT c = %d, fs = %d\n",
-                   count,
-                   varray->fetch_start);
-#endif
-   for (idx = 0; idx < count; ++idx) {
-      varray->fetch_elts[idx] = varray->fetch_start + idx;
-   }
-   varray->fetch_start += idx;
-   varray->fetch_count = idx;
-}
+   assert(segment_count < varray->fetch_max);
+   if (segment_count >= 1) {
+      unsigned nr = 0, i;
 
+      for (i = 0; i < segment_count; i++) 
+         varray->fetch_elts[nr++] = start + segment_start + i;
 
-static boolean split_prim_inplace(unsigned prim, unsigned *first, unsigned *incr)
-{
-   switch (prim) {
-   case PIPE_PRIM_POINTS:
-      *first = 1;
-      *incr = 1;
-      return TRUE;
-   case PIPE_PRIM_LINES:
-      *first = 2;
-      *incr = 2;
-      return TRUE;
-   case PIPE_PRIM_LINE_STRIP:
-      *first = 2;
-      *incr = 1;
-      return TRUE;
-   case PIPE_PRIM_TRIANGLES:
-      *first = 3;
-      *incr = 3;
-      return TRUE;
-   case PIPE_PRIM_TRIANGLE_STRIP:
-      *first = 3;
-      *incr = 1;
-      return TRUE;
-   case PIPE_PRIM_TRIANGLE_FAN:
-      *first = 3;
-      *incr = 1;
-      return TRUE;
-   case PIPE_PRIM_QUADS:
-      *first = 4;
-      *incr = 4;
-      return TRUE;
-   case PIPE_PRIM_QUAD_STRIP:
-      *first = 4;
-      *incr = 2;
-      return TRUE;
-   case PIPE_PRIM_POLYGON:
-      *first = 3;
-      *incr = 1;
-      return TRUE;
-   default:
-      *first = 0;
-      *incr = 1;               /* set to one so that count % incr works */
-      return FALSE;
-   }
-}
+      if (end) 
+         varray->fetch_elts[nr++] = start;
 
+      assert(nr <= FETCH_MAX);
 
-static INLINE void add_draw_el(struct varray_frontend *varray,
-                               int idx, ushort flags)
-{
-   varray->draw_elts[varray->draw_count++] = idx | flags;
+      varray->middle->run(varray->middle, 
+                          varray->fetch_elts,
+                          nr,
+                          varray->draw_elts, /* ie. linear */
+                          nr);
+   }
 }
 
 
-static INLINE void varray_triangle( struct varray_frontend *varray,
-                                    unsigned i0,
-                                    unsigned i1,
-                                    unsigned i2 )
-{
-   add_draw_el(varray, i0, 0);
-   add_draw_el(varray, i1, 0);
-   add_draw_el(varray, i2, 0);
-}
 
-static INLINE void varray_triangle_flags( struct varray_frontend *varray,
-                                          ushort flags,
-                                          unsigned i0,
-                                          unsigned i1,
-                                          unsigned i2 )
+static void varray_fan_segment(struct varray_frontend *varray,
+                               unsigned start, 
+                               unsigned segment_start,
+                               unsigned segment_count )
 {
-   add_draw_el(varray, i0, flags);
-   add_draw_el(varray, i1, 0);
-   add_draw_el(varray, i2, 0);
-}
-
-static INLINE void varray_line( struct varray_frontend *varray,
-                                unsigned i0,
-                                unsigned i1 )
-{
-   add_draw_el(varray, i0, 0);
-   add_draw_el(varray, i1, 0);
-}
+   assert(segment_count < varray->fetch_max);
+   if (segment_count >= 2) {
+      unsigned nr = 0, i;
 
+      if (segment_start != 0)
+         varray->fetch_elts[nr++] = start;
 
-static INLINE void varray_line_flags( struct varray_frontend *varray,
-                                      ushort flags,
-                                      unsigned i0,
-                                      unsigned i1 )
-{
-   add_draw_el(varray, i0, flags);
-   add_draw_el(varray, i1, 0);
-}
+      for (i = 0 ; i < segment_count; i++) 
+         varray->fetch_elts[nr++] = start + segment_start + i;
 
+      assert(nr <= FETCH_MAX);
 
-static INLINE void varray_point( struct varray_frontend *varray,
-                                 unsigned i0 )
-{
-   add_draw_el(varray, i0, 0);
+      varray->middle->run(varray->middle, 
+                          varray->fetch_elts,
+                          nr,
+                          varray->draw_elts, /* ie. linear */
+                          nr);
+   }
 }
 
-static INLINE void varray_quad( struct varray_frontend *varray,
-                                unsigned i0,
-                                unsigned i1,
-                                unsigned i2,
-                                unsigned i3 )
-{
-   varray_triangle( varray, i0, i1, i3 );
-   varray_triangle( varray, i1, i2, i3 );
-}
 
-static INLINE void varray_ef_quad( struct varray_frontend *varray,
-                                   unsigned i0,
-                                   unsigned i1,
-                                   unsigned i2,
-                                   unsigned i3 )
-{
-   const unsigned omitEdge1 = DRAW_PIPE_EDGE_FLAG_0 | DRAW_PIPE_EDGE_FLAG_2;
-   const unsigned omitEdge2 = DRAW_PIPE_EDGE_FLAG_0 | DRAW_PIPE_EDGE_FLAG_1;
 
-   varray_triangle_flags( varray,
-                          DRAW_PIPE_RESET_STIPPLE | omitEdge1,
-                          i0, i1, i3 );
 
-   varray_triangle_flags( varray,
-                          omitEdge2,
-                          i1, i2, i3 );
-}
-
-/* At least for now, we're back to using a template include file for
- * this.  The two paths aren't too different though - it may be
- * possible to reunify them.
- */
-#define TRIANGLE(vc,flags,i0,i1,i2) varray_triangle_flags(vc,flags,i0,i1,i2)
-#define QUAD(vc,i0,i1,i2,i3)        varray_ef_quad(vc,i0,i1,i2,i3)
-#define LINE(vc,flags,i0,i1)        varray_line_flags(vc,flags,i0,i1)
-#define POINT(vc,i0)                varray_point(vc,i0)
-#define FUNC varray_run_extras
-#include "draw_pt_varray_tmp.h"
-
-#define TRIANGLE(vc,flags,i0,i1,i2) varray_triangle(vc,i0,i1,i2)
-#define QUAD(vc,i0,i1,i2,i3)        varray_quad(vc,i0,i1,i2,i3)
-#define LINE(vc,flags,i0,i1)        varray_line(vc,i0,i1)
-#define POINT(vc,i0)                varray_point(vc,i0)
 #define FUNC varray_run
 #include "draw_pt_varray_tmp_linear.h"
 
-
-
-static unsigned reduced_prim[PIPE_PRIM_POLYGON + 1] = {
+static unsigned decompose_prim[PIPE_PRIM_POLYGON + 1] = {
    PIPE_PRIM_POINTS,
    PIPE_PRIM_LINES,
-   PIPE_PRIM_LINES,
-   PIPE_PRIM_LINES,
-   PIPE_PRIM_TRIANGLES,
-   PIPE_PRIM_TRIANGLES,
+   PIPE_PRIM_LINE_STRIP,        /* decomposed LINELOOP */
+   PIPE_PRIM_LINE_STRIP,
    PIPE_PRIM_TRIANGLES,
-   PIPE_PRIM_TRIANGLES,
-   PIPE_PRIM_TRIANGLES,
-   PIPE_PRIM_TRIANGLES
+   PIPE_PRIM_TRIANGLE_STRIP,
+   PIPE_PRIM_TRIANGLE_FAN, 
+   PIPE_PRIM_QUADS,
+   PIPE_PRIM_QUAD_STRIP,
+   PIPE_PRIM_POLYGON
 };
 
 
 
 static void varray_prepare(struct draw_pt_front_end *frontend,
-                           unsigned prim,
+                           unsigned in_prim,
+                           unsigned out_prim,
                            struct draw_pt_middle_end *middle,
                            unsigned opt)
 {
    struct varray_frontend *varray = (struct varray_frontend *)frontend;
 
-   if (opt & PT_PIPELINE)
-   {
-      varray->base.run = varray_run_extras;
-   }
-   else
-   {
-      varray->base.run = varray_run;
-   }
+   varray->base.run = varray_run;
 
-   varray->input_prim = prim;
-   varray->output_prim = reduced_prim[prim];
+   varray->input_prim = in_prim;
+   varray->output_prim = decompose_prim[out_prim];
 
    varray->middle = middle;
-   middle->prepare(middle, varray->output_prim, opt);
+   middle->prepare(middle, varray->input_prim,
+                   varray->output_prim, opt, &varray->driver_fetch_max );
+
+   /* check that the max is even */
+   assert((varray->driver_fetch_max & 1) == 0);
+
+   varray->fetch_max = MIN2(FETCH_MAX, varray->driver_fetch_max);
 }
 
 
@@ -310,6 +176,7 @@ static void varray_destroy(struct draw_pt_front_end *frontend)
 
 struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw)
 {
+   ushort i;
    struct varray_frontend *varray = CALLOC_STRUCT(varray_frontend);
    if (varray == NULL)
       return NULL;
@@ -320,5 +187,9 @@ struct draw_pt_front_end *draw_pt_varray(struct draw_context *draw)
    varray->base.destroy = varray_destroy;
    varray->draw = draw;
 
+   for (i = 0; i < DRAW_MAX; i++) {
+      varray->draw_elts[i] = i;
+   }
+
    return &varray->base;
 }