1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2020 Google, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "nir_serialize.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "ir3_compiler.h" 27bf215546Sopenharmony_ci#include "ir3_nir.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#define debug 0 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci/* 32bf215546Sopenharmony_ci * Shader disk-cache implementation. 33bf215546Sopenharmony_ci * 34bf215546Sopenharmony_ci * Note that at least in the EGL_ANDROID_blob_cache, we should never 35bf215546Sopenharmony_ci * rely on inter-dependencies between different cache entries: 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * No guarantees are made as to whether a given key/value pair is present in 38bf215546Sopenharmony_ci * the cache after the set call. If a different value has been associated 39bf215546Sopenharmony_ci * with the given key in the past then it is undefined which value, if any, 40bf215546Sopenharmony_ci * is associated with the key after the set call. Note that while there are 41bf215546Sopenharmony_ci * no guarantees, the cache implementation should attempt to cache the most 42bf215546Sopenharmony_ci * recently set value for a given key. 43bf215546Sopenharmony_ci * 44bf215546Sopenharmony_ci * for this reason, because binning pass variants share const_state with 45bf215546Sopenharmony_ci * their draw-pass counterpart, both variants are serialized together. 46bf215546Sopenharmony_ci */ 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_civoid 49bf215546Sopenharmony_ciir3_disk_cache_init(struct ir3_compiler *compiler) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci if (ir3_shader_debug & IR3_DBG_NOCACHE) 52bf215546Sopenharmony_ci return; 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci const char *renderer = fd_dev_name(compiler->dev_id); 55bf215546Sopenharmony_ci const struct build_id_note *note = 56bf215546Sopenharmony_ci build_id_find_nhdr_for_addr(ir3_disk_cache_init); 57bf215546Sopenharmony_ci assert(note && build_id_length(note) == 20); /* sha1 */ 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci const uint8_t *id_sha1 = build_id_data(note); 60bf215546Sopenharmony_ci assert(id_sha1); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci char timestamp[41]; 63bf215546Sopenharmony_ci _mesa_sha1_format(timestamp, id_sha1); 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci uint64_t driver_flags = ir3_shader_debug; 66bf215546Sopenharmony_ci if (compiler->robust_buffer_access2) 67bf215546Sopenharmony_ci driver_flags |= IR3_DBG_ROBUST_UBO_ACCESS; 68bf215546Sopenharmony_ci compiler->disk_cache = disk_cache_create(renderer, timestamp, driver_flags); 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_civoid 72bf215546Sopenharmony_ciir3_disk_cache_init_shader_key(struct ir3_compiler *compiler, 73bf215546Sopenharmony_ci struct ir3_shader *shader) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci if (!compiler->disk_cache) 76bf215546Sopenharmony_ci return; 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_ci struct mesa_sha1 ctx; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci _mesa_sha1_init(&ctx); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci /* Serialize the NIR to a binary blob that we can hash for the disk 83bf215546Sopenharmony_ci * cache. Drop unnecessary information (like variable names) 84bf215546Sopenharmony_ci * so the serialized NIR is smaller, and also to let us detect more 85bf215546Sopenharmony_ci * isomorphic shaders when hashing, increasing cache hits. 86bf215546Sopenharmony_ci */ 87bf215546Sopenharmony_ci struct blob blob; 88bf215546Sopenharmony_ci blob_init(&blob); 89bf215546Sopenharmony_ci nir_serialize(&blob, shader->nir, true); 90bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, blob.data, blob.size); 91bf215546Sopenharmony_ci blob_finish(&blob); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, &shader->api_wavesize, 94bf215546Sopenharmony_ci sizeof(shader->api_wavesize)); 95bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, &shader->real_wavesize, 96bf215546Sopenharmony_ci sizeof(shader->real_wavesize)); 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci /* Note that on some gens stream-out is lowered in ir3 to stg. For later 99bf215546Sopenharmony_ci * gens we maybe don't need to include stream-out in the cache key. 100bf215546Sopenharmony_ci */ 101bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, &shader->stream_output, 102bf215546Sopenharmony_ci sizeof(shader->stream_output)); 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci _mesa_sha1_final(&ctx, shader->cache_key); 105bf215546Sopenharmony_ci} 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_cistatic void 108bf215546Sopenharmony_cicompute_variant_key(struct ir3_shader *shader, struct ir3_shader_variant *v, 109bf215546Sopenharmony_ci cache_key cache_key) 110bf215546Sopenharmony_ci{ 111bf215546Sopenharmony_ci struct blob blob; 112bf215546Sopenharmony_ci blob_init(&blob); 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci blob_write_bytes(&blob, &shader->cache_key, sizeof(shader->cache_key)); 115bf215546Sopenharmony_ci blob_write_bytes(&blob, &v->key, sizeof(v->key)); 116bf215546Sopenharmony_ci blob_write_uint8(&blob, v->binning_pass); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci disk_cache_compute_key(shader->compiler->disk_cache, blob.data, blob.size, 119bf215546Sopenharmony_ci cache_key); 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci blob_finish(&blob); 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic void 125bf215546Sopenharmony_ciretrieve_variant(struct blob_reader *blob, struct ir3_shader_variant *v) 126bf215546Sopenharmony_ci{ 127bf215546Sopenharmony_ci blob_copy_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci /* 130bf215546Sopenharmony_ci * pointers need special handling: 131bf215546Sopenharmony_ci */ 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci v->bin = rzalloc_size(v, v->info.size); 134bf215546Sopenharmony_ci blob_copy_bytes(blob, v->bin, v->info.size); 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci if (!v->binning_pass) { 137bf215546Sopenharmony_ci blob_copy_bytes(blob, v->const_state, sizeof(*v->const_state)); 138bf215546Sopenharmony_ci unsigned immeds_sz = v->const_state->immediates_size * 139bf215546Sopenharmony_ci sizeof(v->const_state->immediates[0]); 140bf215546Sopenharmony_ci v->const_state->immediates = ralloc_size(v->const_state, immeds_sz); 141bf215546Sopenharmony_ci blob_copy_bytes(blob, v->const_state->immediates, immeds_sz); 142bf215546Sopenharmony_ci } 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic void 146bf215546Sopenharmony_cistore_variant(struct blob *blob, struct ir3_shader_variant *v) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci blob_write_bytes(blob, VARIANT_CACHE_PTR(v), VARIANT_CACHE_SIZE); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /* 151bf215546Sopenharmony_ci * pointers need special handling: 152bf215546Sopenharmony_ci */ 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci blob_write_bytes(blob, v->bin, v->info.size); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci /* No saving constant_data, it's already baked into bin at this point. */ 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci if (!v->binning_pass) { 159bf215546Sopenharmony_ci blob_write_bytes(blob, v->const_state, sizeof(*v->const_state)); 160bf215546Sopenharmony_ci unsigned immeds_sz = v->const_state->immediates_size * 161bf215546Sopenharmony_ci sizeof(v->const_state->immediates[0]); 162bf215546Sopenharmony_ci blob_write_bytes(blob, v->const_state->immediates, immeds_sz); 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci} 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_cistruct ir3_shader_variant * 167bf215546Sopenharmony_ciir3_retrieve_variant(struct blob_reader *blob, struct ir3_compiler *compiler, 168bf215546Sopenharmony_ci void *mem_ctx) 169bf215546Sopenharmony_ci{ 170bf215546Sopenharmony_ci struct ir3_shader_variant *v = rzalloc_size(mem_ctx, sizeof(*v)); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci v->id = 0; 173bf215546Sopenharmony_ci v->compiler = compiler; 174bf215546Sopenharmony_ci v->binning_pass = false; 175bf215546Sopenharmony_ci v->nonbinning = NULL; 176bf215546Sopenharmony_ci v->binning = NULL; 177bf215546Sopenharmony_ci blob_copy_bytes(blob, &v->key, sizeof(v->key)); 178bf215546Sopenharmony_ci v->type = blob_read_uint32(blob); 179bf215546Sopenharmony_ci v->mergedregs = blob_read_uint32(blob); 180bf215546Sopenharmony_ci v->const_state = rzalloc_size(v, sizeof(*v->const_state)); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci retrieve_variant(blob, v); 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci if (v->type == MESA_SHADER_VERTEX && ir3_has_binning_vs(&v->key)) { 185bf215546Sopenharmony_ci v->binning = rzalloc_size(v, sizeof(*v->binning)); 186bf215546Sopenharmony_ci v->binning->id = 0; 187bf215546Sopenharmony_ci v->binning->compiler = compiler; 188bf215546Sopenharmony_ci v->binning->binning_pass = true; 189bf215546Sopenharmony_ci v->binning->nonbinning = v; 190bf215546Sopenharmony_ci v->binning->key = v->key; 191bf215546Sopenharmony_ci v->binning->type = MESA_SHADER_VERTEX; 192bf215546Sopenharmony_ci v->binning->mergedregs = v->mergedregs; 193bf215546Sopenharmony_ci v->binning->const_state = v->const_state; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci retrieve_variant(blob, v->binning); 196bf215546Sopenharmony_ci } 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci return v; 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_civoid 202bf215546Sopenharmony_ciir3_store_variant(struct blob *blob, struct ir3_shader_variant *v) 203bf215546Sopenharmony_ci{ 204bf215546Sopenharmony_ci blob_write_bytes(blob, &v->key, sizeof(v->key)); 205bf215546Sopenharmony_ci blob_write_uint32(blob, v->type); 206bf215546Sopenharmony_ci blob_write_uint32(blob, v->mergedregs); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci store_variant(blob, v); 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci if (v->type == MESA_SHADER_VERTEX && ir3_has_binning_vs(&v->key)) { 211bf215546Sopenharmony_ci store_variant(blob, v->binning); 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_cibool 216bf215546Sopenharmony_ciir3_disk_cache_retrieve(struct ir3_shader *shader, 217bf215546Sopenharmony_ci struct ir3_shader_variant *v) 218bf215546Sopenharmony_ci{ 219bf215546Sopenharmony_ci if (!shader->compiler->disk_cache) 220bf215546Sopenharmony_ci return false; 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci cache_key cache_key; 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci compute_variant_key(shader, v, cache_key); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci if (debug) { 227bf215546Sopenharmony_ci char sha1[41]; 228bf215546Sopenharmony_ci _mesa_sha1_format(sha1, cache_key); 229bf215546Sopenharmony_ci fprintf(stderr, "[mesa disk cache] retrieving variant %s: ", sha1); 230bf215546Sopenharmony_ci } 231bf215546Sopenharmony_ci 232bf215546Sopenharmony_ci size_t size; 233bf215546Sopenharmony_ci void *buffer = disk_cache_get(shader->compiler->disk_cache, cache_key, &size); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci if (debug) 236bf215546Sopenharmony_ci fprintf(stderr, "%s\n", buffer ? "found" : "missing"); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci if (!buffer) 239bf215546Sopenharmony_ci return false; 240bf215546Sopenharmony_ci 241bf215546Sopenharmony_ci struct blob_reader blob; 242bf215546Sopenharmony_ci blob_reader_init(&blob, buffer, size); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci retrieve_variant(&blob, v); 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci if (v->binning) 247bf215546Sopenharmony_ci retrieve_variant(&blob, v->binning); 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci free(buffer); 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci return true; 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_civoid 255bf215546Sopenharmony_ciir3_disk_cache_store(struct ir3_shader *shader, 256bf215546Sopenharmony_ci struct ir3_shader_variant *v) 257bf215546Sopenharmony_ci{ 258bf215546Sopenharmony_ci if (!shader->compiler->disk_cache) 259bf215546Sopenharmony_ci return; 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci cache_key cache_key; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci compute_variant_key(shader, v, cache_key); 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci if (debug) { 266bf215546Sopenharmony_ci char sha1[41]; 267bf215546Sopenharmony_ci _mesa_sha1_format(sha1, cache_key); 268bf215546Sopenharmony_ci fprintf(stderr, "[mesa disk cache] storing variant %s\n", sha1); 269bf215546Sopenharmony_ci } 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci struct blob blob; 272bf215546Sopenharmony_ci blob_init(&blob); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci store_variant(&blob, v); 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci if (v->binning) 277bf215546Sopenharmony_ci store_variant(&blob, v->binning); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci disk_cache_put(shader->compiler->disk_cache, cache_key, blob.data, blob.size, NULL); 280bf215546Sopenharmony_ci blob_finish(&blob); 281bf215546Sopenharmony_ci} 282