diff --git a/src/gallium/drivers/r600/evergreen_compute.c b/src/gallium/drivers/r600/evergreen_compute.c index 48d8982d58a..7ddee6ea630 100644 --- a/src/gallium/drivers/r600/evergreen_compute.c +++ b/src/gallium/drivers/r600/evergreen_compute.c @@ -444,6 +444,13 @@ static void *evergreen_create_compute_state(struct pipe_context *ctx, if (shader->ir_type == PIPE_SHADER_IR_TGSI || shader->ir_type == PIPE_SHADER_IR_NIR) { 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; } #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) { bool compute_dirty; 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"); } @@ -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|| 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"); return; } diff --git a/src/gallium/drivers/r600/r600_pipe.h b/src/gallium/drivers/r600/r600_pipe.h index 6418ee5d172..93804a88b98 100644 --- a/src/gallium/drivers/r600/r600_pipe.h +++ b/src/gallium/drivers/r600/r600_pipe.h @@ -1065,7 +1065,7 @@ struct r600_pipe_shader_selector *r600_create_shader_state_tokens(struct pipe_co unsigned pipe_shader_type); int r600_shader_select(struct pipe_context *ctx, struct r600_pipe_shader_selector* sel, - bool *dirty); + bool *dirty, bool precompile); void r600_delete_shader_selector(struct pipe_context *ctx, struct r600_pipe_shader_selector *sel); diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 0858a867679..4518d9e892b 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -372,6 +372,15 @@ int r600_pipe_shader_create(struct pipe_context *ctx, r = -EINVAL; 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; error: @@ -3451,6 +3460,8 @@ static int r600_shader_from_tgsi(struct r600_context *rctx, shader->uses_helper_invocation = false; shader->uses_doubles = ctx.info.uses_doubles; 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->uses_images = ctx.info.file_count[TGSI_FILE_IMAGE] > 0 || diff --git a/src/gallium/drivers/r600/r600_shader.h b/src/gallium/drivers/r600/r600_shader.h index 25b3ca58afc..43c4beedb4a 100644 --- a/src/gallium/drivers/r600/r600_shader.h +++ b/src/gallium/drivers/r600/r600_shader.h @@ -114,6 +114,8 @@ struct r600_shader { unsigned tes_as_es; unsigned tcs_prim_mode; unsigned ps_prim_id_input; + unsigned num_loops; + struct r600_shader_array * arrays; boolean uses_doubles; diff --git a/src/gallium/drivers/r600/r600_state_common.c b/src/gallium/drivers/r600/r600_state_common.c index 4669d2d30bf..ec09d6c3495 100644 --- a/src/gallium/drivers/r600/r600_state_common.c +++ b/src/gallium/drivers/r600/r600_state_common.c @@ -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. * (*dirty) is set to 1 if current variant was changed */ int r600_shader_select(struct pipe_context *ctx, struct r600_pipe_shader_selector* sel, - bool *dirty) + bool *dirty, bool precompile) { union r600_shader_key key; struct r600_pipe_shader * shader = NULL; 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. * 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; } + /* 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; } @@ -1771,7 +1823,7 @@ void r600_setup_scratch_buffers(struct r600_context *rctx) { } #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)) \ return false; \ } while(0)