1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 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 (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 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <ctype.h> 27bf215546Sopenharmony_ci#include <ftw.h> 28bf215546Sopenharmony_ci#include <string.h> 29bf215546Sopenharmony_ci#include <stdlib.h> 30bf215546Sopenharmony_ci#include <stdio.h> 31bf215546Sopenharmony_ci#include <sys/file.h> 32bf215546Sopenharmony_ci#include <sys/types.h> 33bf215546Sopenharmony_ci#include <sys/stat.h> 34bf215546Sopenharmony_ci#include <sys/mman.h> 35bf215546Sopenharmony_ci#include <fcntl.h> 36bf215546Sopenharmony_ci#include <errno.h> 37bf215546Sopenharmony_ci#include <dirent.h> 38bf215546Sopenharmony_ci#include <inttypes.h> 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci#include "util/crc32.h" 41bf215546Sopenharmony_ci#include "util/debug.h" 42bf215546Sopenharmony_ci#include "util/rand_xor.h" 43bf215546Sopenharmony_ci#include "util/u_atomic.h" 44bf215546Sopenharmony_ci#include "util/mesa-sha1.h" 45bf215546Sopenharmony_ci#include "util/ralloc.h" 46bf215546Sopenharmony_ci#include "util/compiler.h" 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci#include "disk_cache.h" 49bf215546Sopenharmony_ci#include "disk_cache_os.h" 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci/* The cache version should be bumped whenever a change is made to the 52bf215546Sopenharmony_ci * structure of cache entries or the index. This will give any 3rd party 53bf215546Sopenharmony_ci * applications reading the cache entries a chance to adjust to the changes. 54bf215546Sopenharmony_ci * 55bf215546Sopenharmony_ci * - The cache version is checked internally when reading a cache entry. If we 56bf215546Sopenharmony_ci * ever have a mismatch we are in big trouble as this means we had a cache 57bf215546Sopenharmony_ci * collision. In case of such an event please check the skys for giant 58bf215546Sopenharmony_ci * asteroids and that the entire Mesa team hasn't been eaten by wolves. 59bf215546Sopenharmony_ci * 60bf215546Sopenharmony_ci * - There is no strict requirement that cache versions be backwards 61bf215546Sopenharmony_ci * compatible but effort should be taken to limit disruption where possible. 62bf215546Sopenharmony_ci */ 63bf215546Sopenharmony_ci#define CACHE_VERSION 1 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci#define DRV_KEY_CPY(_dst, _src, _src_size) \ 66bf215546Sopenharmony_cido { \ 67bf215546Sopenharmony_ci memcpy(_dst, _src, _src_size); \ 68bf215546Sopenharmony_ci _dst += _src_size; \ 69bf215546Sopenharmony_ci} while (0); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistruct disk_cache * 72bf215546Sopenharmony_cidisk_cache_create(const char *gpu_name, const char *driver_id, 73bf215546Sopenharmony_ci uint64_t driver_flags) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci void *local; 76bf215546Sopenharmony_ci struct disk_cache *cache = NULL; 77bf215546Sopenharmony_ci char *max_size_str; 78bf215546Sopenharmony_ci uint64_t max_size; 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci uint8_t cache_version = CACHE_VERSION; 81bf215546Sopenharmony_ci size_t cv_size = sizeof(cache_version); 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci if (!disk_cache_enabled()) 84bf215546Sopenharmony_ci return NULL; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci /* A ralloc context for transient data during this invocation. */ 87bf215546Sopenharmony_ci local = ralloc_context(NULL); 88bf215546Sopenharmony_ci if (local == NULL) 89bf215546Sopenharmony_ci goto fail; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci cache = rzalloc(NULL, struct disk_cache); 92bf215546Sopenharmony_ci if (cache == NULL) 93bf215546Sopenharmony_ci goto fail; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci /* Assume failure. */ 96bf215546Sopenharmony_ci cache->path_init_failed = true; 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci#ifdef ANDROID 99bf215546Sopenharmony_ci /* Android needs the "disk cache" to be enabled for 100bf215546Sopenharmony_ci * EGL_ANDROID_blob_cache's callbacks to be called, but it doesn't actually 101bf215546Sopenharmony_ci * want any storing to disk to happen inside of the driver. 102bf215546Sopenharmony_ci */ 103bf215546Sopenharmony_ci goto path_fail; 104bf215546Sopenharmony_ci#endif 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci char *path = disk_cache_generate_cache_dir(local, gpu_name, driver_id); 107bf215546Sopenharmony_ci if (!path) 108bf215546Sopenharmony_ci goto path_fail; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci cache->path = ralloc_strdup(cache, path); 111bf215546Sopenharmony_ci if (cache->path == NULL) 112bf215546Sopenharmony_ci goto path_fail; 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci if (env_var_as_boolean("MESA_DISK_CACHE_SINGLE_FILE", false)) { 115bf215546Sopenharmony_ci if (!disk_cache_load_cache_index(local, cache)) 116bf215546Sopenharmony_ci goto path_fail; 117bf215546Sopenharmony_ci } 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci if (!disk_cache_mmap_cache_index(local, cache, path)) 120bf215546Sopenharmony_ci goto path_fail; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci max_size = 0; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci max_size_str = getenv("MESA_SHADER_CACHE_MAX_SIZE"); 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci if (!max_size_str) { 127bf215546Sopenharmony_ci max_size_str = getenv("MESA_GLSL_CACHE_MAX_SIZE"); 128bf215546Sopenharmony_ci if (max_size_str) 129bf215546Sopenharmony_ci fprintf(stderr, 130bf215546Sopenharmony_ci "*** MESA_GLSL_CACHE_MAX_SIZE is deprecated; " 131bf215546Sopenharmony_ci "use MESA_SHADER_CACHE_MAX_SIZE instead ***\n"); 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci #ifdef MESA_SHADER_CACHE_MAX_SIZE 135bf215546Sopenharmony_ci if( !max_size_str ) { 136bf215546Sopenharmony_ci max_size_str = MESA_SHADER_CACHE_MAX_SIZE; 137bf215546Sopenharmony_ci } 138bf215546Sopenharmony_ci #endif 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci if (max_size_str) { 141bf215546Sopenharmony_ci char *end; 142bf215546Sopenharmony_ci max_size = strtoul(max_size_str, &end, 10); 143bf215546Sopenharmony_ci if (end == max_size_str) { 144bf215546Sopenharmony_ci max_size = 0; 145bf215546Sopenharmony_ci } else { 146bf215546Sopenharmony_ci switch (*end) { 147bf215546Sopenharmony_ci case 'K': 148bf215546Sopenharmony_ci case 'k': 149bf215546Sopenharmony_ci max_size *= 1024; 150bf215546Sopenharmony_ci break; 151bf215546Sopenharmony_ci case 'M': 152bf215546Sopenharmony_ci case 'm': 153bf215546Sopenharmony_ci max_size *= 1024*1024; 154bf215546Sopenharmony_ci break; 155bf215546Sopenharmony_ci case '\0': 156bf215546Sopenharmony_ci case 'G': 157bf215546Sopenharmony_ci case 'g': 158bf215546Sopenharmony_ci default: 159bf215546Sopenharmony_ci max_size *= 1024*1024*1024; 160bf215546Sopenharmony_ci break; 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci } 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci /* Default to 1GB for maximum cache size. */ 166bf215546Sopenharmony_ci if (max_size == 0) { 167bf215546Sopenharmony_ci max_size = 1024*1024*1024; 168bf215546Sopenharmony_ci } 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci cache->max_size = max_size; 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci /* 4 threads were chosen below because just about all modern CPUs currently 173bf215546Sopenharmony_ci * available that run Mesa have *at least* 4 cores. For these CPUs allowing 174bf215546Sopenharmony_ci * more threads can result in the queue being processed faster, thus 175bf215546Sopenharmony_ci * avoiding excessive memory use due to a backlog of cache entrys building 176bf215546Sopenharmony_ci * up in the queue. Since we set the UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY 177bf215546Sopenharmony_ci * flag this should have little negative impact on low core systems. 178bf215546Sopenharmony_ci * 179bf215546Sopenharmony_ci * The queue will resize automatically when it's full, so adding new jobs 180bf215546Sopenharmony_ci * doesn't stall. 181bf215546Sopenharmony_ci */ 182bf215546Sopenharmony_ci if (!util_queue_init(&cache->cache_queue, "disk$", 32, 4, 183bf215546Sopenharmony_ci UTIL_QUEUE_INIT_SCALE_THREADS | 184bf215546Sopenharmony_ci UTIL_QUEUE_INIT_RESIZE_IF_FULL | 185bf215546Sopenharmony_ci UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY | 186bf215546Sopenharmony_ci UTIL_QUEUE_INIT_SET_FULL_THREAD_AFFINITY, NULL)) 187bf215546Sopenharmony_ci goto fail; 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci cache->path_init_failed = false; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci path_fail: 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci cache->driver_keys_blob_size = cv_size; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci /* Create driver id keys */ 196bf215546Sopenharmony_ci size_t id_size = strlen(driver_id) + 1; 197bf215546Sopenharmony_ci size_t gpu_name_size = strlen(gpu_name) + 1; 198bf215546Sopenharmony_ci cache->driver_keys_blob_size += id_size; 199bf215546Sopenharmony_ci cache->driver_keys_blob_size += gpu_name_size; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci /* We sometimes store entire structs that contains a pointers in the cache, 202bf215546Sopenharmony_ci * use pointer size as a key to avoid hard to debug issues. 203bf215546Sopenharmony_ci */ 204bf215546Sopenharmony_ci uint8_t ptr_size = sizeof(void *); 205bf215546Sopenharmony_ci size_t ptr_size_size = sizeof(ptr_size); 206bf215546Sopenharmony_ci cache->driver_keys_blob_size += ptr_size_size; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci size_t driver_flags_size = sizeof(driver_flags); 209bf215546Sopenharmony_ci cache->driver_keys_blob_size += driver_flags_size; 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci cache->driver_keys_blob = 212bf215546Sopenharmony_ci ralloc_size(cache, cache->driver_keys_blob_size); 213bf215546Sopenharmony_ci if (!cache->driver_keys_blob) 214bf215546Sopenharmony_ci goto fail; 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_ci uint8_t *drv_key_blob = cache->driver_keys_blob; 217bf215546Sopenharmony_ci DRV_KEY_CPY(drv_key_blob, &cache_version, cv_size) 218bf215546Sopenharmony_ci DRV_KEY_CPY(drv_key_blob, driver_id, id_size) 219bf215546Sopenharmony_ci DRV_KEY_CPY(drv_key_blob, gpu_name, gpu_name_size) 220bf215546Sopenharmony_ci DRV_KEY_CPY(drv_key_blob, &ptr_size, ptr_size_size) 221bf215546Sopenharmony_ci DRV_KEY_CPY(drv_key_blob, &driver_flags, driver_flags_size) 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* Seed our rand function */ 224bf215546Sopenharmony_ci s_rand_xorshift128plus(cache->seed_xorshift128plus, true); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci ralloc_free(local); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci return cache; 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci fail: 231bf215546Sopenharmony_ci if (cache) 232bf215546Sopenharmony_ci ralloc_free(cache); 233bf215546Sopenharmony_ci ralloc_free(local); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci return NULL; 236bf215546Sopenharmony_ci} 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_civoid 239bf215546Sopenharmony_cidisk_cache_destroy(struct disk_cache *cache) 240bf215546Sopenharmony_ci{ 241bf215546Sopenharmony_ci if (cache && !cache->path_init_failed) { 242bf215546Sopenharmony_ci util_queue_finish(&cache->cache_queue); 243bf215546Sopenharmony_ci util_queue_destroy(&cache->cache_queue); 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci if (env_var_as_boolean("MESA_DISK_CACHE_SINGLE_FILE", false)) 246bf215546Sopenharmony_ci foz_destroy(&cache->foz_db); 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci disk_cache_destroy_mmap(cache); 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci ralloc_free(cache); 252bf215546Sopenharmony_ci} 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_civoid 255bf215546Sopenharmony_cidisk_cache_wait_for_idle(struct disk_cache *cache) 256bf215546Sopenharmony_ci{ 257bf215546Sopenharmony_ci util_queue_finish(&cache->cache_queue); 258bf215546Sopenharmony_ci} 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_civoid 261bf215546Sopenharmony_cidisk_cache_remove(struct disk_cache *cache, const cache_key key) 262bf215546Sopenharmony_ci{ 263bf215546Sopenharmony_ci char *filename = disk_cache_get_cache_filename(cache, key); 264bf215546Sopenharmony_ci if (filename == NULL) { 265bf215546Sopenharmony_ci return; 266bf215546Sopenharmony_ci } 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci disk_cache_evict_item(cache, filename); 269bf215546Sopenharmony_ci} 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_cistatic struct disk_cache_put_job * 272bf215546Sopenharmony_cicreate_put_job(struct disk_cache *cache, const cache_key key, 273bf215546Sopenharmony_ci void *data, size_t size, 274bf215546Sopenharmony_ci struct cache_item_metadata *cache_item_metadata, 275bf215546Sopenharmony_ci bool take_ownership) 276bf215546Sopenharmony_ci{ 277bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) 278bf215546Sopenharmony_ci malloc(sizeof(struct disk_cache_put_job) + (take_ownership ? 0 : size)); 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci if (dc_job) { 281bf215546Sopenharmony_ci dc_job->cache = cache; 282bf215546Sopenharmony_ci memcpy(dc_job->key, key, sizeof(cache_key)); 283bf215546Sopenharmony_ci if (take_ownership) { 284bf215546Sopenharmony_ci dc_job->data = data; 285bf215546Sopenharmony_ci } else { 286bf215546Sopenharmony_ci dc_job->data = dc_job + 1; 287bf215546Sopenharmony_ci memcpy(dc_job->data, data, size); 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci dc_job->size = size; 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci /* Copy the cache item metadata */ 292bf215546Sopenharmony_ci if (cache_item_metadata) { 293bf215546Sopenharmony_ci dc_job->cache_item_metadata.type = cache_item_metadata->type; 294bf215546Sopenharmony_ci if (cache_item_metadata->type == CACHE_ITEM_TYPE_GLSL) { 295bf215546Sopenharmony_ci dc_job->cache_item_metadata.num_keys = 296bf215546Sopenharmony_ci cache_item_metadata->num_keys; 297bf215546Sopenharmony_ci dc_job->cache_item_metadata.keys = (cache_key *) 298bf215546Sopenharmony_ci malloc(cache_item_metadata->num_keys * sizeof(cache_key)); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci if (!dc_job->cache_item_metadata.keys) 301bf215546Sopenharmony_ci goto fail; 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci memcpy(dc_job->cache_item_metadata.keys, 304bf215546Sopenharmony_ci cache_item_metadata->keys, 305bf215546Sopenharmony_ci sizeof(cache_key) * cache_item_metadata->num_keys); 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci } else { 308bf215546Sopenharmony_ci dc_job->cache_item_metadata.type = CACHE_ITEM_TYPE_UNKNOWN; 309bf215546Sopenharmony_ci dc_job->cache_item_metadata.keys = NULL; 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci return dc_job; 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_cifail: 316bf215546Sopenharmony_ci free(dc_job); 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci return NULL; 319bf215546Sopenharmony_ci} 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_cistatic void 322bf215546Sopenharmony_cidestroy_put_job(void *job, void *gdata, int thread_index) 323bf215546Sopenharmony_ci{ 324bf215546Sopenharmony_ci if (job) { 325bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) job; 326bf215546Sopenharmony_ci free(dc_job->cache_item_metadata.keys); 327bf215546Sopenharmony_ci free(job); 328bf215546Sopenharmony_ci } 329bf215546Sopenharmony_ci} 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_cistatic void 332bf215546Sopenharmony_cidestroy_put_job_nocopy(void *job, void *gdata, int thread_index) 333bf215546Sopenharmony_ci{ 334bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) job; 335bf215546Sopenharmony_ci free(dc_job->data); 336bf215546Sopenharmony_ci destroy_put_job(job, gdata, thread_index); 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_cistatic void 340bf215546Sopenharmony_cicache_put(void *job, void *gdata, int thread_index) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci assert(job); 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci unsigned i = 0; 345bf215546Sopenharmony_ci char *filename = NULL; 346bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = (struct disk_cache_put_job *) job; 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci if (env_var_as_boolean("MESA_DISK_CACHE_SINGLE_FILE", false)) { 349bf215546Sopenharmony_ci disk_cache_write_item_to_disk_foz(dc_job); 350bf215546Sopenharmony_ci } else { 351bf215546Sopenharmony_ci filename = disk_cache_get_cache_filename(dc_job->cache, dc_job->key); 352bf215546Sopenharmony_ci if (filename == NULL) 353bf215546Sopenharmony_ci goto done; 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci /* If the cache is too large, evict something else first. */ 356bf215546Sopenharmony_ci while (*dc_job->cache->size + dc_job->size > dc_job->cache->max_size && 357bf215546Sopenharmony_ci i < 8) { 358bf215546Sopenharmony_ci disk_cache_evict_lru_item(dc_job->cache); 359bf215546Sopenharmony_ci i++; 360bf215546Sopenharmony_ci } 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci disk_cache_write_item_to_disk(dc_job, filename); 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_cidone: 365bf215546Sopenharmony_ci free(filename); 366bf215546Sopenharmony_ci } 367bf215546Sopenharmony_ci} 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_civoid 370bf215546Sopenharmony_cidisk_cache_put(struct disk_cache *cache, const cache_key key, 371bf215546Sopenharmony_ci const void *data, size_t size, 372bf215546Sopenharmony_ci struct cache_item_metadata *cache_item_metadata) 373bf215546Sopenharmony_ci{ 374bf215546Sopenharmony_ci if (cache->blob_put_cb) { 375bf215546Sopenharmony_ci cache->blob_put_cb(key, CACHE_KEY_SIZE, data, size); 376bf215546Sopenharmony_ci return; 377bf215546Sopenharmony_ci } 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci if (cache->path_init_failed) 380bf215546Sopenharmony_ci return; 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = 383bf215546Sopenharmony_ci create_put_job(cache, key, (void*)data, size, cache_item_metadata, false); 384bf215546Sopenharmony_ci 385bf215546Sopenharmony_ci if (dc_job) { 386bf215546Sopenharmony_ci util_queue_fence_init(&dc_job->fence); 387bf215546Sopenharmony_ci util_queue_add_job(&cache->cache_queue, dc_job, &dc_job->fence, 388bf215546Sopenharmony_ci cache_put, destroy_put_job, dc_job->size); 389bf215546Sopenharmony_ci } 390bf215546Sopenharmony_ci} 391bf215546Sopenharmony_ci 392bf215546Sopenharmony_civoid 393bf215546Sopenharmony_cidisk_cache_put_nocopy(struct disk_cache *cache, const cache_key key, 394bf215546Sopenharmony_ci void *data, size_t size, 395bf215546Sopenharmony_ci struct cache_item_metadata *cache_item_metadata) 396bf215546Sopenharmony_ci{ 397bf215546Sopenharmony_ci if (cache->blob_put_cb) { 398bf215546Sopenharmony_ci cache->blob_put_cb(key, CACHE_KEY_SIZE, data, size); 399bf215546Sopenharmony_ci free(data); 400bf215546Sopenharmony_ci return; 401bf215546Sopenharmony_ci } 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_ci if (cache->path_init_failed) { 404bf215546Sopenharmony_ci free(data); 405bf215546Sopenharmony_ci return; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci struct disk_cache_put_job *dc_job = 409bf215546Sopenharmony_ci create_put_job(cache, key, data, size, cache_item_metadata, true); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci if (dc_job) { 412bf215546Sopenharmony_ci util_queue_fence_init(&dc_job->fence); 413bf215546Sopenharmony_ci util_queue_add_job(&cache->cache_queue, dc_job, &dc_job->fence, 414bf215546Sopenharmony_ci cache_put, destroy_put_job_nocopy, dc_job->size); 415bf215546Sopenharmony_ci } 416bf215546Sopenharmony_ci} 417bf215546Sopenharmony_ci 418bf215546Sopenharmony_civoid * 419bf215546Sopenharmony_cidisk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size) 420bf215546Sopenharmony_ci{ 421bf215546Sopenharmony_ci if (size) 422bf215546Sopenharmony_ci *size = 0; 423bf215546Sopenharmony_ci 424bf215546Sopenharmony_ci if (cache->blob_get_cb) { 425bf215546Sopenharmony_ci /* This is what Android EGL defines as the maxValueSize in egl_cache_t 426bf215546Sopenharmony_ci * class implementation. 427bf215546Sopenharmony_ci */ 428bf215546Sopenharmony_ci const signed long max_blob_size = 64 * 1024; 429bf215546Sopenharmony_ci void *blob = malloc(max_blob_size); 430bf215546Sopenharmony_ci if (!blob) 431bf215546Sopenharmony_ci return NULL; 432bf215546Sopenharmony_ci 433bf215546Sopenharmony_ci signed long bytes = 434bf215546Sopenharmony_ci cache->blob_get_cb(key, CACHE_KEY_SIZE, blob, max_blob_size); 435bf215546Sopenharmony_ci 436bf215546Sopenharmony_ci if (!bytes) { 437bf215546Sopenharmony_ci free(blob); 438bf215546Sopenharmony_ci return NULL; 439bf215546Sopenharmony_ci } 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci if (size) 442bf215546Sopenharmony_ci *size = bytes; 443bf215546Sopenharmony_ci return blob; 444bf215546Sopenharmony_ci } 445bf215546Sopenharmony_ci 446bf215546Sopenharmony_ci if (env_var_as_boolean("MESA_DISK_CACHE_SINGLE_FILE", false)) { 447bf215546Sopenharmony_ci return disk_cache_load_item_foz(cache, key, size); 448bf215546Sopenharmony_ci } else { 449bf215546Sopenharmony_ci char *filename = disk_cache_get_cache_filename(cache, key); 450bf215546Sopenharmony_ci if (filename == NULL) 451bf215546Sopenharmony_ci return NULL; 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci return disk_cache_load_item(cache, filename, size); 454bf215546Sopenharmony_ci } 455bf215546Sopenharmony_ci} 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_civoid 458bf215546Sopenharmony_cidisk_cache_put_key(struct disk_cache *cache, const cache_key key) 459bf215546Sopenharmony_ci{ 460bf215546Sopenharmony_ci const uint32_t *key_chunk = (const uint32_t *) key; 461bf215546Sopenharmony_ci int i = CPU_TO_LE32(*key_chunk) & CACHE_INDEX_KEY_MASK; 462bf215546Sopenharmony_ci unsigned char *entry; 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci if (cache->blob_put_cb) { 465bf215546Sopenharmony_ci cache->blob_put_cb(key, CACHE_KEY_SIZE, key_chunk, sizeof(uint32_t)); 466bf215546Sopenharmony_ci return; 467bf215546Sopenharmony_ci } 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci if (cache->path_init_failed) 470bf215546Sopenharmony_ci return; 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_ci entry = &cache->stored_keys[i * CACHE_KEY_SIZE]; 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_ci memcpy(entry, key, CACHE_KEY_SIZE); 475bf215546Sopenharmony_ci} 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci/* This function lets us test whether a given key was previously 478bf215546Sopenharmony_ci * stored in the cache with disk_cache_put_key(). The implement is 479bf215546Sopenharmony_ci * efficient by not using syscalls or hitting the disk. It's not 480bf215546Sopenharmony_ci * race-free, but the races are benign. If we race with someone else 481bf215546Sopenharmony_ci * calling disk_cache_put_key, then that's just an extra cache miss and an 482bf215546Sopenharmony_ci * extra recompile. 483bf215546Sopenharmony_ci */ 484bf215546Sopenharmony_cibool 485bf215546Sopenharmony_cidisk_cache_has_key(struct disk_cache *cache, const cache_key key) 486bf215546Sopenharmony_ci{ 487bf215546Sopenharmony_ci const uint32_t *key_chunk = (const uint32_t *) key; 488bf215546Sopenharmony_ci int i = CPU_TO_LE32(*key_chunk) & CACHE_INDEX_KEY_MASK; 489bf215546Sopenharmony_ci unsigned char *entry; 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci if (cache->blob_get_cb) { 492bf215546Sopenharmony_ci uint32_t blob; 493bf215546Sopenharmony_ci return cache->blob_get_cb(key, CACHE_KEY_SIZE, &blob, sizeof(uint32_t)); 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci 496bf215546Sopenharmony_ci if (cache->path_init_failed) 497bf215546Sopenharmony_ci return false; 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_ci entry = &cache->stored_keys[i * CACHE_KEY_SIZE]; 500bf215546Sopenharmony_ci 501bf215546Sopenharmony_ci return memcmp(entry, key, CACHE_KEY_SIZE) == 0; 502bf215546Sopenharmony_ci} 503bf215546Sopenharmony_ci 504bf215546Sopenharmony_civoid 505bf215546Sopenharmony_cidisk_cache_compute_key(struct disk_cache *cache, const void *data, size_t size, 506bf215546Sopenharmony_ci cache_key key) 507bf215546Sopenharmony_ci{ 508bf215546Sopenharmony_ci struct mesa_sha1 ctx; 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci _mesa_sha1_init(&ctx); 511bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, cache->driver_keys_blob, 512bf215546Sopenharmony_ci cache->driver_keys_blob_size); 513bf215546Sopenharmony_ci _mesa_sha1_update(&ctx, data, size); 514bf215546Sopenharmony_ci _mesa_sha1_final(&ctx, key); 515bf215546Sopenharmony_ci} 516bf215546Sopenharmony_ci 517bf215546Sopenharmony_civoid 518bf215546Sopenharmony_cidisk_cache_set_callbacks(struct disk_cache *cache, disk_cache_put_cb put, 519bf215546Sopenharmony_ci disk_cache_get_cb get) 520bf215546Sopenharmony_ci{ 521bf215546Sopenharmony_ci cache->blob_put_cb = put; 522bf215546Sopenharmony_ci cache->blob_get_cb = get; 523bf215546Sopenharmony_ci} 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci#endif /* ENABLE_SHADER_CACHE */ 526