1/* 2 * Copyright © 2021 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23#ifndef VK_PIPELINE_CACHE_H 24#define VK_PIPELINE_CACHE_H 25 26#include "vk_object.h" 27#include "vk_util.h" 28 29#include "util/simple_mtx.h" 30 31#ifdef __cplusplus 32extern "C" { 33#endif 34 35/* #include "util/blob.h" */ 36struct blob; 37struct blob_reader; 38 39/* #include "util/set.h" */ 40struct set; 41 42/* #include "compiler/nir/nir.h" */ 43struct nir_shader; 44struct nir_shader_compiler_options; 45 46struct vk_pipeline_cache; 47struct vk_pipeline_cache_object; 48 49#define VK_PIPELINE_CACHE_BLOB_ALIGN 8 50 51struct vk_pipeline_cache_object_ops { 52 /** Writes this cache object to the given blob 53 * 54 * Because the cache works with both raw blob data and driver object data 55 * and can't always tell the difference between the two, we have to be very 56 * careful about alignments when [de]serializing. When serialize() is 57 * called, the blob will be aligned to VK_PIPELINE_CACHE_BLOB_ALIGN. The 58 * driver must be careful to not [de]serialize any data types which require 59 * a higher alignment. When deserialize() is called, the blob_reader is 60 * also guaranteed to be aligned to VK_PIPELINE_CACHE_BLOB_ALIGN. 61 * 62 * Returns true on success 63 * 64 * This function is optional. Objects without [de]serialization support 65 * will still be cached in memory but will not be placed in the disk cache 66 * and will not exported to the client when vkGetPipelineCacheData() is 67 * called. 68 */ 69 bool (*serialize)(struct vk_pipeline_cache_object *object, 70 struct blob *blob); 71 72 /** Constructs an object from cached data 73 * 74 * See serialize() for details about data alignment. 75 * 76 * returns the created object 77 * 78 * This function is optional. 79 */ 80 struct vk_pipeline_cache_object *(*deserialize)(struct vk_device *device, 81 const void *key_data, 82 size_t key_size, 83 struct blob_reader *blob); 84 85 /** Destroys the object 86 * 87 * Called when vk_pipeline_cache_object.ref_cnt hits 0. 88 */ 89 void (*destroy)(struct vk_pipeline_cache_object *object); 90}; 91 92/** Base struct for cached objects 93 * 94 * A vk_pipeline_cache stores any number of vk_pipeline_cache_object's, each 95 * of which has an associated key of arbitrary size. Cached objects are 96 * reference counted so that they can exist in multiple caches (for example, 97 * when vkMergePipelineCaches() is called) and so that they can persist after 98 * the pipeline cache is destroyed. Each object also has a pointer to a 99 * vk_pipeline_cache_object_ops table which the pipeline cache uses to 100 * [de]serialize the object and clean it up when the reference count hits 0. 101 * 102 * The rest of the details of any given object are entirely up to the driver. 103 * The driver may even have multiple types of objects (distinguished by their 104 * vk_pipeline_cache_object_ops table) in the cache so long as it guarantees 105 * it never has two objects of different types with the same key. 106 */ 107struct vk_pipeline_cache_object { 108 struct vk_device *device; 109 const struct vk_pipeline_cache_object_ops *ops; 110 uint32_t ref_cnt; 111 112 uint32_t data_size; 113 const void *key_data; 114 uint32_t key_size; 115}; 116 117static inline void 118vk_pipeline_cache_object_init(struct vk_device *device, 119 struct vk_pipeline_cache_object *object, 120 const struct vk_pipeline_cache_object_ops *ops, 121 const void *key_data, uint32_t key_size) 122{ 123 memset(object, 0, sizeof(*object)); 124 object->device = device; 125 object->ops = ops; 126 p_atomic_set(&object->ref_cnt, 1); 127 object->data_size = 0; /* Unknown */ 128 object->key_data = key_data; 129 object->key_size = key_size; 130} 131 132static inline void 133vk_pipeline_cache_object_finish(struct vk_pipeline_cache_object *object) 134{ 135 assert(p_atomic_read(&object->ref_cnt) <= 1); 136} 137 138static inline struct vk_pipeline_cache_object * 139vk_pipeline_cache_object_ref(struct vk_pipeline_cache_object *object) 140{ 141 assert(object && p_atomic_read(&object->ref_cnt) >= 1); 142 p_atomic_inc(&object->ref_cnt); 143 return object; 144} 145 146static inline void 147vk_pipeline_cache_object_unref(struct vk_pipeline_cache_object *object) 148{ 149 assert(object && p_atomic_read(&object->ref_cnt) >= 1); 150 if (p_atomic_dec_zero(&object->ref_cnt)) 151 object->ops->destroy(object); 152} 153 154/** A generic implementation of VkPipelineCache */ 155struct vk_pipeline_cache { 156 struct vk_object_base base; 157 158 /* pCreateInfo::flags */ 159 VkPipelineCacheCreateFlags flags; 160 161 struct vk_pipeline_cache_header header; 162 163 /** Protects object_cache */ 164 simple_mtx_t lock; 165 166 struct set *object_cache; 167}; 168 169VK_DEFINE_NONDISP_HANDLE_CASTS(vk_pipeline_cache, base, VkPipelineCache, 170 VK_OBJECT_TYPE_PIPELINE_CACHE) 171 172struct vk_pipeline_cache_create_info { 173 /* The pCreateInfo for this pipeline cache, if any. 174 * 175 * For driver-internal caches, this is allowed to be NULL. 176 */ 177 const VkPipelineCacheCreateInfo *pCreateInfo; 178 179 /** If true, ignore VK_ENABLE_PIPELINE_CACHE and enable anyway */ 180 bool force_enable; 181}; 182 183struct vk_pipeline_cache * 184vk_pipeline_cache_create(struct vk_device *device, 185 const struct vk_pipeline_cache_create_info *info, 186 const VkAllocationCallbacks *pAllocator); 187void 188vk_pipeline_cache_destroy(struct vk_pipeline_cache *cache, 189 const VkAllocationCallbacks *pAllocator); 190 191/** Attempts to look up an object in the cache by key 192 * 193 * If an object is found in the cache matching the given key, *cache_hit is 194 * set to true and a reference to that object is returned. 195 * 196 * If the driver sets vk_device.disk_cache, we attempt to look up any missing 197 * objects in the disk cache before declaring failure. If an object is found 198 * in the disk cache but not the in-memory cache, *cache_hit is set to false. 199 * 200 * The deserialization of pipeline cache objects found in the cache data 201 * provided via VkPipelineCacheCreateInfo::pInitialData happens during 202 * vk_pipeline_cache_lookup() rather than during vkCreatePipelineCache(). 203 * Prior to the first vk_pipeline_cache_lookup() of a given object, it is 204 * stored as an internal raw data object with the same hash. This allows us 205 * to avoid any complex object type tagging in the serialized cache. It does, 206 * however, mean that drivers need to be careful to ensure that objects with 207 * different types (ops) have different keys. 208 * 209 * Returns a reference to the object, if found 210 */ 211struct vk_pipeline_cache_object * MUST_CHECK 212vk_pipeline_cache_lookup_object(struct vk_pipeline_cache *cache, 213 const void *key_data, size_t key_size, 214 const struct vk_pipeline_cache_object_ops *ops, 215 bool *cache_hit); 216 217/** Adds an object to the pipeline cache 218 * 219 * This function adds the given object to the pipeline cache. We do not 220 * specify a key here because the key is part of the object. See also 221 * vk_pipeline_cache_object_init(). 222 * 223 * This function consumes a reference to the object and returns a reference to 224 * the (possibly different) object in the cache. The intended usage pattern 225 * is as follows: 226 * 227 * key = compute_key(); 228 * struct vk_pipeline_cache_object *object = 229 * vk_pipeline_cache_lookup_object(cache, &key, sizeof(key), 230 * &driver_type_ops, &cache_hit); 231 * if (object != NULL) 232 * return container_of(object, driver_type, base); 233 * 234 * object = do_compile(); 235 * assert(object != NULL); 236 * 237 * object = vk_pipeline_cache_add_object(cache, object); 238 * return container_of(object, driver_type, base); 239 */ 240struct vk_pipeline_cache_object * MUST_CHECK 241vk_pipeline_cache_add_object(struct vk_pipeline_cache *cache, 242 struct vk_pipeline_cache_object *object); 243 244struct nir_shader * 245vk_pipeline_cache_lookup_nir(struct vk_pipeline_cache *cache, 246 const void *key_data, size_t key_size, 247 const struct nir_shader_compiler_options *nir_options, 248 bool *cache_hit, void *mem_ctx); 249void 250vk_pipeline_cache_add_nir(struct vk_pipeline_cache *cache, 251 const void *key_data, size_t key_size, 252 const struct nir_shader *nir); 253 254#ifdef __cplusplus 255} 256#endif 257 258#endif /* VK_PIPELINE_CACHE_H */ 259