1/* 2 * Copyright © 2020 Google, Inc. 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#include "nir_serialize.h" 25 26#include "ir3_compiler.h" 27#include "ir3_nir.h" 28 29#define debug 0 30 31/* 32 * Shader disk-cache implementation. 33 * 34 * Note that at least in the EGL_ANDROID_blob_cache, we should never 35 * rely on inter-dependencies between different cache entries: 36 * 37 * No guarantees are made as to whether a given key/value pair is present in 38 * the cache after the set call. If a different value has been associated 39 * with the given key in the past then it is undefined which value, if any, 40 * is associated with the key after the set call. Note that while there are 41 * no guarantees, the cache implementation should attempt to cache the most 42 * recently set value for a given key. 43 * 44 * for this reason, because binning pass variants share const_state with 45 * their draw-pass counterpart, both variants are serialized together. 46 */ 47 48void 49ir3_disk_cache_init(struct ir3_compiler *compiler) 50{ 51 if (ir3_shader_debug & IR3_DBG_NOCACHE) 52 return; 53 54 const char *renderer = fd_dev_name(compiler->dev_id); 55 const struct build_id_note *note = 56 build_id_find_nhdr_for_addr(ir3_disk_cache_init); 57 assert(note && build_id_length(note) == 20); /* sha1 */ 58 59 const uint8_t *id_sha1 = build_id_data(note); 60 assert(id_sha1); 61 62 char timestamp[41]; 63 _mesa_sha1_format(timestamp, id_sha1); 64 65 uint64_t driver_flags = ir3_shader_debug; 66 if (compiler->robust_ubo_access) 67 driver_flags |= IR3_DBG_ROBUST_UBO_ACCESS; 68 compiler->disk_cache = disk_cache_create(renderer, timestamp, driver_flags); 69} 70 71void 72ir3_disk_cache_init_shader_key(struct ir3_compiler *compiler, 73 struct ir3_shader *shader) 74{ 75 if (!compiler->disk_cache) 76 return; 77 78 struct mesa_sha1 ctx; 79 80 _mesa_sha1_init(&ctx); 81 82 /* Serialize the NIR to a binary blob that we can hash for the disk 83 * cache. Drop unnecessary information (like variable names) 84 * so the serialized NIR is smaller, and also to let us detect more 85 * isomorphic shaders when hashing, increasing cache hits. 86 */ 87 struct blob blob; 88 blob_init(&blob); 89 nir_serialize(&blob, shader->nir, true); 90 _mesa_sha1_update(&ctx, blob.data, blob.size); 91 blob_finish(&blob); 92 93 /* Note that on some gens stream-out is lowered in ir3 to stg. For later 94 * gens we maybe don't need to include stream-out in the cache key. 95 */ 96 _mesa_sha1_update(&ctx, &shader->stream_output, 97 sizeof(shader->stream_output)); 98 99 _mesa_sha1_final(&ctx, shader->cache_key); 100} 101 102static void 103compute_variant_key(struct ir3_compiler *compiler, struct ir3_shader_variant *v, 104 cache_key cache_key) 105{ 106 struct blob blob; 107 blob_init(&blob); 108 109 blob_write_bytes(&blob, &v->shader->cache_key, sizeof(v->shader->cache_key)); 110 blob_write_bytes(&blob, &v->key, sizeof(v->key)); 111 blob_write_uint8(&blob, v->binning_pass); 112 113 disk_cache_compute_key(compiler->disk_cache, blob.data, blob.size, 114 cache_key); 115 116 blob_finish(&blob); 117} 118 119static void 120retrieve_variant(struct blob_reader *blob, struct ir3_shader_variant *v) 121{ 122 blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); 123 124 /* 125 * pointers need special handling: 126 */ 127 128 v->bin = rzalloc_size(v, v->info.size); 129 blob_copy_bytes(blob, v->bin, v->info.size); 130 131 if (!v->binning_pass) { 132 blob_copy_bytes(blob, v->const_state, sizeof(*v->const_state)); 133 unsigned immeds_sz = v->const_state->immediates_size * 134 sizeof(v->const_state->immediates[0]); 135 v->const_state->immediates = ralloc_size(v->const_state, immeds_sz); 136 blob_copy_bytes(blob, v->const_state->immediates, immeds_sz); 137 } 138} 139 140static void 141store_variant(struct blob *blob, struct ir3_shader_variant *v) 142{ 143 blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); 144 145 /* 146 * pointers need special handling: 147 */ 148 149 blob_write_bytes(blob, v->bin, v->info.size); 150 151 /* No saving constant_data, it's already baked into bin at this point. */ 152 153 if (!v->binning_pass) { 154 blob_write_bytes(blob, v->const_state, sizeof(*v->const_state)); 155 unsigned immeds_sz = v->const_state->immediates_size * 156 sizeof(v->const_state->immediates[0]); 157 blob_write_bytes(blob, v->const_state->immediates, immeds_sz); 158 } 159} 160 161bool 162ir3_disk_cache_retrieve(struct ir3_compiler *compiler, 163 struct ir3_shader_variant *v) 164{ 165 if (!compiler->disk_cache) 166 return false; 167 168 cache_key cache_key; 169 170 compute_variant_key(compiler, v, cache_key); 171 172 if (debug) { 173 char sha1[41]; 174 _mesa_sha1_format(sha1, cache_key); 175 fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1); 176 } 177 178 size_t size; 179 void *buffer = disk_cache_get(compiler->disk_cache, cache_key, &size); 180 181 if (debug) 182 fprintf(stderr, "%s\n", buffer ? "found" : "missing"); 183 184 if (!buffer) 185 return false; 186 187 struct blob_reader blob; 188 blob_reader_init(&blob, buffer, size); 189 190 retrieve_variant(&blob, v); 191 192 if (v->binning) 193 retrieve_variant(&blob, v->binning); 194 195 free(buffer); 196 197 return true; 198} 199 200void 201ir3_disk_cache_store(struct ir3_compiler *compiler, 202 struct ir3_shader_variant *v) 203{ 204 if (!compiler->disk_cache) 205 return; 206 207 cache_key cache_key; 208 209 compute_variant_key(compiler, v, cache_key); 210 211 if (debug) { 212 char sha1[41]; 213 _mesa_sha1_format(sha1, cache_key); 214 fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1); 215 } 216 217 struct blob blob; 218 blob_init(&blob); 219 220 store_variant(&blob, v); 221 222 if (v->binning) 223 store_variant(&blob, v->binning); 224 225 disk_cache_put(compiler->disk_cache, cache_key, blob.data, blob.size, NULL); 226 blob_finish(&blob); 227} 228