Reviewed-by: Marek Olšák <[email protected]> Marek
On Mon, Nov 27, 2017 at 6:30 AM, Timothy Arceri <[email protected]> wrote: > 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. > --- > 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 1034e2b196b..5e1682b351c 100644 > --- a/src/compiler/glsl/shader_cache.cpp > +++ b/src/compiler/glsl/shader_cache.cpp > @@ -141,21 +141,21 @@ bool > shader_cache_read_program_metadata(struct gl_context *ctx, > struct gl_shader_program *prog) > { > /* Fixed function programs generated by Mesa are not cached. So don't > * try to read metadata for them from the cache. > */ > if (prog->Name == 0) > 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 > * binary so they are just as important as the shader source. > */ > char *buf = ralloc_strdup(NULL, "vb: "); > prog->AttributeBindings->iterate(create_binding_str, &buf); > ralloc_strcat(&buf, "fb: "); > prog->FragDataBindings->iterate(create_binding_str, &buf); > ralloc_strcat(&buf, "fbi: "); > diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h > index 79d5fcad3e0..2babe4229be 100644 > --- a/src/mesa/main/mtypes.h > +++ b/src/mesa/main/mtypes.h > @@ -2881,27 +2881,20 @@ struct gl_shader_program_data > * > * From the ARB_get_program_binary spec: > * > * "A successful call to ProgramBinary will reset all uniform > * variables to their initial values. The initial value is either > * the value of the variable's initializer as specified in the > * original shader source, or 0 if no initializer was present. > */ > union gl_constant_value *UniformDataDefaults; > > - /* 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. */ > struct gl_program_resource *ProgramResourceList; > unsigned NumProgramResourceList; > > enum gl_link_status LinkStatus; /**< GL_LINK_STATUS */ > GLchar *InfoLog; > > unsigned Version; /**< GLSL version used for linking */ > diff --git a/src/mesa/state_tracker/st_program.h > b/src/mesa/state_tracker/st_program.h > index 6049fba517b..0e6c8e00c6e 100644 > --- a/src/mesa/state_tracker/st_program.h > +++ b/src/mesa/state_tracker/st_program.h > @@ -143,23 +143,20 @@ struct st_fragment_program > struct gl_program Base; > struct pipe_shader_state tgsi; > struct glsl_to_tgsi_visitor* glsl_to_tgsi; > struct ati_fragment_shader *ati_fs; > uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding > */ > > /* used when bypassing glsl_to_tgsi: */ > 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]; > }; > > > > /** Vertex program variant key */ > struct st_vp_variant_key > { > struct st_context *st; /**< variants are per-context */ > boolean passthrough_edgeflags; > > diff --git a/src/mesa/state_tracker/st_shader_cache.c > b/src/mesa/state_tracker/st_shader_cache.c > index 2e9b7cc6708..a5e33133b3c 100644 > --- a/src/mesa/state_tracker/st_shader_cache.c > +++ b/src/mesa/state_tracker/st_shader_cache.c > @@ -33,100 +33,90 @@ > static void > write_stream_out_to_cache(struct blob *blob, > struct pipe_shader_state *tgsi) > { > blob_write_bytes(blob, &tgsi->stream_output, > sizeof(tgsi->stream_output)); > } > > 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; > } > > /** > * Store tgsi and any other required state in on-disk shader cache. > */ > void > st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog, > struct pipe_shader_state *out_state, > unsigned num_tokens) > { > if (!st->ctx->Cache) > return; > > /* Exit early when we are dealing with a ff shader with no source file to > * generate a source from. > */ > static const char zero[sizeof(prog->sh.data->sha1)] = {0}; > 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, > sizeof(stvp->index_to_input)); > blob_write_bytes(&blob, stvp->result_to_output, > 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: > unreachable("Unsupported stage"); > } > > 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); > } > > static void > read_stream_out_from_cache(struct blob_reader *blob_reader, > struct pipe_shader_state *tgsi) > { > blob_copy_bytes(blob_reader, (uint8_t *) &tgsi->stream_output, > @@ -143,261 +133,160 @@ read_tgsi_from_cache(struct blob_reader *blob_reader, > blob_copy_bytes(blob_reader, (uint8_t *) *tokens, tokens_size); > } > > bool > st_load_tgsi_from_disk_cache(struct gl_context *ctx, > struct gl_shader_program *prog) > { > 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.14.3 > > _______________________________________________ > mesa-dev mailing list > [email protected] > https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/mesa-dev
