1/* 2 * Copyright © 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23 24/** 25 * \file shader_cache.cpp 26 * 27 * GLSL shader cache implementation 28 * 29 * This uses disk_cache.c to write out a serialization of various 30 * state that's required in order to successfully load and use a 31 * binary written out by a drivers backend, this state is referred to as 32 * "metadata" throughout the implementation. 33 * 34 * The hash key for glsl metadata is a hash of the hashes of each GLSL 35 * source string as well as some API settings that change the final program 36 * such as SSO, attribute bindings, frag data bindings, etc. 37 * 38 * In order to avoid caching any actual IR we use the put_key/get_key support 39 * in the disk_cache to put the SHA-1 hash for each successfully compiled 40 * shader into the cache, and optimisticly return early from glCompileShader 41 * (if the identical shader had been successfully compiled in the past), 42 * in the hope that the final linked shader will be found in the cache. 43 * If anything goes wrong (shader variant not found, backend cache item is 44 * corrupt, etc) we will use a fallback path to compile and link the IR. 45 */ 46 47#include "util/os_misc.h" 48 49#include "compiler/shader_info.h" 50#include "glsl_symbol_table.h" 51#include "glsl_parser_extras.h" 52#include "ir.h" 53#include "ir_optimization.h" 54#include "ir_rvalue_visitor.h" 55#include "ir_uniform.h" 56#include "linker.h" 57#include "link_varyings.h" 58#include "nir.h" 59#include "program.h" 60#include "serialize.h" 61#include "shader_cache.h" 62#include "util/mesa-sha1.h" 63#include "string_to_uint_map.h" 64#include "main/mtypes.h" 65 66extern "C" { 67#include "main/enums.h" 68#include "main/shaderobj.h" 69#include "program/program.h" 70} 71 72static void 73compile_shaders(struct gl_context *ctx, struct gl_shader_program *prog) { 74 for (unsigned i = 0; i < prog->NumShaders; i++) { 75 _mesa_glsl_compile_shader(ctx, prog->Shaders[i], false, false, true); 76 } 77} 78 79static void 80create_binding_str(const char *key, unsigned value, void *closure) 81{ 82 char **bindings_str = (char **) closure; 83 ralloc_asprintf_append(bindings_str, "%s:%u,", key, value); 84} 85 86void 87shader_cache_write_program_metadata(struct gl_context *ctx, 88 struct gl_shader_program *prog) 89{ 90 struct disk_cache *cache = ctx->Cache; 91 if (!cache) 92 return; 93 94 /* Exit early when we are dealing with a ff shader with no source file to 95 * generate a source from, or with a SPIR-V shader. 96 * 97 * TODO: In future we should use another method to generate a key for ff 98 * programs, and SPIR-V shaders. 99 */ 100 static const char zero[sizeof(prog->data->sha1)] = {0}; 101 if (memcmp(prog->data->sha1, zero, sizeof(prog->data->sha1)) == 0) 102 return; 103 104 struct blob metadata; 105 blob_init(&metadata); 106 107 if (ctx->Driver.ShaderCacheSerializeDriverBlob) { 108 for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 109 struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 110 if (sh) 111 ctx->Driver.ShaderCacheSerializeDriverBlob(ctx, sh->Program); 112 } 113 } 114 115 serialize_glsl_program(&metadata, ctx, prog); 116 117 struct cache_item_metadata cache_item_metadata; 118 cache_item_metadata.type = CACHE_ITEM_TYPE_GLSL; 119 cache_item_metadata.keys = 120 (cache_key *) malloc(prog->NumShaders * sizeof(cache_key)); 121 cache_item_metadata.num_keys = prog->NumShaders; 122 123 if (!cache_item_metadata.keys) 124 goto fail; 125 126 for (unsigned i = 0; i < prog->NumShaders; i++) { 127 memcpy(cache_item_metadata.keys[i], prog->Shaders[i]->disk_cache_sha1, 128 sizeof(cache_key)); 129 } 130 131 disk_cache_put(cache, prog->data->sha1, metadata.data, metadata.size, 132 &cache_item_metadata); 133 134 char sha1_buf[41]; 135 if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 136 _mesa_sha1_format(sha1_buf, prog->data->sha1); 137 fprintf(stderr, "putting program metadata in cache: %s\n", sha1_buf); 138 } 139 140fail: 141 free(cache_item_metadata.keys); 142 blob_finish(&metadata); 143} 144 145bool 146shader_cache_read_program_metadata(struct gl_context *ctx, 147 struct gl_shader_program *prog) 148{ 149 /* Fixed function programs generated by Mesa, or SPIR-V shaders, are not 150 * cached. So don't try to read metadata for them from the cache. 151 */ 152 if (prog->Name == 0 || prog->data->spirv) 153 return false; 154 155 struct disk_cache *cache = ctx->Cache; 156 if (!cache) 157 return false; 158 159 /* Include bindings when creating sha1. These bindings change the resulting 160 * binary so they are just as important as the shader source. 161 */ 162 char *buf = ralloc_strdup(NULL, "vb: "); 163 prog->AttributeBindings->iterate(create_binding_str, &buf); 164 ralloc_strcat(&buf, "fb: "); 165 prog->FragDataBindings->iterate(create_binding_str, &buf); 166 ralloc_strcat(&buf, "fbi: "); 167 prog->FragDataIndexBindings->iterate(create_binding_str, &buf); 168 ralloc_asprintf_append(&buf, "tf: %d ", prog->TransformFeedback.BufferMode); 169 for (unsigned int i = 0; i < prog->TransformFeedback.NumVarying; i++) { 170 ralloc_asprintf_append(&buf, "%s ", 171 prog->TransformFeedback.VaryingNames[i]); 172 } 173 174 /* SSO has an effect on the linked program so include this when generating 175 * the sha also. 176 */ 177 ralloc_asprintf_append(&buf, "sso: %s\n", 178 prog->SeparateShader ? "T" : "F"); 179 180 /* A shader might end up producing different output depending on the glsl 181 * version supported by the compiler. For example a different path might be 182 * taken by the preprocessor, so add the version to the hash input. 183 */ 184 ralloc_asprintf_append(&buf, "api: %d glsl: %d fglsl: %d\n", 185 ctx->API, ctx->Const.GLSLVersion, 186 ctx->Const.ForceGLSLVersion); 187 188 /* We run the preprocessor on shaders after hashing them, so we need to 189 * add any extension override vars to the hash. If we don't do this the 190 * preprocessor could result in different output and we could load the 191 * wrong shader. 192 */ 193 const char *ext_override = os_get_option("MESA_EXTENSION_OVERRIDE"); 194 if (ext_override) { 195 ralloc_asprintf_append(&buf, "ext:%s", ext_override); 196 } 197 198 /* DRI config options may also change the output from the compiler so 199 * include them as an input to sha1 creation. 200 */ 201 char sha1buf[41]; 202 _mesa_sha1_format(sha1buf, ctx->Const.dri_config_options_sha1); 203 ralloc_strcat(&buf, sha1buf); 204 205 for (unsigned i = 0; i < prog->NumShaders; i++) { 206 struct gl_shader *sh = prog->Shaders[i]; 207 _mesa_sha1_format(sha1buf, sh->disk_cache_sha1); 208 ralloc_asprintf_append(&buf, "%s: %s\n", 209 _mesa_shader_stage_to_abbrev(sh->Stage), sha1buf); 210 } 211 disk_cache_compute_key(cache, buf, strlen(buf), prog->data->sha1); 212 ralloc_free(buf); 213 214 size_t size; 215 uint8_t *buffer = (uint8_t *) disk_cache_get(cache, prog->data->sha1, 216 &size); 217 if (buffer == NULL) { 218 /* Cached program not found. We may have seen the individual shaders 219 * before and skipped compiling but they may not have been used together 220 * in this combination before. Fall back to linking shaders but first 221 * re-compile the shaders. 222 * 223 * We could probably only compile the shaders which were skipped here 224 * but we need to be careful because the source may also have been 225 * changed since the last compile so for now we just recompile 226 * everything. 227 */ 228 compile_shaders(ctx, prog); 229 return false; 230 } 231 232 if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 233 _mesa_sha1_format(sha1buf, prog->data->sha1); 234 fprintf(stderr, "loading shader program meta data from cache: %s\n", 235 sha1buf); 236 } 237 238 struct blob_reader metadata; 239 blob_reader_init(&metadata, buffer, size); 240 241 bool deserialized = deserialize_glsl_program(&metadata, ctx, prog); 242 243 if (!deserialized || metadata.current != metadata.end || metadata.overrun) { 244 /* Something has gone wrong discard the item from the cache and rebuild 245 * from source. 246 */ 247 assert(!"Invalid GLSL shader disk cache item!"); 248 249 if (ctx->_Shader->Flags & GLSL_CACHE_INFO) { 250 fprintf(stderr, "Error reading program from cache (invalid GLSL " 251 "cache item)\n"); 252 } 253 254 disk_cache_remove(cache, prog->data->sha1); 255 compile_shaders(ctx, prog); 256 free(buffer); 257 return false; 258 } 259 260 /* This is used to flag a shader retrieved from cache */ 261 prog->data->LinkStatus = LINKING_SKIPPED; 262 263 free (buffer); 264 265 return true; 266} 267