1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 Intel Corporation 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 shall be included 12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software. 13bf215546Sopenharmony_ci * 14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 21bf215546Sopenharmony_ci */ 22bf215546Sopenharmony_ci 23bf215546Sopenharmony_ci/** 24bf215546Sopenharmony_ci * @file iris_disk_cache.c 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * Functions for interacting with the on-disk shader cache. 27bf215546Sopenharmony_ci */ 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <stdio.h> 30bf215546Sopenharmony_ci#include <stdint.h> 31bf215546Sopenharmony_ci#include <assert.h> 32bf215546Sopenharmony_ci#include <string.h> 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "compiler/nir/nir.h" 35bf215546Sopenharmony_ci#include "util/blob.h" 36bf215546Sopenharmony_ci#include "util/build_id.h" 37bf215546Sopenharmony_ci#include "util/disk_cache.h" 38bf215546Sopenharmony_ci#include "util/mesa-sha1.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "iris_context.h" 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_cistatic bool debug = false; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci/** 45bf215546Sopenharmony_ci * Compute a disk cache key for the given uncompiled shader and NOS key. 46bf215546Sopenharmony_ci */ 47bf215546Sopenharmony_cistatic void 48bf215546Sopenharmony_ciiris_disk_cache_compute_key(struct disk_cache *cache, 49bf215546Sopenharmony_ci const struct iris_uncompiled_shader *ish, 50bf215546Sopenharmony_ci const void *orig_prog_key, 51bf215546Sopenharmony_ci uint32_t prog_key_size, 52bf215546Sopenharmony_ci cache_key cache_key) 53bf215546Sopenharmony_ci{ 54bf215546Sopenharmony_ci /* Create a copy of the program key with program_string_id zeroed out. 55bf215546Sopenharmony_ci * It's essentially random data which we don't want to include in our 56bf215546Sopenharmony_ci * hashing and comparisons. We'll set a proper value on a cache hit. 57bf215546Sopenharmony_ci */ 58bf215546Sopenharmony_ci union brw_any_prog_key prog_key; 59bf215546Sopenharmony_ci memcpy(&prog_key, orig_prog_key, prog_key_size); 60bf215546Sopenharmony_ci prog_key.base.program_string_id = 0; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci uint8_t data[sizeof(prog_key) + sizeof(ish->nir_sha1)]; 63bf215546Sopenharmony_ci uint32_t data_size = prog_key_size + sizeof(ish->nir_sha1); 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci memcpy(data, ish->nir_sha1, sizeof(ish->nir_sha1)); 66bf215546Sopenharmony_ci memcpy(data + sizeof(ish->nir_sha1), &prog_key, prog_key_size); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci disk_cache_compute_key(cache, data, data_size, cache_key); 69bf215546Sopenharmony_ci} 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci/** 72bf215546Sopenharmony_ci * Store the given compiled shader in the disk cache. 73bf215546Sopenharmony_ci * 74bf215546Sopenharmony_ci * This should only be called on newly compiled shaders. No checking is 75bf215546Sopenharmony_ci * done to prevent repeated stores of the same shader. 76bf215546Sopenharmony_ci */ 77bf215546Sopenharmony_civoid 78bf215546Sopenharmony_ciiris_disk_cache_store(struct disk_cache *cache, 79bf215546Sopenharmony_ci const struct iris_uncompiled_shader *ish, 80bf215546Sopenharmony_ci const struct iris_compiled_shader *shader, 81bf215546Sopenharmony_ci const void *prog_key, 82bf215546Sopenharmony_ci uint32_t prog_key_size) 83bf215546Sopenharmony_ci{ 84bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 85bf215546Sopenharmony_ci if (!cache) 86bf215546Sopenharmony_ci return; 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ci gl_shader_stage stage = ish->nir->info.stage; 89bf215546Sopenharmony_ci const struct brw_stage_prog_data *prog_data = shader->prog_data; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci cache_key cache_key; 92bf215546Sopenharmony_ci iris_disk_cache_compute_key(cache, ish, prog_key, prog_key_size, cache_key); 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci if (debug) { 95bf215546Sopenharmony_ci char sha1[41]; 96bf215546Sopenharmony_ci _mesa_sha1_format(sha1, cache_key); 97bf215546Sopenharmony_ci fprintf(stderr, "[mesa disk cache] storing %s\n", sha1); 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci struct blob blob; 101bf215546Sopenharmony_ci blob_init(&blob); 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci /* We write the following data to the cache blob: 104bf215546Sopenharmony_ci * 105bf215546Sopenharmony_ci * 1. Prog data (must come first because it has the assembly size) 106bf215546Sopenharmony_ci * 2. Assembly code 107bf215546Sopenharmony_ci * 3. Number of entries in the system value array 108bf215546Sopenharmony_ci * 4. System value array 109bf215546Sopenharmony_ci * 5. Size (in bytes) of kernel inputs 110bf215546Sopenharmony_ci * 6. Shader relocations 111bf215546Sopenharmony_ci * 7. Legacy param array (only used for compute workgroup ID) 112bf215546Sopenharmony_ci * 8. Binding table 113bf215546Sopenharmony_ci */ 114bf215546Sopenharmony_ci blob_write_bytes(&blob, shader->prog_data, brw_prog_data_size(stage)); 115bf215546Sopenharmony_ci blob_write_bytes(&blob, shader->map, shader->prog_data->program_size); 116bf215546Sopenharmony_ci blob_write_uint32(&blob, shader->num_system_values); 117bf215546Sopenharmony_ci blob_write_bytes(&blob, shader->system_values, 118bf215546Sopenharmony_ci shader->num_system_values * sizeof(enum brw_param_builtin)); 119bf215546Sopenharmony_ci blob_write_uint32(&blob, shader->kernel_input_size); 120bf215546Sopenharmony_ci blob_write_bytes(&blob, prog_data->relocs, 121bf215546Sopenharmony_ci prog_data->num_relocs * sizeof(struct brw_shader_reloc)); 122bf215546Sopenharmony_ci blob_write_bytes(&blob, prog_data->param, 123bf215546Sopenharmony_ci prog_data->nr_params * sizeof(uint32_t)); 124bf215546Sopenharmony_ci blob_write_bytes(&blob, &shader->bt, sizeof(shader->bt)); 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci disk_cache_put(cache, cache_key, blob.data, blob.size, NULL); 127bf215546Sopenharmony_ci blob_finish(&blob); 128bf215546Sopenharmony_ci#endif 129bf215546Sopenharmony_ci} 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_cistatic const enum iris_program_cache_id cache_id_for_stage[] = { 132bf215546Sopenharmony_ci [MESA_SHADER_VERTEX] = IRIS_CACHE_VS, 133bf215546Sopenharmony_ci [MESA_SHADER_TESS_CTRL] = IRIS_CACHE_TCS, 134bf215546Sopenharmony_ci [MESA_SHADER_TESS_EVAL] = IRIS_CACHE_TES, 135bf215546Sopenharmony_ci [MESA_SHADER_GEOMETRY] = IRIS_CACHE_GS, 136bf215546Sopenharmony_ci [MESA_SHADER_FRAGMENT] = IRIS_CACHE_FS, 137bf215546Sopenharmony_ci [MESA_SHADER_COMPUTE] = IRIS_CACHE_CS, 138bf215546Sopenharmony_ci}; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci/** 141bf215546Sopenharmony_ci * Search for a compiled shader in the disk cache. If found, upload it 142bf215546Sopenharmony_ci * to the in-memory program cache so we can use it. 143bf215546Sopenharmony_ci */ 144bf215546Sopenharmony_cibool 145bf215546Sopenharmony_ciiris_disk_cache_retrieve(struct iris_screen *screen, 146bf215546Sopenharmony_ci struct u_upload_mgr *uploader, 147bf215546Sopenharmony_ci struct iris_uncompiled_shader *ish, 148bf215546Sopenharmony_ci struct iris_compiled_shader *shader, 149bf215546Sopenharmony_ci const void *prog_key, 150bf215546Sopenharmony_ci uint32_t key_size) 151bf215546Sopenharmony_ci{ 152bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 153bf215546Sopenharmony_ci struct disk_cache *cache = screen->disk_cache; 154bf215546Sopenharmony_ci gl_shader_stage stage = ish->nir->info.stage; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if (!cache) 157bf215546Sopenharmony_ci return false; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci cache_key cache_key; 160bf215546Sopenharmony_ci iris_disk_cache_compute_key(cache, ish, prog_key, key_size, cache_key); 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci if (debug) { 163bf215546Sopenharmony_ci char sha1[41]; 164bf215546Sopenharmony_ci _mesa_sha1_format(sha1, cache_key); 165bf215546Sopenharmony_ci fprintf(stderr, "[mesa disk cache] retrieving %s: ", sha1); 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci size_t size; 169bf215546Sopenharmony_ci void *buffer = disk_cache_get(screen->disk_cache, cache_key, &size); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci if (debug) 172bf215546Sopenharmony_ci fprintf(stderr, "%s\n", buffer ? "found" : "missing"); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci if (!buffer) 175bf215546Sopenharmony_ci return false; 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci const uint32_t prog_data_size = brw_prog_data_size(stage); 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci struct brw_stage_prog_data *prog_data = ralloc_size(NULL, prog_data_size); 180bf215546Sopenharmony_ci const void *assembly; 181bf215546Sopenharmony_ci uint32_t num_system_values; 182bf215546Sopenharmony_ci uint32_t kernel_input_size; 183bf215546Sopenharmony_ci uint32_t *system_values = NULL; 184bf215546Sopenharmony_ci uint32_t *so_decls = NULL; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci struct blob_reader blob; 187bf215546Sopenharmony_ci blob_reader_init(&blob, buffer, size); 188bf215546Sopenharmony_ci blob_copy_bytes(&blob, prog_data, prog_data_size); 189bf215546Sopenharmony_ci assembly = blob_read_bytes(&blob, prog_data->program_size); 190bf215546Sopenharmony_ci num_system_values = blob_read_uint32(&blob); 191bf215546Sopenharmony_ci if (num_system_values) { 192bf215546Sopenharmony_ci system_values = 193bf215546Sopenharmony_ci ralloc_array(NULL, enum brw_param_builtin, num_system_values); 194bf215546Sopenharmony_ci blob_copy_bytes(&blob, system_values, 195bf215546Sopenharmony_ci num_system_values * sizeof(enum brw_param_builtin)); 196bf215546Sopenharmony_ci } 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci kernel_input_size = blob_read_uint32(&blob); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci prog_data->relocs = NULL; 201bf215546Sopenharmony_ci if (prog_data->num_relocs) { 202bf215546Sopenharmony_ci struct brw_shader_reloc *relocs = 203bf215546Sopenharmony_ci ralloc_array(NULL, struct brw_shader_reloc, prog_data->num_relocs); 204bf215546Sopenharmony_ci blob_copy_bytes(&blob, relocs, 205bf215546Sopenharmony_ci prog_data->num_relocs * sizeof(struct brw_shader_reloc)); 206bf215546Sopenharmony_ci prog_data->relocs = relocs; 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci prog_data->param = NULL; 210bf215546Sopenharmony_ci if (prog_data->nr_params) { 211bf215546Sopenharmony_ci prog_data->param = ralloc_array(NULL, uint32_t, prog_data->nr_params); 212bf215546Sopenharmony_ci blob_copy_bytes(&blob, prog_data->param, 213bf215546Sopenharmony_ci prog_data->nr_params * sizeof(uint32_t)); 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci struct iris_binding_table bt; 217bf215546Sopenharmony_ci blob_copy_bytes(&blob, &bt, sizeof(bt)); 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci if (stage == MESA_SHADER_VERTEX || 220bf215546Sopenharmony_ci stage == MESA_SHADER_TESS_EVAL || 221bf215546Sopenharmony_ci stage == MESA_SHADER_GEOMETRY) { 222bf215546Sopenharmony_ci struct brw_vue_prog_data *vue_prog_data = (void *) prog_data; 223bf215546Sopenharmony_ci so_decls = screen->vtbl.create_so_decl_list(&ish->stream_output, 224bf215546Sopenharmony_ci &vue_prog_data->vue_map); 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci /* System values and uniforms are stored in constant buffer 0, the 228bf215546Sopenharmony_ci * user-facing UBOs are indexed by one. So if any constant buffer is 229bf215546Sopenharmony_ci * needed, the constant buffer 0 will be needed, so account for it. 230bf215546Sopenharmony_ci */ 231bf215546Sopenharmony_ci unsigned num_cbufs = ish->nir->info.num_ubos; 232bf215546Sopenharmony_ci 233bf215546Sopenharmony_ci if (num_cbufs || ish->nir->num_uniforms) 234bf215546Sopenharmony_ci num_cbufs++; 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci if (num_system_values || kernel_input_size) 237bf215546Sopenharmony_ci num_cbufs++; 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci iris_finalize_program(shader, prog_data, so_decls, system_values, 240bf215546Sopenharmony_ci num_system_values, kernel_input_size, num_cbufs, 241bf215546Sopenharmony_ci &bt); 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci assert(stage < ARRAY_SIZE(cache_id_for_stage)); 244bf215546Sopenharmony_ci enum iris_program_cache_id cache_id = cache_id_for_stage[stage]; 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci /* Upload our newly read shader to the in-memory program cache. */ 247bf215546Sopenharmony_ci iris_upload_shader(screen, ish, shader, NULL, uploader, 248bf215546Sopenharmony_ci cache_id, key_size, prog_key, assembly); 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci free(buffer); 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci return true; 253bf215546Sopenharmony_ci#else 254bf215546Sopenharmony_ci return false; 255bf215546Sopenharmony_ci#endif 256bf215546Sopenharmony_ci} 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci/** 259bf215546Sopenharmony_ci * Initialize the on-disk shader cache. 260bf215546Sopenharmony_ci */ 261bf215546Sopenharmony_civoid 262bf215546Sopenharmony_ciiris_disk_cache_init(struct iris_screen *screen) 263bf215546Sopenharmony_ci{ 264bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 265bf215546Sopenharmony_ci if (INTEL_DEBUG(DEBUG_DISK_CACHE_DISABLE_MASK)) 266bf215546Sopenharmony_ci return; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci /* array length = print length + nul char + 1 extra to verify it's unused */ 269bf215546Sopenharmony_ci char renderer[11]; 270bf215546Sopenharmony_ci UNUSED int len = 271bf215546Sopenharmony_ci snprintf(renderer, sizeof(renderer), "iris_%04x", screen->pci_id); 272bf215546Sopenharmony_ci assert(len == sizeof(renderer) - 2); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci const struct build_id_note *note = 275bf215546Sopenharmony_ci build_id_find_nhdr_for_addr(iris_disk_cache_init); 276bf215546Sopenharmony_ci assert(note && build_id_length(note) == 20); /* sha1 */ 277bf215546Sopenharmony_ci 278bf215546Sopenharmony_ci const uint8_t *id_sha1 = build_id_data(note); 279bf215546Sopenharmony_ci assert(id_sha1); 280bf215546Sopenharmony_ci 281bf215546Sopenharmony_ci char timestamp[41]; 282bf215546Sopenharmony_ci _mesa_sha1_format(timestamp, id_sha1); 283bf215546Sopenharmony_ci 284bf215546Sopenharmony_ci const uint64_t driver_flags = 285bf215546Sopenharmony_ci brw_get_compiler_config_value(screen->compiler); 286bf215546Sopenharmony_ci screen->disk_cache = disk_cache_create(renderer, timestamp, driver_flags); 287bf215546Sopenharmony_ci#endif 288bf215546Sopenharmony_ci} 289