r600: Add shader precompile and shader-db support.

This should reduce draw-time jank, and was useful for me in evaluating
NIR-to-TGSI's impact for r600.

Acked-by: Gert Wollny <gert.wollny@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14427>
This commit is contained in:
Emma Anholt 2022-01-06 10:28:02 -08:00 committed by Marge Bot
parent f07b8a0cac
commit 28d6a5af25
5 changed files with 78 additions and 6 deletions

View file

@ -444,6 +444,13 @@ static void *evergreen_create_compute_state(struct pipe_context *ctx,
if (shader->ir_type == PIPE_SHADER_IR_TGSI || if (shader->ir_type == PIPE_SHADER_IR_TGSI ||
shader->ir_type == PIPE_SHADER_IR_NIR) { shader->ir_type == PIPE_SHADER_IR_NIR) {
shader->sel = r600_create_shader_state_tokens(ctx, cso->prog, cso->ir_type, PIPE_SHADER_COMPUTE); shader->sel = r600_create_shader_state_tokens(ctx, cso->prog, cso->ir_type, PIPE_SHADER_COMPUTE);
/* Precompile the shader with the expected shader key, to reduce jank at
* draw time. Also produces output for shader-db.
*/
bool dirty;
r600_shader_select(ctx, shader->sel, &dirty, true);
return shader; return shader;
} }
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
@ -506,7 +513,7 @@ static void evergreen_bind_compute_state(struct pipe_context *ctx, void *state)
cstate->ir_type == PIPE_SHADER_IR_NIR) { cstate->ir_type == PIPE_SHADER_IR_NIR) {
bool compute_dirty; bool compute_dirty;
cstate->sel->ir_type = cstate->ir_type; cstate->sel->ir_type = cstate->ir_type;
if (r600_shader_select(ctx, cstate->sel, &compute_dirty)) if (r600_shader_select(ctx, cstate->sel, &compute_dirty, false))
R600_ERR("Failed to select compute shader\n"); R600_ERR("Failed to select compute shader\n");
} }
@ -736,7 +743,7 @@ static void compute_emit_cs(struct r600_context *rctx,
if (rctx->cs_shader_state.shader->ir_type == PIPE_SHADER_IR_TGSI|| if (rctx->cs_shader_state.shader->ir_type == PIPE_SHADER_IR_TGSI||
rctx->cs_shader_state.shader->ir_type == PIPE_SHADER_IR_NIR) { rctx->cs_shader_state.shader->ir_type == PIPE_SHADER_IR_NIR) {
if (r600_shader_select(&rctx->b.b, rctx->cs_shader_state.shader->sel, &compute_dirty)) { if (r600_shader_select(&rctx->b.b, rctx->cs_shader_state.shader->sel, &compute_dirty, false)) {
R600_ERR("Failed to select compute shader\n"); R600_ERR("Failed to select compute shader\n");
return; return;
} }

View file

@ -1065,7 +1065,7 @@ struct r600_pipe_shader_selector *r600_create_shader_state_tokens(struct pipe_co
unsigned pipe_shader_type); unsigned pipe_shader_type);
int r600_shader_select(struct pipe_context *ctx, int r600_shader_select(struct pipe_context *ctx,
struct r600_pipe_shader_selector* sel, struct r600_pipe_shader_selector* sel,
bool *dirty); bool *dirty, bool precompile);
void r600_delete_shader_selector(struct pipe_context *ctx, void r600_delete_shader_selector(struct pipe_context *ctx,
struct r600_pipe_shader_selector *sel); struct r600_pipe_shader_selector *sel);

View file

@ -372,6 +372,15 @@ int r600_pipe_shader_create(struct pipe_context *ctx,
r = -EINVAL; r = -EINVAL;
goto error; goto error;
} }
pipe_debug_message(&rctx->b.debug, SHADER_INFO, "%s shader: %d dw, %d gprs, %d loops, %d cf, %d stack",
_mesa_shader_stage_to_abbrev(tgsi_processor_to_shader_stage(processor)),
shader->shader.bc.ndw,
shader->shader.bc.ngpr,
shader->shader.num_loops,
shader->shader.bc.ncf,
shader->shader.bc.nstack);
return 0; return 0;
error: error:
@ -3451,6 +3460,8 @@ static int r600_shader_from_tgsi(struct r600_context *rctx,
shader->uses_helper_invocation = false; shader->uses_helper_invocation = false;
shader->uses_doubles = ctx.info.uses_doubles; shader->uses_doubles = ctx.info.uses_doubles;
shader->uses_atomics = ctx.info.file_mask[TGSI_FILE_HW_ATOMIC]; shader->uses_atomics = ctx.info.file_mask[TGSI_FILE_HW_ATOMIC];
shader->num_loops = ctx.info.opcode_count[TGSI_OPCODE_BGNLOOP];
shader->nsys_inputs = 0; shader->nsys_inputs = 0;
shader->uses_images = ctx.info.file_count[TGSI_FILE_IMAGE] > 0 || shader->uses_images = ctx.info.file_count[TGSI_FILE_IMAGE] > 0 ||

View file

@ -114,6 +114,8 @@ struct r600_shader {
unsigned tes_as_es; unsigned tes_as_es;
unsigned tcs_prim_mode; unsigned tcs_prim_mode;
unsigned ps_prim_id_input; unsigned ps_prim_id_input;
unsigned num_loops;
struct r600_shader_array * arrays; struct r600_shader_array * arrays;
boolean uses_doubles; boolean uses_doubles;

View file

@ -867,17 +867,63 @@ static inline void r600_shader_selector_key(const struct pipe_context *ctx,
} }
} }
static void
r600_shader_precompile_key(const struct pipe_context *ctx,
const struct r600_pipe_shader_selector *sel,
union r600_shader_key *key)
{
memset(key, 0, sizeof(*key));
switch (sel->type) {
case PIPE_SHADER_VERTEX:
case PIPE_SHADER_TESS_EVAL:
/* Assume no tess or GS for setting .as_es. In order to
* precompile with es, we'd need the other shaders we're linked
* with (see the link_shader screen method)
*/
break;
case PIPE_SHADER_GEOMETRY:
break;
case PIPE_SHADER_FRAGMENT:
key->ps.image_size_const_offset = sel->info.file_max[TGSI_FILE_IMAGE];
/* This is used for gl_FragColor output expansion to the number
* of color buffers bound, but also with sb it'll drop outputs
* to unused cbufs.
*/
key->ps.nr_cbufs = sel->info.file_max[TGSI_FILE_OUTPUT] + 1;
break;
case PIPE_SHADER_TESS_CTRL:
/* Prim mode comes from the TES, but we need some valid value. */
key->tcs.prim_mode = PIPE_PRIM_TRIANGLES;
break;
case PIPE_SHADER_COMPUTE:
break;
default:
unreachable("bad shader stage");
break;
}
}
/* Select the hw shader variant depending on the current state. /* Select the hw shader variant depending on the current state.
* (*dirty) is set to 1 if current variant was changed */ * (*dirty) is set to 1 if current variant was changed */
int r600_shader_select(struct pipe_context *ctx, int r600_shader_select(struct pipe_context *ctx,
struct r600_pipe_shader_selector* sel, struct r600_pipe_shader_selector* sel,
bool *dirty) bool *dirty, bool precompile)
{ {
union r600_shader_key key; union r600_shader_key key;
struct r600_pipe_shader * shader = NULL; struct r600_pipe_shader * shader = NULL;
int r; int r;
r600_shader_selector_key(ctx, sel, &key); if (precompile)
r600_shader_precompile_key(ctx, sel, &key);
else
r600_shader_selector_key(ctx, sel, &key);
/* Check if we don't need to change anything. /* Check if we don't need to change anything.
* This path is also used for most shaders that don't need multiple * This path is also used for most shaders that don't need multiple
@ -997,6 +1043,12 @@ static void *r600_create_shader_state(struct pipe_context *ctx,
break; break;
} }
/* Precompile the shader with the expected shader key, to reduce jank at
* draw time. Also produces output for shader-db.
*/
bool dirty;
r600_shader_select(ctx, sel, &dirty, true);
return sel; return sel;
} }
@ -1771,7 +1823,7 @@ void r600_setup_scratch_buffers(struct r600_context *rctx) {
} }
#define SELECT_SHADER_OR_FAIL(x) do { \ #define SELECT_SHADER_OR_FAIL(x) do { \
r600_shader_select(ctx, rctx->x##_shader, &x##_dirty); \ r600_shader_select(ctx, rctx->x##_shader, &x##_dirty, false); \
if (unlikely(!rctx->x##_shader->current)) \ if (unlikely(!rctx->x##_shader->current)) \
return false; \ return false; \
} while(0) } while(0)