radeonsi: add workaround for issue 2647
[mesa.git] / src / util / disk_cache.h
index d4d939883e61a7e9331bd451e757facf356b6c51..09b316e6e8d0600e35c224dcea923d7b5d4bf1e3 100644 (file)
 #ifndef DISK_CACHE_H
 #define DISK_CACHE_H
 
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#include <stdio.h>
+#include "util/build_id.h"
+#endif
+#include <assert.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <sys/stat.h>
+#include "util/mesa-sha1.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -34,8 +42,98 @@ extern "C" {
 /* Size of cache keys in bytes. */
 #define CACHE_KEY_SIZE 20
 
+#define CACHE_DIR_NAME "mesa_shader_cache"
+
 typedef uint8_t cache_key[CACHE_KEY_SIZE];
 
+/* WARNING: 3rd party applications might be reading the cache item metadata.
+ * Do not change these values without making the change widely known.
+ * Please contact Valve developers and make them aware of this change.
+ */
+#define CACHE_ITEM_TYPE_UNKNOWN  0x0
+#define CACHE_ITEM_TYPE_GLSL     0x1
+
+typedef void
+(*disk_cache_put_cb) (const void *key, signed long keySize,
+                      const void *value, signed long valueSize);
+
+typedef signed long
+(*disk_cache_get_cb) (const void *key, signed long keySize,
+                      void *value, signed long valueSize);
+
+struct cache_item_metadata {
+   /**
+    * The cache item type. This could be used to identify a GLSL cache item,
+    * a certain type of IR (tgsi, nir, etc), or signal that it is the final
+    * binary form of the shader.
+    */
+   uint32_t type;
+
+   /** GLSL cache item metadata */
+   cache_key *keys;   /* sha1 list of shaders that make up the cache item */
+   uint32_t num_keys;
+};
+
+struct disk_cache;
+
+static inline char *
+disk_cache_format_hex_id(char *buf, const uint8_t *hex_id, unsigned size)
+{
+   static const char hex_digits[] = "0123456789abcdef";
+   unsigned i;
+
+   for (i = 0; i < size; i += 2) {
+      buf[i] = hex_digits[hex_id[i >> 1] >> 4];
+      buf[i + 1] = hex_digits[hex_id[i >> 1] & 0x0f];
+   }
+   buf[i] = '\0';
+
+   return buf;
+}
+
+#ifdef HAVE_DLADDR
+static inline bool
+disk_cache_get_function_timestamp(void *ptr, uint32_t* timestamp)
+{
+   Dl_info info;
+   struct stat st;
+   if (!dladdr(ptr, &info) || !info.dli_fname) {
+      return false;
+   }
+   if (stat(info.dli_fname, &st)) {
+      return false;
+   }
+
+   if (!st.st_mtime) {
+      fprintf(stderr, "Mesa: The provided filesystem timestamp for the cache "
+              "is bogus! Disabling On-disk cache.\n");
+      return false;
+   }
+
+   *timestamp = st.st_mtime;
+
+   return true;
+}
+
+static inline bool
+disk_cache_get_function_identifier(void *ptr, struct mesa_sha1 *ctx)
+{
+   uint32_t timestamp;
+
+#ifdef HAVE_DL_ITERATE_PHDR
+   const struct build_id_note *note = NULL;
+   if ((note = build_id_find_nhdr_for_addr(ptr))) {
+      _mesa_sha1_update(ctx, build_id_data(note), build_id_length(note));
+   } else
+#endif
+   if (disk_cache_get_function_timestamp(ptr, &timestamp)) {
+      _mesa_sha1_update(ctx, &timestamp, sizeof(timestamp));
+   } else
+      return false;
+   return true;
+}
+#endif
+
 /* Provide inlined stub functions if the shader cache is disabled. */
 
 #ifdef ENABLE_SHADER_CACHE
@@ -49,12 +147,12 @@ typedef uint8_t cache_key[CACHE_KEY_SIZE];
  * This cache provides two distinct operations:
  *
  *   o Storage and retrieval of arbitrary objects by cryptographic
- *     name (or "key").  This is provided via cache_put() and
- *     cache_get().
+ *     name (or "key").  This is provided via disk_cache_put() and
+ *     disk_cache_get().
  *
  *   o The ability to store a key alone and check later whether the
- *     key was previously stored. This is provided via cache_put_key()
- *     and cache_has_key().
+ *     key was previously stored. This is provided via disk_cache_put_key()
+ *     and disk_cache_has_key().
  *
  * The put_key()/has_key() operations are conceptually identical to
  * put()/get() with no data, but are provided separately to allow for
@@ -66,32 +164,46 @@ typedef uint8_t cache_key[CACHE_KEY_SIZE];
  * names are computed). See mesa-sha1.h and _mesa_sha1_compute for
  * assistance in computing SHA-1 signatures.
  */
-struct program_cache *
-cache_create(void);
+struct disk_cache *
+disk_cache_create(const char *gpu_name, const char *timestamp,
+                  uint64_t driver_flags);
 
 /**
  * Destroy a cache object, (freeing all associated resources).
  */
 void
-cache_destroy(struct program_cache *cache);
+disk_cache_destroy(struct disk_cache *cache);
+
+/* Wait for all previous disk_cache_put() calls to be processed (used for unit
+ * testing).
+ */
+void
+disk_cache_wait_for_idle(struct disk_cache *cache);
+
+/**
+ * Remove the item in the cache under the name \key.
+ */
+void
+disk_cache_remove(struct disk_cache *cache, const cache_key key);
 
 /**
  * Store an item in the cache under the name \key.
  *
- * The item can be retrieved later with cache_get(), (unless the item has
+ * The item can be retrieved later with disk_cache_get(), (unless the item has
  * been evicted in the interim).
  *
- * Any call to cache_put() may cause an existing, random item to be
+ * Any call to disk_cache_put() may cause an existing, random item to be
  * evicted from the cache.
  */
 void
-cache_put(struct program_cache *cache, cache_key key,
-          const void *data, size_t size);
+disk_cache_put(struct disk_cache *cache, const cache_key key,
+               const void *data, size_t size,
+               struct cache_item_metadata *cache_item_metadata);
 
 /**
  * Retrieve an item previously stored in the cache with the name <key>.
  *
- * The item must have been previously stored with a call to cache_put().
+ * The item must have been previously stored with a call to disk_cache_put().
  *
  * If \size is non-NULL, then, on successful return, it will be set to the
  * size of the object.
@@ -102,71 +214,104 @@ cache_put(struct program_cache *cache, cache_key key,
  * caller should call free() it when finished.
  */
 void *
-cache_get(struct program_cache *cache, cache_key key, size_t *size);
+disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size);
 
 /**
  * Store the name \key within the cache, (without any associated data).
  *
- * Later this key can be checked with cache_has_key(), (unless the key
+ * Later this key can be checked with disk_cache_has_key(), (unless the key
  * has been evicted in the interim).
  *
- * Any call to cache_record() may cause an existing, random key to be
+ * Any call to disk_cache_put_key() may cause an existing, random key to be
  * evicted from the cache.
  */
 void
-cache_put_key(struct program_cache *cache, cache_key key);
+disk_cache_put_key(struct disk_cache *cache, const cache_key key);
 
 /**
  * Test whether the name \key was previously recorded in the cache.
  *
- * Return value: True if cache_put_key() was previously called with
+ * Return value: True if disk_cache_put_key() was previously called with
  * \key, (and the key was not evicted in the interim).
  *
- * Note: cache_has_key() will only return true for keys passed to
- * cache_put_key(). Specifically, a call to cache_put() will not cause
- * cache_has_key() to return true for the same key.
+ * Note: disk_cache_has_key() will only return true for keys passed to
+ * disk_cache_put_key(). Specifically, a call to disk_cache_put() will not cause
+ * disk_cache_has_key() to return true for the same key.
  */
 bool
-cache_has_key(struct program_cache *cache, cache_key key);
+disk_cache_has_key(struct disk_cache *cache, const cache_key key);
+
+/**
+ * Compute the name \key from \data of given \size.
+ */
+void
+disk_cache_compute_key(struct disk_cache *cache, const void *data, size_t size,
+                       cache_key key);
+
+void
+disk_cache_set_callbacks(struct disk_cache *cache, disk_cache_put_cb put,
+                         disk_cache_get_cb get);
 
 #else
 
-static inline struct program_cache *
-cache_create(void)
+static inline struct disk_cache *
+disk_cache_create(const char *gpu_name, const char *timestamp,
+                  uint64_t driver_flags)
 {
    return NULL;
 }
 
 static inline void
-cache_destroy(struct program_cache *cache) {
+disk_cache_destroy(struct disk_cache *cache) {
+   return;
+}
+
+static inline void
+disk_cache_put(struct disk_cache *cache, const cache_key key,
+               const void *data, size_t size,
+               struct cache_item_metadata *cache_item_metadata)
+{
    return;
 }
 
 static inline void
-cache_put(struct program_cache *cache, cache_key key,
-          const void *data, size_t size)
+disk_cache_remove(struct disk_cache *cache, const cache_key key)
 {
    return;
 }
 
 static inline uint8_t *
-cache_get(struct program_cache *cache, cache_key key, size_t *size)
+disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size)
 {
    return NULL;
 }
 
 static inline void
-cache_put_key(struct program_cache *cache, cache_key key)
+disk_cache_put_key(struct disk_cache *cache, const cache_key key)
 {
    return;
 }
 
 static inline bool
-cache_has_key(struct program_cache *cache, cache_key key)
+disk_cache_has_key(struct disk_cache *cache, const cache_key key)
 {
    return false;
 }
 
+static inline void
+disk_cache_compute_key(struct disk_cache *cache, const void *data, size_t size,
+                       const cache_key key)
+{
+   return;
+}
+
+static inline void
+disk_cache_set_callbacks(struct disk_cache *cache, disk_cache_put_cb put,
+                         disk_cache_get_cb get)
+{
+   return;
+}
+
 #endif /* ENABLE_SHADER_CACHE */
 
 #ifdef __cplusplus