From fbc51c4c956bb681c52e3163f73051303b24d8b8 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 4 Dec 2018 15:34:30 -0800 Subject: [PATCH] iris: Defer uploading sampler state tables until draw time MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Gallium might call us multiple times to bind subsets of the samplers, at which point we'd recreate the table a bunch of times. It doesn't really buy us anything to do it here - even if we defer to draw time, the dirty tracking ensures we'll only do it on the first draw after a bind_sampler_states() call. We now use the number of samplers specified by the shader instead of the binding count. If this number changes, we flag sampler state as dirty so we re-upload a table with the right number of entries. This also fixes a bug where ice->state.need_border_colors was never unset, so once something needed border colors, the pool would always be pinned in all future batches. v2: Explicitly flag sampler states as dirty, rather than assuming that bind_sampler_states() will be called if the program texture count changes. While this may be true for st/mesa, it isn't the case for Gallium HUD. Tested-by: Timur Kristóf Tested-by: Andre Heider Reviewed-by: Jason Ekstrand --- src/gallium/drivers/iris/iris_context.h | 4 +- src/gallium/drivers/iris/iris_program.c | 8 ++++ src/gallium/drivers/iris/iris_state.c | 52 ++++++++++++++++--------- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h index 771c47ffced..70a929178df 100644 --- a/src/gallium/drivers/iris/iris_context.h +++ b/src/gallium/drivers/iris/iris_context.h @@ -575,8 +575,8 @@ struct iris_context { /** Do vertex shader uses edge flag ? */ bool vs_needs_edge_flag; - /** Do any samplers (for any stage) need border color? */ - bool need_border_colors; + /** Do any samplers need border color? One bit per shader stage. */ + uint8_t need_border_colors; struct pipe_stream_output_target *so_target[PIPE_MAX_SO_BUFFERS]; bool streamout_active; diff --git a/src/gallium/drivers/iris/iris_program.c b/src/gallium/drivers/iris/iris_program.c index 0ceaeb22d27..9d1664029d9 100644 --- a/src/gallium/drivers/iris/iris_program.c +++ b/src/gallium/drivers/iris/iris_program.c @@ -1614,6 +1614,14 @@ bind_state(struct iris_context *ice, uint64_t dirty_bit = IRIS_DIRTY_UNCOMPILED_VS << stage; const uint64_t nos = ish ? ish->nos : 0; + const struct shader_info *old_info = iris_get_shader_info(ice, stage); + const struct shader_info *new_info = ish ? &ish->nir->info : NULL; + + if ((old_info ? util_last_bit(old_info->textures_used) : 0) != + (new_info ? util_last_bit(new_info->textures_used) : 0)) { + ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage; + } + ice->shaders.uncompiled[stage] = ish; ice->state.dirty |= dirty_bit; diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 7e1ead70797..0483bb8caa0 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -1437,19 +1437,7 @@ iris_create_sampler_state(struct pipe_context *ctx, /** * The pipe->bind_sampler_states() driver hook. - * - * Now that we know all the sampler states, we upload them all into a - * contiguous area of GPU memory, for 3DSTATE_SAMPLER_STATE_POINTERS_*. - * We also fill out the border color state pointers at this point. - * - * We could defer this work to draw time, but we assume that binding - * will be less frequent than drawing. */ -// XXX: this may be a bad idea, need to make sure that st/mesa calls us -// XXX: with the complete set of shaders. If it makes multiple calls to -// XXX: things one at a time, we could waste a lot of time assembling things. -// XXX: it doesn't even BUY us anything to do it here, because we only flag -// XXX: IRIS_DIRTY_SAMPLER_STATE when this is called... static void iris_bind_sampler_states(struct pipe_context *ctx, enum pipe_shader_type p_stage, @@ -1466,6 +1454,29 @@ iris_bind_sampler_states(struct pipe_context *ctx, shs->samplers[start + i] = states[i]; } + ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage; +} + +/** + * Upload the sampler states into a contiguous area of GPU memory, for + * for 3DSTATE_SAMPLER_STATE_POINTERS_*. + * + * Also fill out the border color state pointers. + */ +static void +iris_upload_sampler_states(struct iris_context *ice, gl_shader_stage stage) +{ + struct iris_shader_state *shs = &ice->state.shaders[stage]; + const struct shader_info *info = iris_get_shader_info(ice, stage); + + /* We assume the state tracker will call pipe->bind_sampler_states() + * if the program's number of textures changes. + */ + unsigned count = info ? util_last_bit(info->textures_used) : 0; + + if (!count) + return; + /* Assemble the SAMPLER_STATEs into a contiguous table that lives * in the dynamic state memory zone, so we can point to it via the * 3DSTATE_SAMPLER_STATE_POINTERS_* commands. @@ -1483,6 +1494,8 @@ iris_bind_sampler_states(struct pipe_context *ctx, /* Make sure all land in the same BO */ iris_border_color_pool_reserve(ice, IRIS_MAX_TEXTURE_SAMPLERS); + ice->state.need_border_colors &= ~(1 << stage); + for (int i = 0; i < count; i++) { struct iris_sampler_state *state = shs->samplers[i]; @@ -1491,7 +1504,7 @@ iris_bind_sampler_states(struct pipe_context *ctx, } else if (!state->needs_border_color) { memcpy(map, state->sampler_state, 4 * GENX(SAMPLER_STATE_length)); } else { - ice->state.need_border_colors = true; + ice->state.need_border_colors |= 1 << stage; /* Stream out the border color and merge the pointer. */ uint32_t offset = @@ -1508,8 +1521,6 @@ iris_bind_sampler_states(struct pipe_context *ctx, map += GENX(SAMPLER_STATE_length); } - - ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage; } static enum isl_channel_select @@ -4439,14 +4450,13 @@ iris_upload_dirty_render_state(struct iris_context *ice, } } - if (ice->state.need_border_colors) - iris_use_pinned_bo(batch, ice->state.border_color_pool.bo, false); - for (int stage = 0; stage <= MESA_SHADER_FRAGMENT; stage++) { if (!(dirty & (IRIS_DIRTY_SAMPLER_STATES_VS << stage)) || !ice->shaders.prog[stage]) continue; + iris_upload_sampler_states(ice, stage); + struct iris_shader_state *shs = &ice->state.shaders[stage]; struct pipe_resource *res = shs->sampler_table.res; if (res) @@ -4458,6 +4468,9 @@ iris_upload_dirty_render_state(struct iris_context *ice, } } + if (ice->state.need_border_colors) + iris_use_pinned_bo(batch, ice->state.border_color_pool.bo, false); + if (dirty & IRIS_DIRTY_MULTISAMPLE) { iris_emit_cmd(batch, GENX(3DSTATE_MULTISAMPLE), ms) { ms.PixelLocation = @@ -5101,6 +5114,9 @@ iris_upload_compute_state(struct iris_context *ice, if (dirty & IRIS_DIRTY_BINDINGS_CS) iris_populate_binding_table(ice, batch, MESA_SHADER_COMPUTE, false); + if (dirty & IRIS_DIRTY_SAMPLER_STATES_CS) + iris_upload_sampler_states(ice, MESA_SHADER_COMPUTE); + iris_use_optional_res(batch, shs->sampler_table.res, false); iris_use_pinned_bo(batch, iris_resource_bo(shader->assembly.res), false); -- 2.30.2