[Mesa-dev] [PATCH 6/6] draw: fix/improve dirty state validation
Jose Fonseca
jfonseca at vmware.com
Sat Dec 8 02:48:29 PST 2012
Reviewed-by: Jose Fonseca <jfonseca at vmware.com>
Series looks excellent Brian. Thanks for nailing this issue. I never stop to be amazed on how state derivation bugs go unnoticed for so long, just because most apps ends up touch a lot of state at the same time. One could try to write piglit tests that draw something, change one bit of state, re-draw, but it would take a lot of tests to cover everything.
Slight different issue -- you originally were looking into draw module and user buffer pointers -- is draw module actually properly flushing whenever user buffers are used? Or is that still outstanding?
Jose
----- Original Message -----
> This patch does two things:
>
> 1. Constant buffer state changes were broken (but happened to work by
> dumb luck). The problem is we weren't calling draw_do_flush() in
> draw_set_mapped_constant_buffer() when we changed that state. All
> the
> other draw_set_foo() functions were calling draw_do_flush()
> already.
>
> 2. Use a simpler state validation step when we're changing
> light-weight
> parameter state such as constant buffers, viewport dims or clip
> planes.
> There's no need to revalidate the whole pipeline when changing
> state
> like that. The new validation method is called bind_parameters()
> and is called instead of the prepare() method. A new
> DRAW_FLUSH_PARAMETER_CHANGE flag is used to signal these
> light-weight
> state changes. This results in a modest but measurable increase
> in
> FPS for many Mesa demos.
> ---
> src/gallium/auxiliary/draw/draw_context.c | 6 ++-
> src/gallium/auxiliary/draw/draw_pipe.c | 2 +-
> src/gallium/auxiliary/draw/draw_private.h | 7 ++-
> src/gallium/auxiliary/draw/draw_pt.c | 14 ++++++-
> src/gallium/auxiliary/draw/draw_pt.h | 7 +++
> .../auxiliary/draw/draw_pt_fetch_shade_pipeline.c | 10 +++++
> .../draw/draw_pt_fetch_shade_pipeline_llvm.c | 43
> ++++++++++++-------
> src/gallium/auxiliary/draw/draw_pt_vsplit.c | 2 +-
> 8 files changed, 68 insertions(+), 23 deletions(-)
>
> diff --git a/src/gallium/auxiliary/draw/draw_context.c
> b/src/gallium/auxiliary/draw/draw_context.c
> index c231aba..bc2f0e1 100644
> --- a/src/gallium/auxiliary/draw/draw_context.c
> +++ b/src/gallium/auxiliary/draw/draw_context.c
> @@ -289,7 +289,7 @@ void draw_set_rasterize_stage( struct
> draw_context *draw,
> void draw_set_clip_state( struct draw_context *draw,
> const struct pipe_clip_state *clip )
> {
> - draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
> + draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
>
> memcpy(&draw->plane[6], clip->ucp, sizeof(clip->ucp));
> }
> @@ -301,7 +301,7 @@ void draw_set_clip_state( struct draw_context
> *draw,
> void draw_set_viewport_state( struct draw_context *draw,
> const struct pipe_viewport_state
> *viewport )
> {
> - draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
> + draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
> draw->viewport = *viewport; /* struct copy */
> draw->identity_viewport = (viewport->scale[0] == 1.0f &&
> viewport->scale[1] == 1.0f &&
> @@ -368,6 +368,8 @@ draw_set_mapped_constant_buffer(struct
> draw_context *draw,
> shader_type == PIPE_SHADER_GEOMETRY);
> debug_assert(slot < PIPE_MAX_CONSTANT_BUFFERS);
>
> + draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
> +
> switch (shader_type) {
> case PIPE_SHADER_VERTEX:
> draw->pt.user.vs_constants[slot] = buffer;
> diff --git a/src/gallium/auxiliary/draw/draw_pipe.c
> b/src/gallium/auxiliary/draw/draw_pipe.c
> index ac449b7..f1ee6cb 100644
> --- a/src/gallium/auxiliary/draw/draw_pipe.c
> +++ b/src/gallium/auxiliary/draw/draw_pipe.c
> @@ -347,6 +347,6 @@ void draw_pipeline_flush( struct draw_context
> *draw,
> unsigned flags )
> {
> draw->pipeline.first->flush( draw->pipeline.first, flags );
> - if (!(flags & DRAW_FLUSH_BACKEND))
> + if (flags & DRAW_FLUSH_STATE_CHANGE)
> draw->pipeline.first = draw->pipeline.validate;
> }
> diff --git a/src/gallium/auxiliary/draw/draw_private.h
> b/src/gallium/auxiliary/draw/draw_private.h
> index e52b3fd..2223fcb 100644
> --- a/src/gallium/auxiliary/draw/draw_private.h
> +++ b/src/gallium/auxiliary/draw/draw_private.h
> @@ -144,6 +144,8 @@ struct draw_context
> unsigned opt; /**< bitmask of PT_x flags */
> unsigned eltSize; /* saved eltSize for flushing */
>
> + boolean rebind_parameters;
> +
> struct {
> struct draw_pt_middle_end *fetch_emit;
> struct draw_pt_middle_end *fetch_shade_emit;
> @@ -434,8 +436,9 @@ void draw_pipeline_flush( struct draw_context
> *draw,
> * Flushing
> */
>
> -#define DRAW_FLUSH_STATE_CHANGE 0x8
> -#define DRAW_FLUSH_BACKEND 0x10
> +#define DRAW_FLUSH_PARAMETER_CHANGE 0x1 /**< Constants, viewport,
> etc */
> +#define DRAW_FLUSH_STATE_CHANGE 0x2 /**< Other/heavy state
> changes */
> +#define DRAW_FLUSH_BACKEND 0x4 /**< Flush the output
> buffer */
>
>
> void draw_do_flush( struct draw_context *draw, unsigned flags );
> diff --git a/src/gallium/auxiliary/draw/draw_pt.c
> b/src/gallium/auxiliary/draw/draw_pt.c
> index 7113b9e..ddaedcd 100644
> --- a/src/gallium/auxiliary/draw/draw_pt.c
> +++ b/src/gallium/auxiliary/draw/draw_pt.c
> @@ -139,6 +139,12 @@ draw_pt_arrays(struct draw_context *draw,
> draw->pt.opt = opt;
> }
>
> + if (draw->pt.rebind_parameters) {
> + /* update constants, viewport dims, clip planes, etc */
> + middle->bind_parameters(middle);
> + draw->pt.rebind_parameters = FALSE;
> + }
> +
> frontend->run( frontend, start, count );
>
> return TRUE;
> @@ -146,13 +152,19 @@ draw_pt_arrays(struct draw_context *draw,
>
> void draw_pt_flush( struct draw_context *draw, unsigned flags )
> {
> + assert(flags);
> +
> if (draw->pt.frontend) {
> draw->pt.frontend->flush( draw->pt.frontend, flags );
>
> /* don't prepare if we only are flushing the backend */
> - if (!(flags & DRAW_FLUSH_BACKEND))
> + if (flags & DRAW_FLUSH_STATE_CHANGE)
> draw->pt.frontend = NULL;
> }
> +
> + if (flags & DRAW_FLUSH_PARAMETER_CHANGE) {
> + draw->pt.rebind_parameters = TRUE;
> + }
> }
>
>
> diff --git a/src/gallium/auxiliary/draw/draw_pt.h
> b/src/gallium/auxiliary/draw/draw_pt.h
> index 2c2efdc..7d07363 100644
> --- a/src/gallium/auxiliary/draw/draw_pt.h
> +++ b/src/gallium/auxiliary/draw/draw_pt.h
> @@ -93,6 +93,13 @@ struct draw_pt_middle_end {
> unsigned opt,
> unsigned *max_vertices );
>
> + /**
> + * Bind/update parameter state such as constants, viewport dims
> + * and clip planes. Basically, stuff which isn't "baked" into
> the
> + * shader or pipeline state.
> + */
> + void (*bind_parameters)(struct draw_pt_middle_end *);
> +
> void (*run)( struct draw_pt_middle_end *,
> const unsigned *fetch_elts,
> unsigned fetch_count,
> diff --git
> a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> index a6f5484..d1b76b1 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> @@ -137,6 +137,15 @@ static void fetch_pipeline_prepare( struct
> draw_pt_middle_end *middle,
> }
>
>
> +static void
> +fetch_pipeline_bind_parameters(struct draw_pt_middle_end *middle)
> +{
> + /* No-op since the vertex shader executor and drawing pipeline
> + * just grab the constants, viewport, etc. from the draw context
> state.
> + */
> +}
> +
> +
> static void fetch( struct pt_fetch *fetch,
> const struct draw_fetch_info *fetch_info,
> char *output)
> @@ -421,6 +430,7 @@ struct draw_pt_middle_end
> *draw_pt_fetch_pipeline_or_emit( struct draw_context *
> goto fail;
>
> fpme->base.prepare = fetch_pipeline_prepare;
> + fpme->base.bind_parameters = fetch_pipeline_bind_parameters;
> fpme->base.run = fetch_pipeline_run;
> fpme->base.run_linear = fetch_pipeline_linear_run;
> fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
> diff --git
> a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> index 2230a7e..bfad54b 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> @@ -180,24 +180,34 @@ llvm_middle_end_prepare( struct
> draw_pt_middle_end *middle,
>
> fpme->current_variant = variant;
> }
> +}
>
> - /* Bind the VS and GS input constants, clip planes and viewport
> */
> - {
> - unsigned i;
>
> - for (i = 0; i <
> Elements(fpme->llvm->jit_context.vs_constants); ++i) {
> - fpme->llvm->jit_context.vs_constants[i] =
> - draw->pt.user.vs_constants[i];
> - }
> - for (i = 0; i <
> Elements(fpme->llvm->jit_context.gs_constants); ++i) {
> - fpme->llvm->jit_context.gs_constants[i] =
> - draw->pt.user.gs_constants[i];
> - }
> - fpme->llvm->jit_context.planes =
> - (float (*) [DRAW_TOTAL_CLIP_PLANES][4])
> draw->pt.user.planes[0];
> - fpme->llvm->jit_context.viewport =
> - (float *) draw->viewport.scale;
> - }
> +/**
> + * Bind/update constant buffer pointers, clip planes and viewport
> dims.
> + * These are "light weight" parameters which aren't baked into the
> + * generated code. Updating these items is much cheaper than
> revalidating
> + * and rebuilding the generated pipeline code.
> + */
> +static void
> +llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
> +{
> + struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
> + struct draw_context *draw = fpme->draw;
> + unsigned i;
> +
> + for (i = 0; i < Elements(fpme->llvm->jit_context.vs_constants);
> ++i) {
> + fpme->llvm->jit_context.vs_constants[i] =
> draw->pt.user.vs_constants[i];
> + }
> +
> + for (i = 0; i < Elements(fpme->llvm->jit_context.gs_constants);
> ++i) {
> + fpme->llvm->jit_context.gs_constants[i] =
> draw->pt.user.gs_constants[i];
> + }
> +
> + fpme->llvm->jit_context.planes =
> + (float (*)[DRAW_TOTAL_CLIP_PLANES][4])
> draw->pt.user.planes[0];
> +
> + fpme->llvm->jit_context.viewport = (float *)
> draw->viewport.scale;
> }
>
>
> @@ -448,6 +458,7 @@ draw_pt_fetch_pipeline_or_emit_llvm(struct
> draw_context *draw)
> goto fail;
>
> fpme->base.prepare = llvm_middle_end_prepare;
> + fpme->base.bind_parameters = llvm_middle_end_bind_parameters;
> fpme->base.run = llvm_middle_end_run;
> fpme->base.run_linear = llvm_middle_end_linear_run;
> fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
> diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> b/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> index 0fed057..c2d2a8f 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> @@ -182,7 +182,7 @@ static void vsplit_flush(struct draw_pt_front_end
> *frontend, unsigned flags)
> {
> struct vsplit_frontend *vsplit = (struct vsplit_frontend *)
> frontend;
>
> - if (!(flags & DRAW_FLUSH_BACKEND)) {
> + if (flags & DRAW_FLUSH_STATE_CHANGE) {
> vsplit->middle->finish(vsplit->middle);
> vsplit->middle = NULL;
> }
> --
> 1.7.3.4
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
More information about the mesa-dev
mailing list