/*1* Copyright © 2014 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#ifndef DISK_CACHE_H24#define DISK_CACHE_H2526#ifdef HAVE_DLFCN_H27#include <dlfcn.h>28#include <stdio.h>29#include "util/build_id.h"30#endif31#include <assert.h>32#include <stdint.h>33#include <stdbool.h>34#include <sys/stat.h>35#include "util/mesa-sha1.h"3637#ifdef __cplusplus38extern "C" {39#endif4041/* Size of cache keys in bytes. */42#define CACHE_KEY_SIZE 204344#define CACHE_DIR_NAME "mesa_shader_cache"45#define CACHE_DIR_NAME_SF "mesa_shader_cache_sf"4647typedef uint8_t cache_key[CACHE_KEY_SIZE];4849/* WARNING: 3rd party applications might be reading the cache item metadata.50* Do not change these values without making the change widely known.51* Please contact Valve developers and make them aware of this change.52*/53#define CACHE_ITEM_TYPE_UNKNOWN 0x054#define CACHE_ITEM_TYPE_GLSL 0x15556typedef void57(*disk_cache_put_cb) (const void *key, signed long keySize,58const void *value, signed long valueSize);5960typedef signed long61(*disk_cache_get_cb) (const void *key, signed long keySize,62void *value, signed long valueSize);6364struct cache_item_metadata {65/**66* The cache item type. This could be used to identify a GLSL cache item,67* a certain type of IR (tgsi, nir, etc), or signal that it is the final68* binary form of the shader.69*/70uint32_t type;7172/** GLSL cache item metadata */73cache_key *keys; /* sha1 list of shaders that make up the cache item */74uint32_t num_keys;75};7677struct disk_cache;7879static inline char *80disk_cache_format_hex_id(char *buf, const uint8_t *hex_id, unsigned size)81{82static const char hex_digits[] = "0123456789abcdef";83unsigned i;8485for (i = 0; i < size; i += 2) {86buf[i] = hex_digits[hex_id[i >> 1] >> 4];87buf[i + 1] = hex_digits[hex_id[i >> 1] & 0x0f];88}89buf[i] = '\0';9091return buf;92}9394#ifdef HAVE_DLADDR95static inline bool96disk_cache_get_function_timestamp(void *ptr, uint32_t* timestamp)97{98Dl_info info;99struct stat st;100if (!dladdr(ptr, &info) || !info.dli_fname) {101return false;102}103if (stat(info.dli_fname, &st)) {104return false;105}106107if (!st.st_mtime) {108fprintf(stderr, "Mesa: The provided filesystem timestamp for the cache "109"is bogus! Disabling On-disk cache.\n");110return false;111}112113*timestamp = st.st_mtime;114115return true;116}117118static inline bool119disk_cache_get_function_identifier(void *ptr, struct mesa_sha1 *ctx)120{121uint32_t timestamp;122123#ifdef HAVE_DL_ITERATE_PHDR124const struct build_id_note *note = NULL;125if ((note = build_id_find_nhdr_for_addr(ptr))) {126_mesa_sha1_update(ctx, build_id_data(note), build_id_length(note));127} else128#endif129if (disk_cache_get_function_timestamp(ptr, ×tamp)) {130_mesa_sha1_update(ctx, ×tamp, sizeof(timestamp));131} else132return false;133return true;134}135#else136static inline bool137disk_cache_get_function_identifier(void *ptr, struct mesa_sha1 *ctx)138{139return false;140}141#endif142143/* Provide inlined stub functions if the shader cache is disabled. */144145#ifdef ENABLE_SHADER_CACHE146147/**148* Create a new cache object.149*150* This function creates the handle necessary for all subsequent cache_*151* functions.152*153* This cache provides two distinct operations:154*155* o Storage and retrieval of arbitrary objects by cryptographic156* name (or "key"). This is provided via disk_cache_put() and157* disk_cache_get().158*159* o The ability to store a key alone and check later whether the160* key was previously stored. This is provided via disk_cache_put_key()161* and disk_cache_has_key().162*163* The put_key()/has_key() operations are conceptually identical to164* put()/get() with no data, but are provided separately to allow for165* a more efficient implementation.166*167* In all cases, the keys are sequences of 20 bytes. It is anticipated168* that callers will compute appropriate SHA-1 signatures for keys,169* (though nothing in this implementation directly relies on how the170* names are computed). See mesa-sha1.h and _mesa_sha1_compute for171* assistance in computing SHA-1 signatures.172*/173struct disk_cache *174disk_cache_create(const char *gpu_name, const char *timestamp,175uint64_t driver_flags);176177/**178* Destroy a cache object, (freeing all associated resources).179*/180void181disk_cache_destroy(struct disk_cache *cache);182183/* Wait for all previous disk_cache_put() calls to be processed (used for unit184* testing).185*/186void187disk_cache_wait_for_idle(struct disk_cache *cache);188189/**190* Remove the item in the cache under the name \key.191*/192void193disk_cache_remove(struct disk_cache *cache, const cache_key key);194195/**196* Store an item in the cache under the name \key.197*198* The item can be retrieved later with disk_cache_get(), (unless the item has199* been evicted in the interim).200*201* Any call to disk_cache_put() may cause an existing, random item to be202* evicted from the cache.203*/204void205disk_cache_put(struct disk_cache *cache, const cache_key key,206const void *data, size_t size,207struct cache_item_metadata *cache_item_metadata);208209/**210* Store an item in the cache under the name \key without copying the data param.211*212* The item can be retrieved later with disk_cache_get(), (unless the item has213* been evicted in the interim).214*215* Any call to disk_cache_put() may cause an existing, random item to be216* evicted from the cache.217*218* @p data will be freed219*/220void221disk_cache_put_nocopy(struct disk_cache *cache, const cache_key key,222void *data, size_t size,223struct cache_item_metadata *cache_item_metadata);224225/**226* Retrieve an item previously stored in the cache with the name <key>.227*228* The item must have been previously stored with a call to disk_cache_put().229*230* If \size is non-NULL, then, on successful return, it will be set to the231* size of the object.232*233* \return A pointer to the stored object if found. NULL if the object234* is not found, or if any error occurs, (memory allocation failure,235* filesystem error, etc.). The returned data is malloc'ed so the236* caller should call free() it when finished.237*/238void *239disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size);240241/**242* Store the name \key within the cache, (without any associated data).243*244* Later this key can be checked with disk_cache_has_key(), (unless the key245* has been evicted in the interim).246*247* Any call to disk_cache_put_key() may cause an existing, random key to be248* evicted from the cache.249*/250void251disk_cache_put_key(struct disk_cache *cache, const cache_key key);252253/**254* Test whether the name \key was previously recorded in the cache.255*256* Return value: True if disk_cache_put_key() was previously called with257* \key, (and the key was not evicted in the interim).258*259* Note: disk_cache_has_key() will only return true for keys passed to260* disk_cache_put_key(). Specifically, a call to disk_cache_put() will not cause261* disk_cache_has_key() to return true for the same key.262*/263bool264disk_cache_has_key(struct disk_cache *cache, const cache_key key);265266/**267* Compute the name \key from \data of given \size.268*/269void270disk_cache_compute_key(struct disk_cache *cache, const void *data, size_t size,271cache_key key);272273void274disk_cache_set_callbacks(struct disk_cache *cache, disk_cache_put_cb put,275disk_cache_get_cb get);276277#else278279static inline struct disk_cache *280disk_cache_create(const char *gpu_name, const char *timestamp,281uint64_t driver_flags)282{283return NULL;284}285286static inline void287disk_cache_destroy(struct disk_cache *cache) {288return;289}290291static inline void292disk_cache_put(struct disk_cache *cache, const cache_key key,293const void *data, size_t size,294struct cache_item_metadata *cache_item_metadata)295{296return;297}298299static inline void300disk_cache_put_nocopy(struct disk_cache *cache, const cache_key key,301void *data, size_t size,302struct cache_item_metadata *cache_item_metadata)303{304return;305}306307static inline void308disk_cache_remove(struct disk_cache *cache, const cache_key key)309{310return;311}312313static inline uint8_t *314disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size)315{316return NULL;317}318319static inline void320disk_cache_put_key(struct disk_cache *cache, const cache_key key)321{322return;323}324325static inline bool326disk_cache_has_key(struct disk_cache *cache, const cache_key key)327{328return false;329}330331static inline void332disk_cache_compute_key(struct disk_cache *cache, const void *data, size_t size,333const cache_key key)334{335return;336}337338static inline void339disk_cache_set_callbacks(struct disk_cache *cache, disk_cache_put_cb put,340disk_cache_get_cb get)341{342return;343}344345#endif /* ENABLE_SHADER_CACHE */346347#ifdef __cplusplus348}349#endif350351#endif /* CACHE_H */352353354