101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2014 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2101e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg/** 2501e04c3fSmrg * \file shader_cache.cpp 2601e04c3fSmrg * 2701e04c3fSmrg * GLSL shader cache implementation 2801e04c3fSmrg * 2901e04c3fSmrg * This uses disk_cache.c to write out a serialization of various 3001e04c3fSmrg * state that's required in order to successfully load and use a 3101e04c3fSmrg * binary written out by a drivers backend, this state is referred to as 3201e04c3fSmrg * "metadata" throughout the implementation. 3301e04c3fSmrg * 3401e04c3fSmrg * The hash key for glsl metadata is a hash of the hashes of each GLSL 3501e04c3fSmrg * source string as well as some API settings that change the final program 3601e04c3fSmrg * such as SSO, attribute bindings, frag data bindings, etc. 3701e04c3fSmrg * 3801e04c3fSmrg * In order to avoid caching any actual IR we use the put_key/get_key support 3901e04c3fSmrg * in the disk_cache to put the SHA-1 hash for each successfully compiled 4001e04c3fSmrg * shader into the cache, and optimisticly return early from glCompileShader 4101e04c3fSmrg * (if the identical shader had been successfully compiled in the past), 4201e04c3fSmrg * in the hope that the final linked shader will be found in the cache. 4301e04c3fSmrg * If anything goes wrong (shader variant not found, backend cache item is 4401e04c3fSmrg * corrupt, etc) we will use a fallback path to compile and link the IR. 4501e04c3fSmrg */ 4601e04c3fSmrg 477ec681f3Smrg#include "util/os_misc.h" 487ec681f3Smrg 4901e04c3fSmrg#include "compiler/shader_info.h" 5001e04c3fSmrg#include "glsl_symbol_table.h" 5101e04c3fSmrg#include "glsl_parser_extras.h" 5201e04c3fSmrg#include "ir.h" 5301e04c3fSmrg#include "ir_optimization.h" 5401e04c3fSmrg#include "ir_rvalue_visitor.h" 5501e04c3fSmrg#include "ir_uniform.h" 5601e04c3fSmrg#include "linker.h" 5701e04c3fSmrg#include "link_varyings.h" 5801e04c3fSmrg#include "nir.h" 5901e04c3fSmrg#include "program.h" 6001e04c3fSmrg#include "serialize.h" 6101e04c3fSmrg#include "shader_cache.h" 6201e04c3fSmrg#include "util/mesa-sha1.h" 6301e04c3fSmrg#include "string_to_uint_map.h" 6401e04c3fSmrg#include "main/mtypes.h" 6501e04c3fSmrg 6601e04c3fSmrgextern "C" { 6701e04c3fSmrg#include "main/enums.h" 6801e04c3fSmrg#include "main/shaderobj.h" 6901e04c3fSmrg#include "program/program.h" 7001e04c3fSmrg} 7101e04c3fSmrg 7201e04c3fSmrgstatic void 7301e04c3fSmrgcompile_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { 7401e04c3fSmrg for (unsigned i = 0; i < prog->NumShaders; i++) { 7501e04c3fSmrg _mesa_glsl_compile_shader(ctx, prog->Shaders[i], false, false, true); 7601e04c3fSmrg } 7701e04c3fSmrg} 7801e04c3fSmrg 7901e04c3fSmrgstatic void 8001e04c3fSmrgcreate_binding_str(const char *key, unsigned value, void *closure) 8101e04c3fSmrg{ 8201e04c3fSmrg char **bindings_str = (char **) closure; 8301e04c3fSmrg ralloc_asprintf_append(bindings_str, "%s:%u,", key, value); 8401e04c3fSmrg} 8501e04c3fSmrg 8601e04c3fSmrgvoid 8701e04c3fSmrgshader_cache_write_program_metadata(struct gl_context *ctx, 8801e04c3fSmrg struct gl_shader_program *prog) 8901e04c3fSmrg{ 9001e04c3fSmrg struct disk_cache *cache = ctx->Cache; 9101e04c3fSmrg if (!cache) 9201e04c3fSmrg return; 9301e04c3fSmrg 9401e04c3fSmrg /* Exit early when we are dealing with a ff shader with no source file to 957ec681f3Smrg * generate a source from, or with a SPIR-V shader. 9601e04c3fSmrg * 9701e04c3fSmrg * TODO: In future we should use another method to generate a key for ff 987ec681f3Smrg * programs, and SPIR-V shaders. 9901e04c3fSmrg */ 10001e04c3fSmrg static const char zero[sizeof(prog->data->sha1)] = {0}; 10101e04c3fSmrg if (memcmp(prog->data->sha1, zero, sizeof(prog->data->sha1)) == 0) 10201e04c3fSmrg return; 10301e04c3fSmrg 10401e04c3fSmrg struct blob metadata; 10501e04c3fSmrg blob_init(&metadata); 10601e04c3fSmrg 10701e04c3fSmrg if (ctx->Driver.ShaderCacheSerializeDriverBlob) { 10801e04c3fSmrg for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 10901e04c3fSmrg struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 11001e04c3fSmrg if (sh) 11101e04c3fSmrg ctx->Driver.ShaderCacheSerializeDriverBlob(ctx, sh->Program); 11201e04c3fSmrg } 11301e04c3fSmrg } 11401e04c3fSmrg 11501e04c3fSmrg serialize_glsl_program(&metadata, ctx, prog); 11601e04c3fSmrg 11701e04c3fSmrg struct cache_item_metadata cache_item_metadata; 11801e04c3fSmrg cache_item_metadata.type = CACHE_ITEM_TYPE_GLSL; 11901e04c3fSmrg cache_item_metadata.keys = 12001e04c3fSmrg (cache_key *) malloc(prog->NumShaders * sizeof(cache_key)); 12101e04c3fSmrg cache_item_metadata.num_keys = prog->NumShaders; 12201e04c3fSmrg 12301e04c3fSmrg if (!cache_item_metadata.keys) 12401e04c3fSmrg goto fail; 12501e04c3fSmrg 12601e04c3fSmrg for (unsigned i = 0; i < prog->NumShaders; i++) { 12701e04c3fSmrg memcpy(cache_item_metadata.keys[i], prog->Shaders[i]->sha1, 12801e04c3fSmrg sizeof(cache_key)); 12901e04c3fSmrg } 13001e04c3fSmrg 13101e04c3fSmrg disk_cache_put(cache, prog->data->sha1, metadata.data, metadata.size, 13201e04c3fSmrg &cache_item_metadata); 13301e04c3fSmrg 1347e102996Smaya char sha1_buf[41]; 13501e04c3fSmrg if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 13601e04c3fSmrg _mesa_sha1_format(sha1_buf, prog->data->sha1); 13701e04c3fSmrg fprintf(stderr, "putting program metadata in cache: %s\n", sha1_buf); 13801e04c3fSmrg } 13901e04c3fSmrg 14001e04c3fSmrgfail: 14101e04c3fSmrg free(cache_item_metadata.keys); 14201e04c3fSmrg blob_finish(&metadata); 14301e04c3fSmrg} 14401e04c3fSmrg 14501e04c3fSmrgbool 14601e04c3fSmrgshader_cache_read_program_metadata(struct gl_context *ctx, 14701e04c3fSmrg struct gl_shader_program *prog) 14801e04c3fSmrg{ 1497ec681f3Smrg /* Fixed function programs generated by Mesa, or SPIR-V shaders, are not 1507ec681f3Smrg * cached. So don't try to read metadata for them from the cache. 15101e04c3fSmrg */ 1527ec681f3Smrg if (prog->Name == 0 || prog->data->spirv) 15301e04c3fSmrg return false; 15401e04c3fSmrg 15501e04c3fSmrg struct disk_cache *cache = ctx->Cache; 15601e04c3fSmrg if (!cache) 15701e04c3fSmrg return false; 15801e04c3fSmrg 15901e04c3fSmrg /* Include bindings when creating sha1. These bindings change the resulting 16001e04c3fSmrg * binary so they are just as important as the shader source. 16101e04c3fSmrg */ 16201e04c3fSmrg char *buf = ralloc_strdup(NULL, "vb: "); 16301e04c3fSmrg prog->AttributeBindings->iterate(create_binding_str, &buf); 16401e04c3fSmrg ralloc_strcat(&buf, "fb: "); 16501e04c3fSmrg prog->FragDataBindings->iterate(create_binding_str, &buf); 16601e04c3fSmrg ralloc_strcat(&buf, "fbi: "); 16701e04c3fSmrg prog->FragDataIndexBindings->iterate(create_binding_str, &buf); 16801e04c3fSmrg ralloc_asprintf_append(&buf, "tf: %d ", prog->TransformFeedback.BufferMode); 16901e04c3fSmrg for (unsigned int i = 0; i < prog->TransformFeedback.NumVarying; i++) { 1707e102996Smaya ralloc_asprintf_append(&buf, "%s ", 1717e102996Smaya prog->TransformFeedback.VaryingNames[i]); 17201e04c3fSmrg } 17301e04c3fSmrg 17401e04c3fSmrg /* SSO has an effect on the linked program so include this when generating 17501e04c3fSmrg * the sha also. 17601e04c3fSmrg */ 17701e04c3fSmrg ralloc_asprintf_append(&buf, "sso: %s\n", 17801e04c3fSmrg prog->SeparateShader ? "T" : "F"); 17901e04c3fSmrg 18001e04c3fSmrg /* A shader might end up producing different output depending on the glsl 18101e04c3fSmrg * version supported by the compiler. For example a different path might be 18201e04c3fSmrg * taken by the preprocessor, so add the version to the hash input. 18301e04c3fSmrg */ 18401e04c3fSmrg ralloc_asprintf_append(&buf, "api: %d glsl: %d fglsl: %d\n", 18501e04c3fSmrg ctx->API, ctx->Const.GLSLVersion, 18601e04c3fSmrg ctx->Const.ForceGLSLVersion); 18701e04c3fSmrg 18801e04c3fSmrg /* We run the preprocessor on shaders after hashing them, so we need to 18901e04c3fSmrg * add any extension override vars to the hash. If we don't do this the 19001e04c3fSmrg * preprocessor could result in different output and we could load the 19101e04c3fSmrg * wrong shader. 19201e04c3fSmrg */ 1937ec681f3Smrg const char *ext_override = os_get_option("MESA_EXTENSION_OVERRIDE"); 19401e04c3fSmrg if (ext_override) { 19501e04c3fSmrg ralloc_asprintf_append(&buf, "ext:%s", ext_override); 19601e04c3fSmrg } 19701e04c3fSmrg 19801e04c3fSmrg /* DRI config options may also change the output from the compiler so 19901e04c3fSmrg * include them as an input to sha1 creation. 20001e04c3fSmrg */ 20101e04c3fSmrg char sha1buf[41]; 20201e04c3fSmrg _mesa_sha1_format(sha1buf, ctx->Const.dri_config_options_sha1); 20301e04c3fSmrg ralloc_strcat(&buf, sha1buf); 20401e04c3fSmrg 20501e04c3fSmrg for (unsigned i = 0; i < prog->NumShaders; i++) { 20601e04c3fSmrg struct gl_shader *sh = prog->Shaders[i]; 20701e04c3fSmrg _mesa_sha1_format(sha1buf, sh->sha1); 20801e04c3fSmrg ralloc_asprintf_append(&buf, "%s: %s\n", 20901e04c3fSmrg _mesa_shader_stage_to_abbrev(sh->Stage), sha1buf); 21001e04c3fSmrg } 21101e04c3fSmrg disk_cache_compute_key(cache, buf, strlen(buf), prog->data->sha1); 21201e04c3fSmrg ralloc_free(buf); 21301e04c3fSmrg 21401e04c3fSmrg size_t size; 21501e04c3fSmrg uint8_t *buffer = (uint8_t *) disk_cache_get(cache, prog->data->sha1, 21601e04c3fSmrg &size); 21701e04c3fSmrg if (buffer == NULL) { 21801e04c3fSmrg /* Cached program not found. We may have seen the individual shaders 21901e04c3fSmrg * before and skipped compiling but they may not have been used together 22001e04c3fSmrg * in this combination before. Fall back to linking shaders but first 22101e04c3fSmrg * re-compile the shaders. 22201e04c3fSmrg * 22301e04c3fSmrg * We could probably only compile the shaders which were skipped here 22401e04c3fSmrg * but we need to be careful because the source may also have been 22501e04c3fSmrg * changed since the last compile so for now we just recompile 22601e04c3fSmrg * everything. 22701e04c3fSmrg */ 22801e04c3fSmrg compile_shaders(ctx, prog); 22901e04c3fSmrg return false; 23001e04c3fSmrg } 23101e04c3fSmrg 23201e04c3fSmrg if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 23301e04c3fSmrg _mesa_sha1_format(sha1buf, prog->data->sha1); 23401e04c3fSmrg fprintf(stderr, "loading shader program meta data from cache: %s\n", 23501e04c3fSmrg sha1buf); 23601e04c3fSmrg } 23701e04c3fSmrg 23801e04c3fSmrg struct blob_reader metadata; 23901e04c3fSmrg blob_reader_init(&metadata, buffer, size); 24001e04c3fSmrg 24101e04c3fSmrg bool deserialized = deserialize_glsl_program(&metadata, ctx, prog); 24201e04c3fSmrg 24301e04c3fSmrg if (!deserialized || metadata.current != metadata.end || metadata.overrun) { 24401e04c3fSmrg /* Something has gone wrong discard the item from the cache and rebuild 24501e04c3fSmrg * from source. 24601e04c3fSmrg */ 24701e04c3fSmrg assert(!"Invalid GLSL shader disk cache item!"); 24801e04c3fSmrg 24901e04c3fSmrg if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 25001e04c3fSmrg fprintf(stderr, "Error reading program from cache (invalid GLSL " 25101e04c3fSmrg "cache item)\n"); 25201e04c3fSmrg } 25301e04c3fSmrg 25401e04c3fSmrg disk_cache_remove(cache, prog->data->sha1); 25501e04c3fSmrg compile_shaders(ctx, prog); 25601e04c3fSmrg free(buffer); 25701e04c3fSmrg return false; 25801e04c3fSmrg } 25901e04c3fSmrg 26001e04c3fSmrg /* This is used to flag a shader retrieved from cache */ 26101e04c3fSmrg prog->data->LinkStatus = LINKING_SKIPPED; 26201e04c3fSmrg 26301e04c3fSmrg free (buffer); 26401e04c3fSmrg 26501e04c3fSmrg return true; 26601e04c3fSmrg} 267