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>
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];
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;
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]);
if (mapped_indices) {
draw_set_indexes(draw, NULL, 0);
}
+ draw_set_mapped_so_targets(draw, 0, NULL);
+
llvmpipe_cleanup_vertex_sampling(lp);
/*
*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;
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;
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;
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;
};
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;
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;
{
task->scene = scene;
- if (!task->rast->no_rast) {
+ if (!task->rast->no_rast && !scene->discard) {
/* loop over scene bins, rasterize each */
#if 0
{
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;
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
*/
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 );
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:
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:
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);
lp_fence_wait(setup->scene->fence);
}
- lp_scene_begin_binning(setup->scene, &setup->fb);
+ lp_scene_begin_binning(setup->scene, &setup->fb, discard);
}
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,
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) {
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 );
boolean ccw_is_frontface;
boolean scissor_test;
boolean point_size_per_vertex;
+ boolean rasterizer_discard;
unsigned cullmode;
float pixel_offset;
float line_width;
#include "lp_setup_context.h"
+#include "lp_context.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "util/u_memory.h"
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.
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;
}
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,
#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;
}
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);