From: Brian Paul Date: Fri, 7 Dec 2012 20:58:34 +0000 (-0700) Subject: draw: fix/improve dirty state validation X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4b73cdb864aef6d64c35a7ab9a59e4ee4e3f9d0f;p=mesa.git draw: fix/improve dirty state validation 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. Reviewed-by: Jose Fonseca --- diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index c231aba1963..bc2f0e1d03f 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 ac449b75f00..f1ee6cb1b0a 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 e52b3fda0ec..2223fcb3f40 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 7113b9e0f2d..ddaedcdab5e 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 2c2efdc1c59..7d07363068e 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 a6f5484fcf4..d1b76b12b02 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 2230a7e5fa3..bfad54bb36e 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 0fed057efbe..c2d2a8fd555 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; }