From e480cb63354a2a878e6056e5b192174fb0f11e0e Mon Sep 17 00:00:00 2001 From: Gert Wollny Date: Wed, 14 Aug 2019 09:48:10 +0200 Subject: [PATCH] vrend: Ignore prev shader stages in shader key when procesing unbound shaders Gallium sends the shaders in the order FS-[GS]-[TES]-[TCS]-VS. If an old shader program is still bound when a new shader is send, then it would use the old bounds shader of the previous stage to evaluate the shader key and code creation might create an invalid shader. Hence, if the shader to be translated is not yet bound ignore the previous stage when evaluating the shader key (Gurchtan) Fixes #114 Signed-off-by: Gert Wollny Reviewed-by: Gurchetan Singh --- src/vrend_renderer.c | 65 +++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index c38ee0f..47789ca 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -3036,9 +3036,11 @@ static inline bool can_emulate_logicop(enum pipe_logicop op) static inline void vrend_fill_shader_key(struct vrend_context *ctx, - unsigned type, + struct vrend_shader_selector *sel, struct vrend_shader_key *key) { + unsigned type = sel->type; + if (vrend_state.use_core_profile == true) { int i; bool add_alpha_test = true; @@ -3090,33 +3092,40 @@ static inline void vrend_fill_shader_key(struct vrend_context *ctx, int prev_type = -1; - switch (type) { - case PIPE_SHADER_GEOMETRY: - if (key->tcs_present || key->tes_present) - prev_type = PIPE_SHADER_TESS_EVAL; - else - prev_type = PIPE_SHADER_VERTEX; - break; - case PIPE_SHADER_FRAGMENT: - if (key->gs_present) - prev_type = PIPE_SHADER_GEOMETRY; - else if (key->tcs_present || key->tes_present) - prev_type = PIPE_SHADER_TESS_EVAL; - else - prev_type = PIPE_SHADER_VERTEX; - break; - case PIPE_SHADER_TESS_EVAL: - if (key->tcs_present) - prev_type = PIPE_SHADER_TESS_CTRL; - else + /* Gallium sends and binds the shaders in the reverse order, so if an + * old shader is still bound we should ignore the "previous" (as in + * execution order) shader when the key is evaluated, unless the currently + * bound shader selector is actually refers to the current shader. */ + if (ctx->sub->shaders[type] == sel) { + switch (type) { + case PIPE_SHADER_GEOMETRY: + if (key->tcs_present || key->tes_present) + prev_type = PIPE_SHADER_TESS_EVAL; + else + prev_type = PIPE_SHADER_VERTEX; + break; + case PIPE_SHADER_FRAGMENT: + if (key->gs_present) + prev_type = PIPE_SHADER_GEOMETRY; + else if (key->tcs_present || key->tes_present) + prev_type = PIPE_SHADER_TESS_EVAL; + else + prev_type = PIPE_SHADER_VERTEX; + break; + case PIPE_SHADER_TESS_EVAL: + if (key->tcs_present) + prev_type = PIPE_SHADER_TESS_CTRL; + else + prev_type = PIPE_SHADER_VERTEX; + break; + case PIPE_SHADER_TESS_CTRL: prev_type = PIPE_SHADER_VERTEX; - break; - case PIPE_SHADER_TESS_CTRL: - prev_type = PIPE_SHADER_VERTEX; - break; - default: - break; + break; + default: + break; + } } + if (prev_type != -1 && ctx->sub->shaders[prev_type]) { key->prev_stage_pervertex_out = ctx->sub->shaders[prev_type]->sinfo.has_pervertex_out; key->prev_stage_num_clip_out = ctx->sub->shaders[prev_type]->sinfo.num_clip_out; @@ -3227,7 +3236,7 @@ static int vrend_shader_select(struct vrend_context *ctx, int r; memset(&key, 0, sizeof(key)); - vrend_fill_shader_key(ctx, sel->type, &key); + vrend_fill_shader_key(ctx, sel, &key); if (sel->current && !memcmp(&sel->current->key, &key, sizeof(key))) return 0; @@ -4151,7 +4160,7 @@ void vrend_inject_tcs(struct vrend_context *ctx, int vertices_per_patch) false, PIPE_SHADER_TESS_CTRL); struct vrend_shader *shader; shader = CALLOC_STRUCT(vrend_shader); - vrend_fill_shader_key(ctx, sel->type, &shader->key); + vrend_fill_shader_key(ctx, sel, &shader->key); shader->sel = sel; list_inithead(&shader->programs);