1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2021 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#ifndef VK_PIPELINE_CACHE_H 24bf215546Sopenharmony_ci#define VK_PIPELINE_CACHE_H 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "vk_object.h" 27bf215546Sopenharmony_ci#include "vk_util.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "util/simple_mtx.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#ifdef __cplusplus 32bf215546Sopenharmony_ciextern "C" { 33bf215546Sopenharmony_ci#endif 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci/* #include "util/blob.h" */ 36bf215546Sopenharmony_cistruct blob; 37bf215546Sopenharmony_cistruct blob_reader; 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci/* #include "util/set.h" */ 40bf215546Sopenharmony_cistruct set; 41bf215546Sopenharmony_ci 42bf215546Sopenharmony_ci/* #include "compiler/nir/nir.h" */ 43bf215546Sopenharmony_cistruct nir_shader; 44bf215546Sopenharmony_cistruct nir_shader_compiler_options; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_cistruct vk_pipeline_cache; 47bf215546Sopenharmony_cistruct vk_pipeline_cache_object; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci#define VK_PIPELINE_CACHE_BLOB_ALIGN 8 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_cistruct vk_pipeline_cache_object_ops { 52bf215546Sopenharmony_ci /** Writes this cache object to the given blob 53bf215546Sopenharmony_ci * 54bf215546Sopenharmony_ci * Because the cache works with both raw blob data and driver object data 55bf215546Sopenharmony_ci * and can't always tell the difference between the two, we have to be very 56bf215546Sopenharmony_ci * careful about alignments when [de]serializing. When serialize() is 57bf215546Sopenharmony_ci * called, the blob will be aligned to VK_PIPELINE_CACHE_BLOB_ALIGN. The 58bf215546Sopenharmony_ci * driver must be careful to not [de]serialize any data types which require 59bf215546Sopenharmony_ci * a higher alignment. When deserialize() is called, the blob_reader is 60bf215546Sopenharmony_ci * also guaranteed to be aligned to VK_PIPELINE_CACHE_BLOB_ALIGN. 61bf215546Sopenharmony_ci * 62bf215546Sopenharmony_ci * Returns true on success 63bf215546Sopenharmony_ci * 64bf215546Sopenharmony_ci * This function is optional. Objects without [de]serialization support 65bf215546Sopenharmony_ci * will still be cached in memory but will not be placed in the disk cache 66bf215546Sopenharmony_ci * and will not exported to the client when vkGetPipelineCacheData() is 67bf215546Sopenharmony_ci * called. 68bf215546Sopenharmony_ci */ 69bf215546Sopenharmony_ci bool (*serialize)(struct vk_pipeline_cache_object *object, 70bf215546Sopenharmony_ci struct blob *blob); 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci /** Constructs an object from cached data 73bf215546Sopenharmony_ci * 74bf215546Sopenharmony_ci * See serialize() for details about data alignment. 75bf215546Sopenharmony_ci * 76bf215546Sopenharmony_ci * returns the created object 77bf215546Sopenharmony_ci * 78bf215546Sopenharmony_ci * This function is optional. 79bf215546Sopenharmony_ci */ 80bf215546Sopenharmony_ci struct vk_pipeline_cache_object *(*deserialize)(struct vk_device *device, 81bf215546Sopenharmony_ci const void *key_data, 82bf215546Sopenharmony_ci size_t key_size, 83bf215546Sopenharmony_ci struct blob_reader *blob); 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci /** Destroys the object 86bf215546Sopenharmony_ci * 87bf215546Sopenharmony_ci * Called when vk_pipeline_cache_object.ref_cnt hits 0. 88bf215546Sopenharmony_ci */ 89bf215546Sopenharmony_ci void (*destroy)(struct vk_pipeline_cache_object *object); 90bf215546Sopenharmony_ci}; 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci/** Base struct for cached objects 93bf215546Sopenharmony_ci * 94bf215546Sopenharmony_ci * A vk_pipeline_cache stores any number of vk_pipeline_cache_object's, each 95bf215546Sopenharmony_ci * of which has an associated key of arbitrary size. Cached objects are 96bf215546Sopenharmony_ci * reference counted so that they can exist in multiple caches (for example, 97bf215546Sopenharmony_ci * when vkMergePipelineCaches() is called) and so that they can persist after 98bf215546Sopenharmony_ci * the pipeline cache is destroyed. Each object also has a pointer to a 99bf215546Sopenharmony_ci * vk_pipeline_cache_object_ops table which the pipeline cache uses to 100bf215546Sopenharmony_ci * [de]serialize the object and clean it up when the reference count hits 0. 101bf215546Sopenharmony_ci * 102bf215546Sopenharmony_ci * The rest of the details of any given object are entirely up to the driver. 103bf215546Sopenharmony_ci * The driver may even have multiple types of objects (distinguished by their 104bf215546Sopenharmony_ci * vk_pipeline_cache_object_ops table) in the cache so long as it guarantees 105bf215546Sopenharmony_ci * it never has two objects of different types with the same key. 106bf215546Sopenharmony_ci */ 107bf215546Sopenharmony_cistruct vk_pipeline_cache_object { 108bf215546Sopenharmony_ci struct vk_device *device; 109bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops; 110bf215546Sopenharmony_ci uint32_t ref_cnt; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci uint32_t data_size; 113bf215546Sopenharmony_ci const void *key_data; 114bf215546Sopenharmony_ci uint32_t key_size; 115bf215546Sopenharmony_ci}; 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_cistatic inline void 118bf215546Sopenharmony_civk_pipeline_cache_object_init(struct vk_device *device, 119bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object, 120bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops, 121bf215546Sopenharmony_ci const void *key_data, uint32_t key_size) 122bf215546Sopenharmony_ci{ 123bf215546Sopenharmony_ci memset(object, 0, sizeof(*object)); 124bf215546Sopenharmony_ci object->device = device; 125bf215546Sopenharmony_ci object->ops = ops; 126bf215546Sopenharmony_ci p_atomic_set(&object->ref_cnt, 1); 127bf215546Sopenharmony_ci object->data_size = 0; /* Unknown */ 128bf215546Sopenharmony_ci object->key_data = key_data; 129bf215546Sopenharmony_ci object->key_size = key_size; 130bf215546Sopenharmony_ci} 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_cistatic inline void 133bf215546Sopenharmony_civk_pipeline_cache_object_finish(struct vk_pipeline_cache_object *object) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci assert(p_atomic_read(&object->ref_cnt) <= 1); 136bf215546Sopenharmony_ci} 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_cistatic inline struct vk_pipeline_cache_object * 139bf215546Sopenharmony_civk_pipeline_cache_object_ref(struct vk_pipeline_cache_object *object) 140bf215546Sopenharmony_ci{ 141bf215546Sopenharmony_ci assert(object && p_atomic_read(&object->ref_cnt) >= 1); 142bf215546Sopenharmony_ci p_atomic_inc(&object->ref_cnt); 143bf215546Sopenharmony_ci return object; 144bf215546Sopenharmony_ci} 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_cistatic inline void 147bf215546Sopenharmony_civk_pipeline_cache_object_unref(struct vk_pipeline_cache_object *object) 148bf215546Sopenharmony_ci{ 149bf215546Sopenharmony_ci assert(object && p_atomic_read(&object->ref_cnt) >= 1); 150bf215546Sopenharmony_ci if (p_atomic_dec_zero(&object->ref_cnt)) 151bf215546Sopenharmony_ci object->ops->destroy(object); 152bf215546Sopenharmony_ci} 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci/** A generic implementation of VkPipelineCache */ 155bf215546Sopenharmony_cistruct vk_pipeline_cache { 156bf215546Sopenharmony_ci struct vk_object_base base; 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci /* pCreateInfo::flags */ 159bf215546Sopenharmony_ci VkPipelineCacheCreateFlags flags; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci struct vk_pipeline_cache_header header; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci /** Protects object_cache */ 164bf215546Sopenharmony_ci simple_mtx_t lock; 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci struct set *object_cache; 167bf215546Sopenharmony_ci}; 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ciVK_DEFINE_NONDISP_HANDLE_CASTS(vk_pipeline_cache, base, VkPipelineCache, 170bf215546Sopenharmony_ci VK_OBJECT_TYPE_PIPELINE_CACHE) 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_cistruct vk_pipeline_cache_create_info { 173bf215546Sopenharmony_ci /* The pCreateInfo for this pipeline cache, if any. 174bf215546Sopenharmony_ci * 175bf215546Sopenharmony_ci * For driver-internal caches, this is allowed to be NULL. 176bf215546Sopenharmony_ci */ 177bf215546Sopenharmony_ci const VkPipelineCacheCreateInfo *pCreateInfo; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci /** If true, ignore VK_ENABLE_PIPELINE_CACHE and enable anyway */ 180bf215546Sopenharmony_ci bool force_enable; 181bf215546Sopenharmony_ci}; 182bf215546Sopenharmony_ci 183bf215546Sopenharmony_cistruct vk_pipeline_cache * 184bf215546Sopenharmony_civk_pipeline_cache_create(struct vk_device *device, 185bf215546Sopenharmony_ci const struct vk_pipeline_cache_create_info *info, 186bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator); 187bf215546Sopenharmony_civoid 188bf215546Sopenharmony_civk_pipeline_cache_destroy(struct vk_pipeline_cache *cache, 189bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci/** Attempts to look up an object in the cache by key 192bf215546Sopenharmony_ci * 193bf215546Sopenharmony_ci * If an object is found in the cache matching the given key, *cache_hit is 194bf215546Sopenharmony_ci * set to true and a reference to that object is returned. 195bf215546Sopenharmony_ci * 196bf215546Sopenharmony_ci * If the driver sets vk_device.disk_cache, we attempt to look up any missing 197bf215546Sopenharmony_ci * objects in the disk cache before declaring failure. If an object is found 198bf215546Sopenharmony_ci * in the disk cache but not the in-memory cache, *cache_hit is set to false. 199bf215546Sopenharmony_ci * 200bf215546Sopenharmony_ci * The deserialization of pipeline cache objects found in the cache data 201bf215546Sopenharmony_ci * provided via VkPipelineCacheCreateInfo::pInitialData happens during 202bf215546Sopenharmony_ci * vk_pipeline_cache_lookup() rather than during vkCreatePipelineCache(). 203bf215546Sopenharmony_ci * Prior to the first vk_pipeline_cache_lookup() of a given object, it is 204bf215546Sopenharmony_ci * stored as an internal raw data object with the same hash. This allows us 205bf215546Sopenharmony_ci * to avoid any complex object type tagging in the serialized cache. It does, 206bf215546Sopenharmony_ci * however, mean that drivers need to be careful to ensure that objects with 207bf215546Sopenharmony_ci * different types (ops) have different keys. 208bf215546Sopenharmony_ci * 209bf215546Sopenharmony_ci * Returns a reference to the object, if found 210bf215546Sopenharmony_ci */ 211bf215546Sopenharmony_cistruct vk_pipeline_cache_object * MUST_CHECK 212bf215546Sopenharmony_civk_pipeline_cache_lookup_object(struct vk_pipeline_cache *cache, 213bf215546Sopenharmony_ci const void *key_data, size_t key_size, 214bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops, 215bf215546Sopenharmony_ci bool *cache_hit); 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci/** Adds an object to the pipeline cache 218bf215546Sopenharmony_ci * 219bf215546Sopenharmony_ci * This function adds the given object to the pipeline cache. We do not 220bf215546Sopenharmony_ci * specify a key here because the key is part of the object. See also 221bf215546Sopenharmony_ci * vk_pipeline_cache_object_init(). 222bf215546Sopenharmony_ci * 223bf215546Sopenharmony_ci * This function consumes a reference to the object and returns a reference to 224bf215546Sopenharmony_ci * the (possibly different) object in the cache. The intended usage pattern 225bf215546Sopenharmony_ci * is as follows: 226bf215546Sopenharmony_ci * 227bf215546Sopenharmony_ci * key = compute_key(); 228bf215546Sopenharmony_ci * struct vk_pipeline_cache_object *object = 229bf215546Sopenharmony_ci * vk_pipeline_cache_lookup_object(cache, &key, sizeof(key), 230bf215546Sopenharmony_ci * &driver_type_ops, &cache_hit); 231bf215546Sopenharmony_ci * if (object != NULL) 232bf215546Sopenharmony_ci * return container_of(object, driver_type, base); 233bf215546Sopenharmony_ci * 234bf215546Sopenharmony_ci * object = do_compile(); 235bf215546Sopenharmony_ci * assert(object != NULL); 236bf215546Sopenharmony_ci * 237bf215546Sopenharmony_ci * object = vk_pipeline_cache_add_object(cache, object); 238bf215546Sopenharmony_ci * return container_of(object, driver_type, base); 239bf215546Sopenharmony_ci */ 240bf215546Sopenharmony_cistruct vk_pipeline_cache_object * MUST_CHECK 241bf215546Sopenharmony_civk_pipeline_cache_add_object(struct vk_pipeline_cache *cache, 242bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object); 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_cistruct nir_shader * 245bf215546Sopenharmony_civk_pipeline_cache_lookup_nir(struct vk_pipeline_cache *cache, 246bf215546Sopenharmony_ci const void *key_data, size_t key_size, 247bf215546Sopenharmony_ci const struct nir_shader_compiler_options *nir_options, 248bf215546Sopenharmony_ci bool *cache_hit, void *mem_ctx); 249bf215546Sopenharmony_civoid 250bf215546Sopenharmony_civk_pipeline_cache_add_nir(struct vk_pipeline_cache *cache, 251bf215546Sopenharmony_ci const void *key_data, size_t key_size, 252bf215546Sopenharmony_ci const struct nir_shader *nir); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci#ifdef __cplusplus 255bf215546Sopenharmony_ci} 256bf215546Sopenharmony_ci#endif 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci#endif /* VK_PIPELINE_CACHE_H */ 259