llvmpipe: EXT_transform_feedback support (v1.1)
authorDave Airlie <airlied@gmail.com>
Tue, 4 Dec 2012 20:50:07 +0000 (06:50 +1000)
committerDave Airlie <airlied@redhat.com>
Thu, 6 Dec 2012 04:48:10 +0000 (14:48 +1000)
I'd written most of this ages ago, but never finished it off.

This passes 115/130 piglit tests so far. I'll look into the
others as time permits.

v1.1: fix calloc return check as suggested by Jose.

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
15 files changed:
src/gallium/drivers/llvmpipe/lp_context.h
src/gallium/drivers/llvmpipe/lp_draw_arrays.c
src/gallium/drivers/llvmpipe/lp_query.c
src/gallium/drivers/llvmpipe/lp_query.h
src/gallium/drivers/llvmpipe/lp_rast.c
src/gallium/drivers/llvmpipe/lp_scene.c
src/gallium/drivers/llvmpipe/lp_scene.h
src/gallium/drivers/llvmpipe/lp_screen.c
src/gallium/drivers/llvmpipe/lp_setup.c
src/gallium/drivers/llvmpipe/lp_setup.h
src/gallium/drivers/llvmpipe/lp_setup_context.h
src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
src/gallium/drivers/llvmpipe/lp_state_rasterizer.c
src/gallium/drivers/llvmpipe/lp_state_so.c
src/gallium/drivers/llvmpipe/lp_surface.c

index fe6fa3f9390c7bb521f794584dc6f7c720399b63..25cdff998c4e484f7e5a60fdbff185a753cb5371 100644 (file)
@@ -81,12 +81,6 @@ struct llvmpipe_context {
    struct pipe_viewport_state viewport;
    struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
    struct pipe_index_buffer index_buffer;
-   struct {
-      struct llvmpipe_resource *buffer[PIPE_MAX_SO_BUFFERS];
-      int offset[PIPE_MAX_SO_BUFFERS];
-      int so_count[PIPE_MAX_SO_BUFFERS];
-      int num_buffers;
-   } so_target;
    struct pipe_resource *mapped_vs_tex[PIPE_MAX_SAMPLERS];
 
    unsigned num_samplers[PIPE_SHADER_TYPES];
@@ -94,6 +88,11 @@ struct llvmpipe_context {
 
    unsigned num_vertex_buffers;
 
+   struct draw_so_target *so_targets[PIPE_MAX_SO_BUFFERS];
+   int num_so_targets;
+   struct pipe_query_data_so_statistics so_stats;
+   unsigned num_primitives_generated;
+
    unsigned dirty; /**< Mask of LP_NEW_x flags */
 
    unsigned active_occlusion_query;
index 3497edf9d1ce1b767d276e468566d1f970c68f5a..eaa9ba3b130407f1e38e92151aa556e5ec019957 100644 (file)
@@ -88,6 +88,13 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
                        lp->index_buffer.index_size);
    }
 
+   for (i = 0; i < lp->num_so_targets; i++) {
+      void *buf = llvmpipe_resource(lp->so_targets[i]->target.buffer)->data;
+      lp->so_targets[i]->mapping = buf;
+   }
+   draw_set_mapped_so_targets(draw, lp->num_so_targets,
+                              lp->so_targets);
+
    llvmpipe_prepare_vertex_sampling(lp,
                                     lp->num_sampler_views[PIPE_SHADER_VERTEX],
                                     lp->sampler_views[PIPE_SHADER_VERTEX]);
@@ -104,6 +111,8 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    if (mapped_indices) {
       draw_set_indexes(draw, NULL, 0);
    }
+   draw_set_mapped_so_targets(draw, 0, NULL);
+
    llvmpipe_cleanup_vertex_sampling(lp);
 
    /*
index e302197256669d6d404eefc3c9dac4ce479bbb8a..7a62a809d581c8eff0cbf96e1f898004f6add837 100644 (file)
@@ -138,6 +138,12 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
             *result = os_time_get_nano();
       }
       break;
+   case PIPE_QUERY_PRIMITIVES_GENERATED:
+      *result = pq->num_primitives_generated;
+      break;
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+      *result = pq->num_primitives_written;
+      break;
    default:
       assert(0);
       break;
@@ -165,6 +171,16 @@ llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
    memset(pq->count, 0, sizeof(pq->count));
    lp_setup_begin_query(llvmpipe->setup, pq);
 
+   if (pq->type == PIPE_QUERY_PRIMITIVES_EMITTED) {
+      pq->num_primitives_written = 0;
+      llvmpipe->so_stats.num_primitives_written = 0;
+   }
+
+   if (pq->type == PIPE_QUERY_PRIMITIVES_GENERATED) {
+      pq->num_primitives_generated = 0;
+      llvmpipe->num_primitives_generated = 0;
+   }
+
    if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
       llvmpipe->active_occlusion_query = TRUE;
       llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
@@ -180,6 +196,14 @@ llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
 
    lp_setup_end_query(llvmpipe->setup, pq);
 
+   if (pq->type == PIPE_QUERY_PRIMITIVES_EMITTED) {
+      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
+   }
+
+   if (pq->type == PIPE_QUERY_PRIMITIVES_GENERATED) {
+      pq->num_primitives_generated = llvmpipe->num_primitives_generated;
+   }
+
    if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
       assert(llvmpipe->active_occlusion_query);
       llvmpipe->active_occlusion_query = FALSE;
index cacbd9d0b8c75a834ed42328768ca4511d56cc86..19d977fd2e446f5b077d698e12f9bf1d508dab7f 100644 (file)
@@ -45,6 +45,8 @@ struct llvmpipe_query {
    uint64_t count[LP_MAX_THREADS];  /* a counter for each thread */
    struct lp_fence *fence;          /* fence from last scene this was binned in */
    unsigned type;                   /* PIPE_QUERY_* */
+   unsigned num_primitives_generated;
+   unsigned num_primitives_written;
 };
 
 
index 40a8591cabe14c8b4738409a070b9d84188fd460..37be6ad571d15b65c6425d9fafe7bf3f0ba1decb 100644 (file)
@@ -440,6 +440,9 @@ lp_rast_begin_query(struct lp_rasterizer_task *task,
    case PIPE_QUERY_TIME_ELAPSED:
       task->query_start = os_time_get_nano();
       break;
+   case PIPE_QUERY_PRIMITIVES_GENERATED:
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+      break;
    default:
       assert(0);
       break;
@@ -471,6 +474,9 @@ lp_rast_end_query(struct lp_rasterizer_task *task,
    case PIPE_QUERY_TIMESTAMP:
       pq->count[task->thread_index] = os_time_get_nano();
       break;
+   case PIPE_QUERY_PRIMITIVES_GENERATED:
+   case PIPE_QUERY_PRIMITIVES_EMITTED:
+      break;
    default:
       assert(0);
       break;
@@ -606,7 +612,7 @@ rasterize_scene(struct lp_rasterizer_task *task,
 {
    task->scene = scene;
 
-   if (!task->rast->no_rast) {
+   if (!task->rast->no_rast && !scene->discard) {
       /* loop over scene bins, rasterize each */
 #if 0
       {
index ed998246fb9364e98a6fdb9f09a01d0399b6af85..328c0f74572c4481619d3efcad795af6e7698071 100644 (file)
@@ -472,10 +472,11 @@ end:
 
 
 void lp_scene_begin_binning( struct lp_scene *scene,
-                             struct pipe_framebuffer_state *fb )
+                             struct pipe_framebuffer_state *fb, boolean discard )
 {
    assert(lp_scene_is_empty(scene));
 
+   scene->discard = discard;
    util_copy_framebuffer_state(&scene->fb, fb);
 
    scene->tiles_x = align(fb->width, TILE_SIZE) / TILE_SIZE;
index 31a5ae72b37e6e7410e4937fbf62e390396321ef..b1db61bd5a3a47cfd428cabdc875df2e59adeb95 100644 (file)
@@ -157,7 +157,7 @@ struct lp_scene {
 
    boolean alloc_failed;
    boolean has_depthstencil_clear;
-
+   boolean discard;
    /**
     * Number of active tiles in each dimension.
     * This basically the framebuffer size divided by tile size
@@ -381,7 +381,8 @@ lp_scene_bin_iter_next( struct lp_scene *scene );
  */
 void
 lp_scene_begin_binning( struct lp_scene *scene,
-                        struct pipe_framebuffer_state *fb );
+                        struct pipe_framebuffer_state *fb,
+                        boolean discard );
 
 void
 lp_scene_end_binning( struct lp_scene *scene );
index acbde9da983fc1f881bb12813209a1821f9a416e..61228f6ed40fea2a07d6f7b5508c90c18392f4bb 100644 (file)
@@ -117,7 +117,7 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_MAX_DUAL_SOURCE_RENDER_TARGETS:
       return 0;
    case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
-      return 0;
+      return PIPE_MAX_SO_BUFFERS;
    case PIPE_CAP_ANISOTROPIC_FILTER:
       return 0;
    case PIPE_CAP_POINT_SPRITE:
@@ -186,6 +186,7 @@ llvmpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
       return 0;
    case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS:
    case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS:
+      return 16*4;
    case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME:
       return 0;
    case PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS:
index 1d71a87319eefc27d3d5c55aa1a01a45764f03d6..25e5da84ebbe084106f1ed1ea0e65e736206dc6f 100644 (file)
@@ -65,7 +65,9 @@ static boolean try_update_scene_state( struct lp_setup_context *setup );
 static void
 lp_setup_get_empty_scene(struct lp_setup_context *setup)
 {
+   struct llvmpipe_context *lp = llvmpipe_context(setup->pipe);
    assert(setup->scene == NULL);
+   boolean discard = lp->rasterizer ? lp->rasterizer->rasterizer_discard : FALSE;
 
    setup->scene_idx++;
    setup->scene_idx %= Elements(setup->scenes);
@@ -80,7 +82,7 @@ lp_setup_get_empty_scene(struct lp_setup_context *setup)
       lp_fence_wait(setup->scene->fence);
    }
 
-   lp_scene_begin_binning(setup->scene, &setup->fb);
+   lp_scene_begin_binning(setup->scene, &setup->fb, discard);
    
 }
 
@@ -620,6 +622,13 @@ lp_setup_set_flatshade_first( struct lp_setup_context *setup,
    setup->flatshade_first = flatshade_first;
 }
 
+void
+lp_setup_set_rasterizer_discard( struct lp_setup_context *setup,
+                                 boolean rasterizer_discard )
+{
+   setup->rasterizer_discard = rasterizer_discard;
+   set_scene_state( setup, SETUP_FLUSHED, __FUNCTION__ );
+}
 
 void 
 lp_setup_set_vertex_info( struct lp_setup_context *setup,
@@ -1057,6 +1066,7 @@ lp_setup_create( struct pipe_context *pipe,
    struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
    struct lp_setup_context *setup;
    unsigned i;
+   struct llvmpipe_context *lp = llvmpipe_context(pipe);
 
    setup = CALLOC_STRUCT(lp_setup_context);
    if (!setup) {
index 78b41451e926d5595717e197b3eb5850f7dddf0f..c3dde8040029a982b409fcdbb1244b877c5a2f20 100644 (file)
@@ -137,6 +137,10 @@ void
 lp_setup_set_flatshade_first( struct lp_setup_context *setup, 
                               boolean flatshade_first );
 
+void
+lp_setup_set_rasterizer_discard( struct lp_setup_context *setup, 
+                                 boolean rasterizer_discard );
+
 void
 lp_setup_set_vertex_info( struct lp_setup_context *setup, 
                           struct vertex_info *info );
index 6c86b4b779ac82ea6473fb2c5d0cf8a26bd22051..f810700ef296c3fd113b613cb2e52573f0c56457 100644 (file)
@@ -95,6 +95,7 @@ struct lp_setup_context
    boolean ccw_is_frontface;
    boolean scissor_test;
    boolean point_size_per_vertex;
+   boolean rasterizer_discard;
    unsigned cullmode;
    float pixel_offset;
    float line_width;
index b287ef4391b996a96e2c8264ec1a3439fc1d6ba4..9e0a5b399549985df5d2ef12e1243bb73032d4ef 100644 (file)
@@ -37,6 +37,7 @@
 
 
 #include "lp_setup_context.h"
+#include "lp_context.h"
 #include "draw/draw_vbuf.h"
 #include "draw/draw_vertex.h"
 #include "util/u_memory.h"
@@ -533,6 +534,18 @@ lp_setup_vbuf_destroy(struct vbuf_render *vbr)
    lp_setup_destroy(setup);
 }
 
+static void
+lp_setup_so_info(struct vbuf_render *vbr, uint primitives, uint vertices,
+                uint prim_generated)
+{
+   struct lp_setup_context *setup = lp_setup_context(vbr);
+   struct llvmpipe_context *lp = llvmpipe_context(setup->pipe);
+
+   lp->so_stats.num_primitives_written += primitives;
+   lp->so_stats.primitives_storage_needed =
+      vertices * 4 /*sizeof(float|int32)*/ * 4 /*x,y,z,w*/;
+   lp->num_primitives_generated += prim_generated;
+}
 
 /**
  * Create the post-transform vertex handler for the given context.
@@ -552,4 +565,5 @@ lp_setup_init_vbuf(struct lp_setup_context *setup)
    setup->base.draw_arrays = lp_setup_draw_arrays;
    setup->base.release_vertices = lp_setup_release_vertices;
    setup->base.destroy = lp_setup_vbuf_destroy;
+   setup->base.set_stream_output_info = lp_setup_so_info;
 }
index 574f9e940efe7eaa4564a385597c5680ada5992c..40ccaf66edac081c82e40f5128759f3a441f87ca 100644 (file)
@@ -114,6 +114,8 @@ llvmpipe_bind_rasterizer_state(struct pipe_context *pipe, void *handle)
                                   state->lp_state.gl_rasterization_rules);
       lp_setup_set_flatshade_first( llvmpipe->setup,
                                    state->lp_state.flatshade_first);
+      lp_setup_set_rasterizer_discard( llvmpipe->setup,
+                                   state->lp_state.rasterizer_discard);
       lp_setup_set_line_state( llvmpipe->setup,
                               state->lp_state.line_width);
       lp_setup_set_point_state( llvmpipe->setup,
index ed2272d05eefbb6df10848bd1b1ddd260b4bbe5d..58bab3964350989158f0f2d7873aa2f99e229fa2 100644 (file)
 #include "util/u_memory.h"
 #include "draw/draw_context.h"
 
-
-static void *
-llvmpipe_create_stream_output_state(struct pipe_context *pipe,
-                                    const struct pipe_stream_output_info *templ)
+static struct pipe_stream_output_target *
+llvmpipe_create_so_target(struct pipe_context *pipe,
+                          struct pipe_resource *buffer,
+                          unsigned buffer_offset,
+                          unsigned buffer_size)
 {
-   struct lp_so_state *so;
-   so = (struct lp_so_state *) CALLOC_STRUCT(lp_so_state);
-
-   if (so) {
-      so->base.num_outputs = templ->num_outputs;
-      memcpy(so->base.stride, templ->stride, sizeof(templ->stride));
-      memcpy(so->base.output, templ->output,
-             templ->num_outputs * sizeof(templ->output[0]));
-   }
-   return so;
+   struct draw_so_target *t;
+
+   t = CALLOC_STRUCT(draw_so_target);
+   if (!t)
+      return NULL;
+
+   t->target.context = pipe;
+   t->target.reference.count = 1;
+   pipe_resource_reference(&t->target.buffer, buffer);
+   t->target.buffer_offset = buffer_offset;
+   t->target.buffer_size = buffer_size;
+   return &t->target;
 }
-
 static void
-llvmpipe_bind_stream_output_state(struct pipe_context *pipe,
-                                  void *so)
+llvmpipe_so_target_destroy(struct pipe_context *pipe,
+                           struct pipe_stream_output_target *target)
 {
-   struct llvmpipe_context *lp = llvmpipe_context(pipe);
-   struct lp_so_state *lp_so = (struct lp_so_state *) so;
-
-   lp->so = lp_so;
-
-   lp->dirty |= LP_NEW_SO;
-
-   if (lp_so)
-      draw_set_so_state(lp->draw, &lp_so->base);
+   pipe_resource_reference(&target->buffer, NULL);
+   FREE(target);
 }
 
 static void
-llvmpipe_delete_stream_output_state(struct pipe_context *pipe, void *so)
+llvmpipe_set_so_targets(struct pipe_context *pipe,
+                        unsigned num_targets,
+                        struct pipe_stream_output_target **targets,
+                        unsigned append_bitmask)
 {
-   FREE( so );
-}
-
-static void
-llvmpipe_set_stream_output_buffers(struct pipe_context *pipe,
-                                   struct pipe_resource **buffers,
-                                   int *offsets,
-                                   int num_buffers)
-{
-   struct llvmpipe_context *lp = llvmpipe_context(pipe);
+   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
    int i;
-   void *map_buffers[PIPE_MAX_SO_BUFFERS];
-
-   assert(num_buffers <= PIPE_MAX_SO_BUFFERS);
-   if (num_buffers > PIPE_MAX_SO_BUFFERS)
-      num_buffers = PIPE_MAX_SO_BUFFERS;
-
-   lp->dirty |= LP_NEW_SO_BUFFERS;
-
-   for (i = 0; i < num_buffers; ++i) {
-      void *mapped;
-      struct llvmpipe_resource *res = llvmpipe_resource(buffers[i]);
-
-      if (!res) {
-         /* the whole call is invalid, bail out */
-         lp->so_target.num_buffers = 0;
-         draw_set_mapped_so_buffers(lp->draw, 0, 0);
-         return;
-      }
-
-      lp->so_target.buffer[i] = res;
-      lp->so_target.offset[i] = offsets[i];
-      lp->so_target.so_count[i] = 0;
-
-      mapped = res->data;
-      if (offsets[i] >= 0)
-         map_buffers[i] = ((char*)mapped) + offsets[i];
-      else {
-         /* this is a buffer append */
-         assert(!"appending not implemented");
-         map_buffers[i] = mapped;
-      }
+   for (i = 0; i < num_targets; i++) {
+      pipe_so_target_reference((struct pipe_stream_output_target **)&llvmpipe->so_targets[i], targets[i]);
    }
-   lp->so_target.num_buffers = num_buffers;
 
-   draw_set_mapped_so_buffers(lp->draw, map_buffers, num_buffers);
+   for (; i < llvmpipe->num_so_targets; i++) {
+      pipe_so_target_reference((struct pipe_stream_output_target **)&llvmpipe->so_targets[i], NULL);
+   }
+   llvmpipe->num_so_targets = num_targets;
 }
 
 void
-llvmpipe_init_so_funcs(struct llvmpipe_context *llvmpipe)
+llvmpipe_init_so_funcs(struct llvmpipe_context *pipe)
 {
-#if 0
-   llvmpipe->pipe.create_stream_output_state =
-      llvmpipe_create_stream_output_state;
-   llvmpipe->pipe.bind_stream_output_state =
-      llvmpipe_bind_stream_output_state;
-   llvmpipe->pipe.delete_stream_output_state =
-      llvmpipe_delete_stream_output_state;
-
-   llvmpipe->pipe.set_stream_output_buffers =
-      llvmpipe_set_stream_output_buffers;
-#else
-   (void) llvmpipe_create_stream_output_state;
-   (void) llvmpipe_bind_stream_output_state;
-   (void) llvmpipe_delete_stream_output_state;
-   (void) llvmpipe_set_stream_output_buffers;
-#endif
+   pipe->pipe.create_stream_output_target = llvmpipe_create_so_target;
+   pipe->pipe.stream_output_target_destroy = llvmpipe_so_target_destroy;
+   pipe->pipe.set_stream_output_targets = llvmpipe_set_so_targets;
 }
index e42f4c838e93fb95bdd9bc2272ca479f4f85a376..11475fd447c296491bc8da4c80e4cefaef9489fe 100644 (file)
@@ -208,8 +208,8 @@ static void lp_blit(struct pipe_context *pipe,
    util_blitter_save_vertex_elements(lp->blitter, (void*)lp->velems);
    util_blitter_save_vertex_shader(lp->blitter, (void*)lp->vs);
    util_blitter_save_geometry_shader(lp->blitter, (void*)lp->gs);
-   /*util_blitter_save_so_targets(lp->blitter, lp->num_so_targets,
-                     (struct pipe_stream_output_target**)lp->so_targets);*/
+   util_blitter_save_so_targets(lp->blitter, lp->num_so_targets,
+                                (struct pipe_stream_output_target**)lp->so_targets);
    util_blitter_save_rasterizer(lp->blitter, (void*)lp->rasterizer);
    util_blitter_save_viewport(lp->blitter, &lp->viewport);
    util_blitter_save_scissor(lp->blitter, &lp->scissor);