From 77b26564c3f0395bf3e744abbf6d0e7aa9d2c8da Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 5 Dec 2012 06:50:07 +1000 Subject: [PATCH] llvmpipe: EXT_transform_feedback support (v1.1) 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 Signed-off-by: Dave Airlie --- src/gallium/drivers/llvmpipe/lp_context.h | 11 +- src/gallium/drivers/llvmpipe/lp_draw_arrays.c | 9 ++ src/gallium/drivers/llvmpipe/lp_query.c | 24 ++++ src/gallium/drivers/llvmpipe/lp_query.h | 2 + src/gallium/drivers/llvmpipe/lp_rast.c | 8 +- src/gallium/drivers/llvmpipe/lp_scene.c | 3 +- src/gallium/drivers/llvmpipe/lp_scene.h | 5 +- src/gallium/drivers/llvmpipe/lp_screen.c | 3 +- src/gallium/drivers/llvmpipe/lp_setup.c | 12 +- src/gallium/drivers/llvmpipe/lp_setup.h | 4 + .../drivers/llvmpipe/lp_setup_context.h | 1 + src/gallium/drivers/llvmpipe/lp_setup_vbuf.c | 14 ++ .../drivers/llvmpipe/lp_state_rasterizer.c | 2 + src/gallium/drivers/llvmpipe/lp_state_so.c | 124 ++++++------------ src/gallium/drivers/llvmpipe/lp_surface.c | 4 +- 15 files changed, 125 insertions(+), 101 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index fe6fa3f9390..25cdff998c4 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c index 3497edf9d1c..eaa9ba3b130 100644 --- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c +++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c @@ -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); /* diff --git a/src/gallium/drivers/llvmpipe/lp_query.c b/src/gallium/drivers/llvmpipe/lp_query.c index e3021972566..7a62a809d58 100644 --- a/src/gallium/drivers/llvmpipe/lp_query.c +++ b/src/gallium/drivers/llvmpipe/lp_query.c @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_query.h b/src/gallium/drivers/llvmpipe/lp_query.h index cacbd9d0b8c..19d977fd2e4 100644 --- a/src/gallium/drivers/llvmpipe/lp_query.h +++ b/src/gallium/drivers/llvmpipe/lp_query.h @@ -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; }; diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c b/src/gallium/drivers/llvmpipe/lp_rast.c index 40a8591cabe..37be6ad571d 100644 --- a/src/gallium/drivers/llvmpipe/lp_rast.c +++ b/src/gallium/drivers/llvmpipe/lp_rast.c @@ -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 { diff --git a/src/gallium/drivers/llvmpipe/lp_scene.c b/src/gallium/drivers/llvmpipe/lp_scene.c index ed998246fb9..328c0f74572 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.c +++ b/src/gallium/drivers/llvmpipe/lp_scene.c @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_scene.h b/src/gallium/drivers/llvmpipe/lp_scene.h index 31a5ae72b37..b1db61bd5a3 100644 --- a/src/gallium/drivers/llvmpipe/lp_scene.h +++ b/src/gallium/drivers/llvmpipe/lp_scene.h @@ -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 ); diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index acbde9da983..61228f6ed40 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -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: diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 1d71a87319e..25e5da84ebb 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -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) { diff --git a/src/gallium/drivers/llvmpipe/lp_setup.h b/src/gallium/drivers/llvmpipe/lp_setup.h index 78b41451e92..c3dde804002 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.h +++ b/src/gallium/drivers/llvmpipe/lp_setup.h @@ -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 ); diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index 6c86b4b779a..f810700ef29 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -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; diff --git a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c index b287ef4391b..9e0a5b39954 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c @@ -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; } diff --git a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c index 574f9e940ef..40ccaf66eda 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c +++ b/src/gallium/drivers/llvmpipe/lp_state_rasterizer.c @@ -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, diff --git a/src/gallium/drivers/llvmpipe/lp_state_so.c b/src/gallium/drivers/llvmpipe/lp_state_so.c index ed2272d05ee..58bab396435 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_so.c +++ b/src/gallium/drivers/llvmpipe/lp_state_so.c @@ -32,106 +32,56 @@ #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; } diff --git a/src/gallium/drivers/llvmpipe/lp_surface.c b/src/gallium/drivers/llvmpipe/lp_surface.c index e42f4c838e9..11475fd447c 100644 --- a/src/gallium/drivers/llvmpipe/lp_surface.c +++ b/src/gallium/drivers/llvmpipe/lp_surface.c @@ -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); -- 2.30.2