From 3e789026cae21e56d07e21773bd6b34f32e31b4d Mon Sep 17 00:00:00 2001 From: Timothy Arceri Date: Mon, 27 Nov 2017 16:25:11 +1100 Subject: [PATCH] st/glsl_to_tgsi: make use of driver_cache_blob with the disk cache MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit driver_cache_blob was introduced with the i965 disk cache, it allows us to simplify the cache a little and possibly offers some minor speed improvements since we load the GLSL metadata and TGSI from disk in one pass. Using driver_cache_blob should also make it straight forward to implement binary support for ARB_get_program_binary in gallium. Reviewed-by: Marek Olšák --- src/compiler/glsl/shader_cache.cpp | 2 +- src/mesa/main/mtypes.h | 7 - src/mesa/state_tracker/st_program.h | 3 - src/mesa/state_tracker/st_shader_cache.c | 329 ++++++++++--------------------- 4 files changed, 110 insertions(+), 231 deletions(-) diff --git a/src/compiler/glsl/shader_cache.cpp b/src/compiler/glsl/shader_cache.cpp index da1c72d..cc63c1c 100644 --- a/src/compiler/glsl/shader_cache.cpp +++ b/src/compiler/glsl/shader_cache.cpp @@ -1299,7 +1299,7 @@ shader_cache_read_program_metadata(struct gl_context *ctx, return false; struct disk_cache *cache = ctx->Cache; - if (!cache || prog->data->skip_cache) + if (!cache) return false; /* Include bindings when creating sha1. These bindings change the resulting diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 9d704c1..9677582 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2887,13 +2887,6 @@ struct gl_shader_program_data unsigned NumUniformDataSlots; union gl_constant_value *UniformDataSlots; - /* TODO: This used by Gallium drivers to skip the cache on tgsi fallback. - * All structures (gl_program, uniform storage, etc) will get recreated - * even though we have already loaded them from cache. We should instead - * switch to storing the GLSL metadata and TGSI IR in a single cache item - * like the i965 driver does with NIR. - */ - bool skip_cache; GLboolean Validated; /** List of all active resources after linking. */ diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h index 6049fba..0e6c8e0 100644 --- a/src/mesa/state_tracker/st_program.h +++ b/src/mesa/state_tracker/st_program.h @@ -150,9 +150,6 @@ struct st_fragment_program struct gl_shader_program *shader_program; struct st_fp_variant *variants; - - /** SHA1 hash of linked tgsi shader program, used for on-disk cache */ - unsigned char sha1[20]; }; diff --git a/src/mesa/state_tracker/st_shader_cache.c b/src/mesa/state_tracker/st_shader_cache.c index 2e9b7cc..a5e3313 100644 --- a/src/mesa/state_tracker/st_shader_cache.c +++ b/src/mesa/state_tracker/st_shader_cache.c @@ -40,14 +40,15 @@ write_stream_out_to_cache(struct blob *blob, static void write_tgsi_to_cache(struct blob *blob, struct pipe_shader_state *tgsi, - struct st_context *st, unsigned char *sha1, - unsigned num_tokens) + struct gl_program *prog, unsigned num_tokens) { blob_write_uint32(blob, num_tokens); blob_write_bytes(blob, tgsi->tokens, num_tokens * sizeof(struct tgsi_token)); - disk_cache_put(st->ctx->Cache, sha1, blob->data, blob->size, NULL); + prog->driver_cache_blob = ralloc_size(NULL, blob->size); + memcpy(prog->driver_cache_blob, blob->data, blob->size); + prog->driver_cache_blob_size = blob->size; } /** @@ -68,14 +69,12 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog, if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0) return; - unsigned char *sha1; struct blob blob; blob_init(&blob); switch (prog->info.stage) { case MESA_SHADER_VERTEX: { struct st_vertex_program *stvp = (struct st_vertex_program *) prog; - sha1 = stvp->sha1; blob_write_uint32(&blob, stvp->num_inputs); blob_write_bytes(&blob, stvp->index_to_input, @@ -84,31 +83,24 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog, sizeof(stvp->result_to_output)); write_stream_out_to_cache(&blob, &stvp->tgsi); - write_tgsi_to_cache(&blob, &stvp->tgsi, st, sha1, num_tokens); + write_tgsi_to_cache(&blob, &stvp->tgsi, prog, num_tokens); break; } case MESA_SHADER_TESS_CTRL: case MESA_SHADER_TESS_EVAL: case MESA_SHADER_GEOMETRY: { - struct st_common_program *p = st_common_program(prog); - sha1 = p->sha1; - write_stream_out_to_cache(&blob, out_state); - write_tgsi_to_cache(&blob, out_state, st, sha1, num_tokens); + write_tgsi_to_cache(&blob, out_state, prog, num_tokens); break; } case MESA_SHADER_FRAGMENT: { struct st_fragment_program *stfp = (struct st_fragment_program *) prog; - sha1 = stfp->sha1; - write_tgsi_to_cache(&blob, &stfp->tgsi, st, sha1, num_tokens); + write_tgsi_to_cache(&blob, &stfp->tgsi, prog, num_tokens); break; } case MESA_SHADER_COMPUTE: { - struct st_compute_program *stcp = (struct st_compute_program *) prog; - sha1 = stcp->sha1; - - write_tgsi_to_cache(&blob, out_state, st, sha1, num_tokens); + write_tgsi_to_cache(&blob, out_state, prog, num_tokens); break; } default: @@ -116,10 +108,8 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog, } if (st->ctx->_Shader->Flags & GLSL_CACHE_INFO) { - char sha1_buf[41]; - _mesa_sha1_format(sha1_buf, sha1); - fprintf(stderr, "putting %s tgsi_tokens in cache: %s\n", - _mesa_shader_stage_to_string(prog->info.stage), sha1_buf); + fprintf(stderr, "putting %s tgsi_tokens in cache\n", + _mesa_shader_stage_to_string(prog->info.stage)); } blob_finish(&blob); @@ -150,254 +140,153 @@ st_load_tgsi_from_disk_cache(struct gl_context *ctx, if (!ctx->Cache) return false; - unsigned char *stage_sha1[MESA_SHADER_STAGES]; - char sha1_buf[41]; - - /* Compute and store sha1 for each stage. These will be reused by the - * cache store pass if we fail to find the cached tgsi. - */ - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (prog->_LinkedShaders[i] == NULL) - continue; - - char *buf = ralloc_strdup(NULL, "tgsi_tokens "); - _mesa_sha1_format(sha1_buf, - prog->_LinkedShaders[i]->Program->sh.data->sha1); - ralloc_strcat(&buf, sha1_buf); - - struct gl_program *glprog = prog->_LinkedShaders[i]->Program; - switch (glprog->info.stage) { - case MESA_SHADER_VERTEX: { - struct st_vertex_program *stvp = (struct st_vertex_program *) glprog; - stage_sha1[i] = stvp->sha1; - ralloc_strcat(&buf, " vs"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - case MESA_SHADER_TESS_CTRL: { - struct st_common_program *stcp = st_common_program(glprog); - stage_sha1[i] = stcp->sha1; - ralloc_strcat(&buf, " tcs"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - case MESA_SHADER_TESS_EVAL: { - struct st_common_program *step = st_common_program(glprog); - stage_sha1[i] = step->sha1; - ralloc_strcat(&buf, " tes"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - case MESA_SHADER_GEOMETRY: { - struct st_common_program *stgp = st_common_program(glprog); - stage_sha1[i] = stgp->sha1; - ralloc_strcat(&buf, " gs"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - case MESA_SHADER_FRAGMENT: { - struct st_fragment_program *stfp = - (struct st_fragment_program *) glprog; - stage_sha1[i] = stfp->sha1; - ralloc_strcat(&buf, " fs"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - case MESA_SHADER_COMPUTE: { - struct st_compute_program *stcp = - (struct st_compute_program *) glprog; - stage_sha1[i] = stcp->sha1; - ralloc_strcat(&buf, " cs"); - disk_cache_compute_key(ctx->Cache, buf, strlen(buf), stage_sha1[i]); - break; - } - default: - unreachable("Unsupported stage"); - } - - ralloc_free(buf); - } - - /* Now that we have created the sha1 keys that will be used for writting to - * the tgsi cache fallback to the regular glsl to tgsi path if we didn't - * load the GLSL IR from cache. We do this as glsl to tgsi can alter things - * such as gl_program_parameter_list which holds things like uniforms. + /* If we didn't load the GLSL metadata from cache then we could not have + * loaded the tgsi either. */ if (prog->data->LinkStatus != linking_skipped) return false; - uint8_t *buffer = NULL; - if (ctx->_Shader->Flags & GLSL_CACHE_FALLBACK) { - goto fallback_recompile; - } - struct st_context *st = st_context(ctx); for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { if (prog->_LinkedShaders[i] == NULL) continue; - unsigned char *sha1 = stage_sha1[i]; - size_t size; - buffer = (uint8_t *) disk_cache_get(ctx->Cache, sha1, &size); - if (buffer) { - struct blob_reader blob_reader; - blob_reader_init(&blob_reader, buffer, size); - - struct gl_program *glprog = prog->_LinkedShaders[i]->Program; - switch (glprog->info.stage) { - case MESA_SHADER_VERTEX: { - struct st_vertex_program *stvp = - (struct st_vertex_program *) glprog; - - st_release_vp_variants(st, stvp); - - stvp->num_inputs = blob_read_uint32(&blob_reader); - blob_copy_bytes(&blob_reader, (uint8_t *) stvp->index_to_input, - sizeof(stvp->index_to_input)); - blob_copy_bytes(&blob_reader, (uint8_t *) stvp->result_to_output, - sizeof(stvp->result_to_output)); - - read_stream_out_from_cache(&blob_reader, &stvp->tgsi); - read_tgsi_from_cache(&blob_reader, &stvp->tgsi.tokens); + struct gl_program *glprog = prog->_LinkedShaders[i]->Program; - if (st->vp == stvp) - st->dirty |= ST_NEW_VERTEX_PROGRAM(st, stvp); + size_t size = glprog->driver_cache_blob_size; + uint8_t *buffer = (uint8_t *) glprog->driver_cache_blob; - break; - } - case MESA_SHADER_TESS_CTRL: { - struct st_common_program *sttcp = st_common_program(glprog); + struct blob_reader blob_reader; + blob_reader_init(&blob_reader, buffer, size); - st_release_basic_variants(st, sttcp->Base.Target, - &sttcp->variants, &sttcp->tgsi); + switch (glprog->info.stage) { + case MESA_SHADER_VERTEX: { + struct st_vertex_program *stvp = (struct st_vertex_program *) glprog; - read_stream_out_from_cache(&blob_reader, &sttcp->tgsi); - read_tgsi_from_cache(&blob_reader, &sttcp->tgsi.tokens); + st_release_vp_variants(st, stvp); - if (st->tcp == sttcp) - st->dirty |= sttcp->affected_states; + stvp->num_inputs = blob_read_uint32(&blob_reader); + blob_copy_bytes(&blob_reader, (uint8_t *) stvp->index_to_input, + sizeof(stvp->index_to_input)); + blob_copy_bytes(&blob_reader, (uint8_t *) stvp->result_to_output, + sizeof(stvp->result_to_output)); - break; - } - case MESA_SHADER_TESS_EVAL: { - struct st_common_program *sttep = st_common_program(glprog); + read_stream_out_from_cache(&blob_reader, &stvp->tgsi); + read_tgsi_from_cache(&blob_reader, &stvp->tgsi.tokens); - st_release_basic_variants(st, sttep->Base.Target, - &sttep->variants, &sttep->tgsi); + if (st->vp == stvp) + st->dirty |= ST_NEW_VERTEX_PROGRAM(st, stvp); - read_stream_out_from_cache(&blob_reader, &sttep->tgsi); - read_tgsi_from_cache(&blob_reader, &sttep->tgsi.tokens); + break; + } + case MESA_SHADER_TESS_CTRL: { + struct st_common_program *sttcp = st_common_program(glprog); - if (st->tep == sttep) - st->dirty |= sttep->affected_states; + st_release_basic_variants(st, sttcp->Base.Target, + &sttcp->variants, &sttcp->tgsi); - break; - } - case MESA_SHADER_GEOMETRY: { - struct st_common_program *stgp = st_common_program(glprog); + read_stream_out_from_cache(&blob_reader, &sttcp->tgsi); + read_tgsi_from_cache(&blob_reader, &sttcp->tgsi.tokens); - st_release_basic_variants(st, stgp->Base.Target, &stgp->variants, - &stgp->tgsi); + if (st->tcp == sttcp) + st->dirty |= sttcp->affected_states; - read_stream_out_from_cache(&blob_reader, &stgp->tgsi); - read_tgsi_from_cache(&blob_reader, &stgp->tgsi.tokens); + break; + } + case MESA_SHADER_TESS_EVAL: { + struct st_common_program *sttep = st_common_program(glprog); - if (st->gp == stgp) - st->dirty |= stgp->affected_states; + st_release_basic_variants(st, sttep->Base.Target, + &sttep->variants, &sttep->tgsi); - break; - } - case MESA_SHADER_FRAGMENT: { - struct st_fragment_program *stfp = - (struct st_fragment_program *) glprog; + read_stream_out_from_cache(&blob_reader, &sttep->tgsi); + read_tgsi_from_cache(&blob_reader, &sttep->tgsi.tokens); - st_release_fp_variants(st, stfp); + if (st->tep == sttep) + st->dirty |= sttep->affected_states; - read_tgsi_from_cache(&blob_reader, &stfp->tgsi.tokens); + break; + } + case MESA_SHADER_GEOMETRY: { + struct st_common_program *stgp = st_common_program(glprog); - if (st->fp == stfp) - st->dirty |= stfp->affected_states; + st_release_basic_variants(st, stgp->Base.Target, &stgp->variants, + &stgp->tgsi); - break; - } - case MESA_SHADER_COMPUTE: { - struct st_compute_program *stcp = - (struct st_compute_program *) glprog; + read_stream_out_from_cache(&blob_reader, &stgp->tgsi); + read_tgsi_from_cache(&blob_reader, &stgp->tgsi.tokens); - st_release_cp_variants(st, stcp); + if (st->gp == stgp) + st->dirty |= stgp->affected_states; - read_tgsi_from_cache(&blob_reader, - (const struct tgsi_token**) &stcp->tgsi.prog); + break; + } + case MESA_SHADER_FRAGMENT: { + struct st_fragment_program *stfp = + (struct st_fragment_program *) glprog; - stcp->tgsi.req_local_mem = stcp->Base.info.cs.shared_size; - stcp->tgsi.req_private_mem = 0; - stcp->tgsi.req_input_mem = 0; + st_release_fp_variants(st, stfp); - if (st->cp == stcp) - st->dirty |= stcp->affected_states; + read_tgsi_from_cache(&blob_reader, &stfp->tgsi.tokens); - break; - } - default: - unreachable("Unsupported stage"); - } + if (st->fp == stfp) + st->dirty |= stfp->affected_states; - if (blob_reader.current != blob_reader.end || blob_reader.overrun) { - /* Something very bad has gone wrong discard the item from the - * cache and rebuild/link from source. - */ - assert(!"Invalid TGSI shader disk cache item!"); + break; + } + case MESA_SHADER_COMPUTE: { + struct st_compute_program *stcp = + (struct st_compute_program *) glprog; - if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { - fprintf(stderr, "Error reading program from cache (invalid " - "TGSI cache item)\n"); - } + st_release_cp_variants(st, stcp); - disk_cache_remove(ctx->Cache, sha1); + read_tgsi_from_cache(&blob_reader, + (const struct tgsi_token**) &stcp->tgsi.prog); - goto fallback_recompile; - } + stcp->tgsi.req_local_mem = stcp->Base.info.cs.shared_size; + stcp->tgsi.req_private_mem = 0; + stcp->tgsi.req_input_mem = 0; - if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { - _mesa_sha1_format(sha1_buf, sha1); - fprintf(stderr, "%s tgsi_tokens retrieved from cache: %s\n", - _mesa_shader_stage_to_string(i), sha1_buf); - } + if (st->cp == stcp) + st->dirty |= stcp->affected_states; - st_set_prog_affected_state_flags(glprog); - _mesa_associate_uniform_storage(ctx, prog, glprog, false); + break; + } + default: + unreachable("Unsupported stage"); + } - /* Create Gallium shaders now instead of on demand. */ - if (ST_DEBUG & DEBUG_PRECOMPILE || - st->shader_has_one_variant[glprog->info.stage]) - st_precompile_shader_variant(st, glprog); + /* Make sure we don't try to read more data than we wrote. This should + * never happen in release builds but its useful to have this check to + * catch development bugs. + */ + if (blob_reader.current != blob_reader.end || blob_reader.overrun) { + assert(!"Invalid TGSI shader disk cache item!"); - free(buffer); - } else { - /* Failed to find a matching cached shader so fallback to recompile. - */ if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { - fprintf(stderr, "TGSI cache item not found.\n"); + fprintf(stderr, "Error reading program from cache (invalid " + "TGSI cache item)\n"); } - - goto fallback_recompile; } - } - return true; + if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { + fprintf(stderr, "%s tgsi_tokens retrieved from cache\n", + _mesa_shader_stage_to_string(i)); + } -fallback_recompile: - free(buffer); + st_set_prog_affected_state_flags(glprog); + _mesa_associate_uniform_storage(ctx, prog, glprog, false); - if (ctx->_Shader->Flags & GLSL_CACHE_INFO) - fprintf(stderr, "TGSI cache falling back to recompile.\n"); + /* Create Gallium shaders now instead of on demand. */ + if (ST_DEBUG & DEBUG_PRECOMPILE || + st->shader_has_one_variant[glprog->info.stage]) + st_precompile_shader_variant(st, glprog); - for (unsigned i = 0; i < prog->NumShaders; i++) { - _mesa_glsl_compile_shader(ctx, prog->Shaders[i], false, false, true); + /* We don't need the cached blob anymore so free it */ + ralloc_free(glprog->driver_cache_blob); + glprog->driver_cache_blob = NULL; + glprog->driver_cache_blob_size = 0; } - prog->data->skip_cache = true; - _mesa_glsl_link_shader(ctx, prog); - return true; } -- 2.7.4