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 24bf215546Sopenharmony_ci#include "vk_pipeline_cache.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "vk_alloc.h" 27bf215546Sopenharmony_ci#include "vk_common_entrypoints.h" 28bf215546Sopenharmony_ci#include "vk_device.h" 29bf215546Sopenharmony_ci#include "vk_log.h" 30bf215546Sopenharmony_ci#include "vk_physical_device.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "compiler/nir/nir_serialize.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "util/blob.h" 35bf215546Sopenharmony_ci#include "util/debug.h" 36bf215546Sopenharmony_ci#include "util/disk_cache.h" 37bf215546Sopenharmony_ci#include "util/hash_table.h" 38bf215546Sopenharmony_ci#include "util/set.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_cistruct raw_data_object { 41bf215546Sopenharmony_ci struct vk_pipeline_cache_object base; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci const void *data; 44bf215546Sopenharmony_ci size_t data_size; 45bf215546Sopenharmony_ci}; 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_cistatic struct raw_data_object * 48bf215546Sopenharmony_ciraw_data_object_create(struct vk_device *device, 49bf215546Sopenharmony_ci const void *key_data, size_t key_size, 50bf215546Sopenharmony_ci const void *data, size_t data_size); 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistatic bool 53bf215546Sopenharmony_ciraw_data_object_serialize(struct vk_pipeline_cache_object *object, 54bf215546Sopenharmony_ci struct blob *blob) 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci struct raw_data_object *data_obj = 57bf215546Sopenharmony_ci container_of(object, struct raw_data_object, base); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci blob_write_bytes(blob, data_obj->data, data_obj->data_size); 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci return true; 62bf215546Sopenharmony_ci} 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object * 65bf215546Sopenharmony_ciraw_data_object_deserialize(struct vk_device *device, 66bf215546Sopenharmony_ci const void *key_data, 67bf215546Sopenharmony_ci size_t key_size, 68bf215546Sopenharmony_ci struct blob_reader *blob) 69bf215546Sopenharmony_ci{ 70bf215546Sopenharmony_ci /* We consume the entire blob_reader. Each call to ops->deserialize() 71bf215546Sopenharmony_ci * happens with a brand new blob reader for error checking anyway so we 72bf215546Sopenharmony_ci * can assume the blob consumes the entire reader and we don't need to 73bf215546Sopenharmony_ci * serialize the data size separately. 74bf215546Sopenharmony_ci */ 75bf215546Sopenharmony_ci assert(blob->current < blob->end); 76bf215546Sopenharmony_ci size_t data_size = blob->end - blob->current; 77bf215546Sopenharmony_ci const void *data = blob_read_bytes(blob, data_size); 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci struct raw_data_object *data_obj = 80bf215546Sopenharmony_ci raw_data_object_create(device, key_data, key_size, data, data_size); 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci return data_obj ? &data_obj->base : NULL; 83bf215546Sopenharmony_ci} 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_cistatic void 86bf215546Sopenharmony_ciraw_data_object_destroy(struct vk_pipeline_cache_object *object) 87bf215546Sopenharmony_ci{ 88bf215546Sopenharmony_ci struct raw_data_object *data_obj = 89bf215546Sopenharmony_ci container_of(object, struct raw_data_object, base); 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci vk_free(&data_obj->base.device->alloc, data_obj); 92bf215546Sopenharmony_ci} 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_cistatic const struct vk_pipeline_cache_object_ops raw_data_object_ops = { 95bf215546Sopenharmony_ci .serialize = raw_data_object_serialize, 96bf215546Sopenharmony_ci .deserialize = raw_data_object_deserialize, 97bf215546Sopenharmony_ci .destroy = raw_data_object_destroy, 98bf215546Sopenharmony_ci}; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_cistatic struct raw_data_object * 101bf215546Sopenharmony_ciraw_data_object_create(struct vk_device *device, 102bf215546Sopenharmony_ci const void *key_data, size_t key_size, 103bf215546Sopenharmony_ci const void *data, size_t data_size) 104bf215546Sopenharmony_ci{ 105bf215546Sopenharmony_ci VK_MULTIALLOC(ma); 106bf215546Sopenharmony_ci VK_MULTIALLOC_DECL(&ma, struct raw_data_object, data_obj, 1); 107bf215546Sopenharmony_ci VK_MULTIALLOC_DECL_SIZE(&ma, char, obj_key_data, key_size); 108bf215546Sopenharmony_ci VK_MULTIALLOC_DECL_SIZE(&ma, char, obj_data, data_size); 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci if (!vk_multialloc_alloc(&ma, &device->alloc, 111bf215546Sopenharmony_ci VK_SYSTEM_ALLOCATION_SCOPE_DEVICE)) 112bf215546Sopenharmony_ci return NULL; 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci vk_pipeline_cache_object_init(device, &data_obj->base, 115bf215546Sopenharmony_ci &raw_data_object_ops, 116bf215546Sopenharmony_ci obj_key_data, key_size); 117bf215546Sopenharmony_ci data_obj->data = obj_data; 118bf215546Sopenharmony_ci data_obj->data_size = data_size; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci memcpy(obj_key_data, key_data, key_size); 121bf215546Sopenharmony_ci memcpy(obj_data, data, data_size); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ci return data_obj; 124bf215546Sopenharmony_ci} 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_cistatic bool 127bf215546Sopenharmony_ciobject_keys_equal(const void *void_a, const void *void_b) 128bf215546Sopenharmony_ci{ 129bf215546Sopenharmony_ci const struct vk_pipeline_cache_object *a = void_a, *b = void_b; 130bf215546Sopenharmony_ci if (a->key_size != b->key_size) 131bf215546Sopenharmony_ci return false; 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_ci return memcmp(a->key_data, b->key_data, a->key_size) == 0; 134bf215546Sopenharmony_ci} 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_cistatic uint32_t 137bf215546Sopenharmony_ciobject_key_hash(const void *void_object) 138bf215546Sopenharmony_ci{ 139bf215546Sopenharmony_ci const struct vk_pipeline_cache_object *object = void_object; 140bf215546Sopenharmony_ci return _mesa_hash_data(object->key_data, object->key_size); 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_cistatic void 144bf215546Sopenharmony_civk_pipeline_cache_lock(struct vk_pipeline_cache *cache) 145bf215546Sopenharmony_ci{ 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci if (!(cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT)) 148bf215546Sopenharmony_ci simple_mtx_lock(&cache->lock); 149bf215546Sopenharmony_ci} 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_cistatic void 152bf215546Sopenharmony_civk_pipeline_cache_unlock(struct vk_pipeline_cache *cache) 153bf215546Sopenharmony_ci{ 154bf215546Sopenharmony_ci if (!(cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT)) 155bf215546Sopenharmony_ci simple_mtx_unlock(&cache->lock); 156bf215546Sopenharmony_ci} 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_cistatic void 159bf215546Sopenharmony_civk_pipeline_cache_remove_object(struct vk_pipeline_cache *cache, 160bf215546Sopenharmony_ci uint32_t hash, 161bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object) 162bf215546Sopenharmony_ci{ 163bf215546Sopenharmony_ci vk_pipeline_cache_lock(cache); 164bf215546Sopenharmony_ci struct set_entry *entry = 165bf215546Sopenharmony_ci _mesa_set_search_pre_hashed(cache->object_cache, hash, object); 166bf215546Sopenharmony_ci if (entry && entry->key == (const void *)object) { 167bf215546Sopenharmony_ci /* Drop the reference owned by the cache */ 168bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(object); 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci _mesa_set_remove(cache->object_cache, entry); 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci vk_pipeline_cache_unlock(cache); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci /* Drop our reference */ 175bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(object); 176bf215546Sopenharmony_ci} 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci/* Consumes references to both search and replace and produces a reference */ 179bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object * 180bf215546Sopenharmony_civk_pipeline_cache_replace_object(struct vk_pipeline_cache *cache, 181bf215546Sopenharmony_ci uint32_t hash, 182bf215546Sopenharmony_ci struct vk_pipeline_cache_object *search, 183bf215546Sopenharmony_ci struct vk_pipeline_cache_object *replace) 184bf215546Sopenharmony_ci{ 185bf215546Sopenharmony_ci assert(object_keys_equal(search, replace)); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci vk_pipeline_cache_lock(cache); 188bf215546Sopenharmony_ci struct set_entry *entry = 189bf215546Sopenharmony_ci _mesa_set_search_pre_hashed(cache->object_cache, hash, search); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci struct vk_pipeline_cache_object *found = NULL; 192bf215546Sopenharmony_ci if (entry) { 193bf215546Sopenharmony_ci if (entry->key == (const void *)search) { 194bf215546Sopenharmony_ci /* Drop the reference owned by the cache */ 195bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(search); 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci entry->key = vk_pipeline_cache_object_ref(replace); 198bf215546Sopenharmony_ci } else { 199bf215546Sopenharmony_ci found = vk_pipeline_cache_object_ref((void *)entry->key); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci } else { 202bf215546Sopenharmony_ci /* I guess the object was purged? Re-add it to the cache */ 203bf215546Sopenharmony_ci vk_pipeline_cache_object_ref(replace); 204bf215546Sopenharmony_ci _mesa_set_add_pre_hashed(cache->object_cache, hash, replace); 205bf215546Sopenharmony_ci } 206bf215546Sopenharmony_ci vk_pipeline_cache_unlock(cache); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(search); 209bf215546Sopenharmony_ci 210bf215546Sopenharmony_ci if (found) { 211bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(replace); 212bf215546Sopenharmony_ci return found; 213bf215546Sopenharmony_ci } else { 214bf215546Sopenharmony_ci return replace; 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci} 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_cistatic bool 219bf215546Sopenharmony_civk_pipeline_cache_object_serialize(struct vk_pipeline_cache *cache, 220bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object, 221bf215546Sopenharmony_ci struct blob *blob, uint32_t *data_size) 222bf215546Sopenharmony_ci{ 223bf215546Sopenharmony_ci if (object->ops->serialize == NULL) 224bf215546Sopenharmony_ci return false; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci assert(blob->size == align64(blob->size, VK_PIPELINE_CACHE_BLOB_ALIGN)); 227bf215546Sopenharmony_ci size_t start = blob->size; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci /* Special case for if we're writing to a NULL blob (just to get the size) 230bf215546Sopenharmony_ci * and we already know the data size of the allocation. This should make 231bf215546Sopenharmony_ci * the first GetPipelineCacheData() call to get the data size faster in the 232bf215546Sopenharmony_ci * common case where a bunch of our objects were loaded from a previous 233bf215546Sopenharmony_ci * cache or where we've already serialized the cache once. 234bf215546Sopenharmony_ci */ 235bf215546Sopenharmony_ci if (blob->data == NULL && blob->fixed_allocation) { 236bf215546Sopenharmony_ci *data_size = p_atomic_read(&object->data_size); 237bf215546Sopenharmony_ci if (*data_size > 0) { 238bf215546Sopenharmony_ci blob_write_bytes(blob, NULL, *data_size); 239bf215546Sopenharmony_ci return true; 240bf215546Sopenharmony_ci } 241bf215546Sopenharmony_ci } 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci if (!object->ops->serialize(object, blob)) { 244bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), 245bf215546Sopenharmony_ci "Failed to serialize pipeline cache object"); 246bf215546Sopenharmony_ci return false; 247bf215546Sopenharmony_ci } 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_ci size_t size = blob->size - start; 250bf215546Sopenharmony_ci if (size > UINT32_MAX) { 251bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), 252bf215546Sopenharmony_ci "Skipping giant (4 GiB or larger) object"); 253bf215546Sopenharmony_ci return false; 254bf215546Sopenharmony_ci } 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci if (blob->out_of_memory) { 257bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), 258bf215546Sopenharmony_ci "Insufficient memory for pipeline cache data"); 259bf215546Sopenharmony_ci return false; 260bf215546Sopenharmony_ci } 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci *data_size = (uint32_t)size; 263bf215546Sopenharmony_ci p_atomic_set(&object->data_size, *data_size); 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci return true; 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_cistatic struct vk_pipeline_cache_object * 269bf215546Sopenharmony_civk_pipeline_cache_object_deserialize(struct vk_pipeline_cache *cache, 270bf215546Sopenharmony_ci const void *key_data, uint32_t key_size, 271bf215546Sopenharmony_ci const void *data, size_t data_size, 272bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops) 273bf215546Sopenharmony_ci{ 274bf215546Sopenharmony_ci if (ops == NULL) 275bf215546Sopenharmony_ci ops = &raw_data_object_ops; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci if (unlikely(ops->deserialize == NULL)) { 278bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), 279bf215546Sopenharmony_ci "Pipeline cache object cannot be deserialized"); 280bf215546Sopenharmony_ci return NULL; 281bf215546Sopenharmony_ci } 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci struct blob_reader reader; 284bf215546Sopenharmony_ci blob_reader_init(&reader, data, data_size); 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object = 287bf215546Sopenharmony_ci ops->deserialize(cache->base.device, key_data, key_size, &reader); 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci if (object == NULL) { 290bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), 291bf215546Sopenharmony_ci "Deserializing pipeline cache object failed"); 292bf215546Sopenharmony_ci return NULL; 293bf215546Sopenharmony_ci } 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci assert(reader.current == reader.end && !reader.overrun); 296bf215546Sopenharmony_ci assert(object->device == cache->base.device); 297bf215546Sopenharmony_ci assert(object->ops == ops); 298bf215546Sopenharmony_ci assert(object->ref_cnt == 1); 299bf215546Sopenharmony_ci assert(object->key_size == key_size); 300bf215546Sopenharmony_ci assert(memcmp(object->key_data, key_data, key_size) == 0); 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci return object; 303bf215546Sopenharmony_ci} 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_cistruct vk_pipeline_cache_object * 306bf215546Sopenharmony_civk_pipeline_cache_lookup_object(struct vk_pipeline_cache *cache, 307bf215546Sopenharmony_ci const void *key_data, size_t key_size, 308bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops, 309bf215546Sopenharmony_ci bool *cache_hit) 310bf215546Sopenharmony_ci{ 311bf215546Sopenharmony_ci assert(key_size <= UINT32_MAX); 312bf215546Sopenharmony_ci assert(ops != NULL); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci if (cache_hit != NULL) 315bf215546Sopenharmony_ci *cache_hit = false; 316bf215546Sopenharmony_ci 317bf215546Sopenharmony_ci struct vk_pipeline_cache_object key = { 318bf215546Sopenharmony_ci .key_data = key_data, 319bf215546Sopenharmony_ci .key_size = key_size, 320bf215546Sopenharmony_ci }; 321bf215546Sopenharmony_ci uint32_t hash = object_key_hash(&key); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object = NULL; 324bf215546Sopenharmony_ci 325bf215546Sopenharmony_ci if (cache != NULL && cache->object_cache != NULL) { 326bf215546Sopenharmony_ci vk_pipeline_cache_lock(cache); 327bf215546Sopenharmony_ci struct set_entry *entry = 328bf215546Sopenharmony_ci _mesa_set_search_pre_hashed(cache->object_cache, hash, &key); 329bf215546Sopenharmony_ci if (entry) { 330bf215546Sopenharmony_ci object = vk_pipeline_cache_object_ref((void *)entry->key); 331bf215546Sopenharmony_ci if (cache_hit != NULL) 332bf215546Sopenharmony_ci *cache_hit = true; 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci vk_pipeline_cache_unlock(cache); 335bf215546Sopenharmony_ci } 336bf215546Sopenharmony_ci 337bf215546Sopenharmony_ci if (object == NULL) { 338bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 339bf215546Sopenharmony_ci struct disk_cache *disk_cache = cache->base.device->physical->disk_cache; 340bf215546Sopenharmony_ci if (disk_cache != NULL && cache->object_cache != NULL) { 341bf215546Sopenharmony_ci cache_key cache_key; 342bf215546Sopenharmony_ci disk_cache_compute_key(disk_cache, key_data, key_size, cache_key); 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci size_t data_size; 345bf215546Sopenharmony_ci uint8_t *data = disk_cache_get(disk_cache, cache_key, &data_size); 346bf215546Sopenharmony_ci if (data) { 347bf215546Sopenharmony_ci object = vk_pipeline_cache_object_deserialize(cache, 348bf215546Sopenharmony_ci key_data, key_size, 349bf215546Sopenharmony_ci data, data_size, 350bf215546Sopenharmony_ci ops); 351bf215546Sopenharmony_ci free(data); 352bf215546Sopenharmony_ci if (object != NULL) 353bf215546Sopenharmony_ci return vk_pipeline_cache_add_object(cache, object); 354bf215546Sopenharmony_ci } 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci#endif 357bf215546Sopenharmony_ci 358bf215546Sopenharmony_ci /* No disk cache or not found in the disk cache */ 359bf215546Sopenharmony_ci return NULL; 360bf215546Sopenharmony_ci } 361bf215546Sopenharmony_ci 362bf215546Sopenharmony_ci if (object->ops == &raw_data_object_ops && ops != &raw_data_object_ops) { 363bf215546Sopenharmony_ci /* The object isn't fully formed yet and we need to deserialize it into 364bf215546Sopenharmony_ci * a real object before it can be used. 365bf215546Sopenharmony_ci */ 366bf215546Sopenharmony_ci struct raw_data_object *data_obj = 367bf215546Sopenharmony_ci container_of(object, struct raw_data_object, base); 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci struct vk_pipeline_cache_object *real_object = 370bf215546Sopenharmony_ci vk_pipeline_cache_object_deserialize(cache, 371bf215546Sopenharmony_ci data_obj->base.key_data, 372bf215546Sopenharmony_ci data_obj->base.key_size, 373bf215546Sopenharmony_ci data_obj->data, 374bf215546Sopenharmony_ci data_obj->data_size, ops); 375bf215546Sopenharmony_ci if (real_object == NULL) { 376bf215546Sopenharmony_ci vk_pipeline_cache_remove_object(cache, hash, object); 377bf215546Sopenharmony_ci return NULL; 378bf215546Sopenharmony_ci } 379bf215546Sopenharmony_ci 380bf215546Sopenharmony_ci object = vk_pipeline_cache_replace_object(cache, hash, object, 381bf215546Sopenharmony_ci real_object); 382bf215546Sopenharmony_ci } 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci assert(object->ops == ops); 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci return object; 387bf215546Sopenharmony_ci} 388bf215546Sopenharmony_ci 389bf215546Sopenharmony_cistruct vk_pipeline_cache_object * 390bf215546Sopenharmony_civk_pipeline_cache_add_object(struct vk_pipeline_cache *cache, 391bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object) 392bf215546Sopenharmony_ci{ 393bf215546Sopenharmony_ci assert(object->ops != NULL); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci if (cache->object_cache == NULL) 396bf215546Sopenharmony_ci return object; 397bf215546Sopenharmony_ci 398bf215546Sopenharmony_ci uint32_t hash = object_key_hash(object); 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci vk_pipeline_cache_lock(cache); 401bf215546Sopenharmony_ci bool found = false; 402bf215546Sopenharmony_ci struct set_entry *entry = 403bf215546Sopenharmony_ci _mesa_set_search_or_add_pre_hashed(cache->object_cache, 404bf215546Sopenharmony_ci hash, object, &found); 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci struct vk_pipeline_cache_object *found_object = NULL; 407bf215546Sopenharmony_ci if (found) { 408bf215546Sopenharmony_ci found_object = vk_pipeline_cache_object_ref((void *)entry->key); 409bf215546Sopenharmony_ci } else { 410bf215546Sopenharmony_ci /* The cache now owns a reference */ 411bf215546Sopenharmony_ci vk_pipeline_cache_object_ref(object); 412bf215546Sopenharmony_ci } 413bf215546Sopenharmony_ci vk_pipeline_cache_unlock(cache); 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci if (found) { 416bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(object); 417bf215546Sopenharmony_ci return found_object; 418bf215546Sopenharmony_ci } else { 419bf215546Sopenharmony_ci /* If it wasn't in the object cache, it might not be in the disk cache 420bf215546Sopenharmony_ci * either. Better try and add it. 421bf215546Sopenharmony_ci */ 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci#ifdef ENABLE_SHADER_CACHE 424bf215546Sopenharmony_ci struct disk_cache *disk_cache = cache->base.device->physical->disk_cache; 425bf215546Sopenharmony_ci if (object->ops->serialize != NULL && disk_cache) { 426bf215546Sopenharmony_ci struct blob blob; 427bf215546Sopenharmony_ci blob_init(&blob); 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci if (object->ops->serialize(object, &blob) && !blob.out_of_memory) { 430bf215546Sopenharmony_ci cache_key cache_key; 431bf215546Sopenharmony_ci disk_cache_compute_key(disk_cache, object->key_data, 432bf215546Sopenharmony_ci object->key_size, cache_key); 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci disk_cache_put(disk_cache, cache_key, blob.data, blob.size, NULL); 435bf215546Sopenharmony_ci } 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ci blob_finish(&blob); 438bf215546Sopenharmony_ci } 439bf215546Sopenharmony_ci#endif 440bf215546Sopenharmony_ci 441bf215546Sopenharmony_ci return object; 442bf215546Sopenharmony_ci } 443bf215546Sopenharmony_ci} 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_cinir_shader * 446bf215546Sopenharmony_civk_pipeline_cache_lookup_nir(struct vk_pipeline_cache *cache, 447bf215546Sopenharmony_ci const void *key_data, size_t key_size, 448bf215546Sopenharmony_ci const struct nir_shader_compiler_options *nir_options, 449bf215546Sopenharmony_ci bool *cache_hit, void *mem_ctx) 450bf215546Sopenharmony_ci{ 451bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object = 452bf215546Sopenharmony_ci vk_pipeline_cache_lookup_object(cache, key_data, key_size, 453bf215546Sopenharmony_ci &raw_data_object_ops, cache_hit); 454bf215546Sopenharmony_ci if (object == NULL) 455bf215546Sopenharmony_ci return NULL; 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci struct raw_data_object *data_obj = 458bf215546Sopenharmony_ci container_of(object, struct raw_data_object, base); 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci struct blob_reader blob; 461bf215546Sopenharmony_ci blob_reader_init(&blob, data_obj->data, data_obj->data_size); 462bf215546Sopenharmony_ci 463bf215546Sopenharmony_ci nir_shader *nir = nir_deserialize(mem_ctx, nir_options, &blob); 464bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(object); 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci if (blob.overrun) { 467bf215546Sopenharmony_ci ralloc_free(nir); 468bf215546Sopenharmony_ci return NULL; 469bf215546Sopenharmony_ci } 470bf215546Sopenharmony_ci 471bf215546Sopenharmony_ci return nir; 472bf215546Sopenharmony_ci} 473bf215546Sopenharmony_ci 474bf215546Sopenharmony_civoid 475bf215546Sopenharmony_civk_pipeline_cache_add_nir(struct vk_pipeline_cache *cache, 476bf215546Sopenharmony_ci const void *key_data, size_t key_size, 477bf215546Sopenharmony_ci const nir_shader *nir) 478bf215546Sopenharmony_ci{ 479bf215546Sopenharmony_ci struct blob blob; 480bf215546Sopenharmony_ci blob_init(&blob); 481bf215546Sopenharmony_ci 482bf215546Sopenharmony_ci nir_serialize(&blob, nir, false); 483bf215546Sopenharmony_ci if (blob.out_of_memory) { 484bf215546Sopenharmony_ci vk_logw(VK_LOG_OBJS(cache), "Ran out of memory serializing NIR shader"); 485bf215546Sopenharmony_ci blob_finish(&blob); 486bf215546Sopenharmony_ci return; 487bf215546Sopenharmony_ci } 488bf215546Sopenharmony_ci 489bf215546Sopenharmony_ci struct raw_data_object *data_obj = 490bf215546Sopenharmony_ci raw_data_object_create(cache->base.device, 491bf215546Sopenharmony_ci key_data, key_size, 492bf215546Sopenharmony_ci blob.data, blob.size); 493bf215546Sopenharmony_ci blob_finish(&blob); 494bf215546Sopenharmony_ci 495bf215546Sopenharmony_ci struct vk_pipeline_cache_object *cached = 496bf215546Sopenharmony_ci vk_pipeline_cache_add_object(cache, &data_obj->base); 497bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(cached); 498bf215546Sopenharmony_ci} 499bf215546Sopenharmony_ci 500bf215546Sopenharmony_cistatic int32_t 501bf215546Sopenharmony_cifind_type_for_ops(const struct vk_physical_device *pdevice, 502bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops) 503bf215546Sopenharmony_ci{ 504bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *const *import_ops = 505bf215546Sopenharmony_ci pdevice->pipeline_cache_import_ops; 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_ci if (import_ops == NULL) 508bf215546Sopenharmony_ci return -1; 509bf215546Sopenharmony_ci 510bf215546Sopenharmony_ci for (int32_t i = 0; import_ops[i]; i++) { 511bf215546Sopenharmony_ci if (import_ops[i] == ops) 512bf215546Sopenharmony_ci return i; 513bf215546Sopenharmony_ci } 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci return -1; 516bf215546Sopenharmony_ci} 517bf215546Sopenharmony_ci 518bf215546Sopenharmony_cistatic const struct vk_pipeline_cache_object_ops * 519bf215546Sopenharmony_cifind_ops_for_type(const struct vk_physical_device *pdevice, 520bf215546Sopenharmony_ci int32_t type) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *const *import_ops = 523bf215546Sopenharmony_ci pdevice->pipeline_cache_import_ops; 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci if (import_ops == NULL || type < 0) 526bf215546Sopenharmony_ci return NULL; 527bf215546Sopenharmony_ci 528bf215546Sopenharmony_ci return import_ops[type]; 529bf215546Sopenharmony_ci} 530bf215546Sopenharmony_ci 531bf215546Sopenharmony_cistatic void 532bf215546Sopenharmony_civk_pipeline_cache_load(struct vk_pipeline_cache *cache, 533bf215546Sopenharmony_ci const void *data, size_t size) 534bf215546Sopenharmony_ci{ 535bf215546Sopenharmony_ci struct blob_reader blob; 536bf215546Sopenharmony_ci blob_reader_init(&blob, data, size); 537bf215546Sopenharmony_ci 538bf215546Sopenharmony_ci struct vk_pipeline_cache_header header; 539bf215546Sopenharmony_ci blob_copy_bytes(&blob, &header, sizeof(header)); 540bf215546Sopenharmony_ci uint32_t count = blob_read_uint32(&blob); 541bf215546Sopenharmony_ci if (blob.overrun) 542bf215546Sopenharmony_ci return; 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_ci if (memcmp(&header, &cache->header, sizeof(header)) != 0) 545bf215546Sopenharmony_ci return; 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci for (uint32_t i = 0; i < count; i++) { 548bf215546Sopenharmony_ci int32_t type = blob_read_uint32(&blob); 549bf215546Sopenharmony_ci uint32_t key_size = blob_read_uint32(&blob); 550bf215546Sopenharmony_ci uint32_t data_size = blob_read_uint32(&blob); 551bf215546Sopenharmony_ci const void *key_data = blob_read_bytes(&blob, key_size); 552bf215546Sopenharmony_ci blob_reader_align(&blob, VK_PIPELINE_CACHE_BLOB_ALIGN); 553bf215546Sopenharmony_ci const void *data = blob_read_bytes(&blob, data_size); 554bf215546Sopenharmony_ci if (blob.overrun) 555bf215546Sopenharmony_ci break; 556bf215546Sopenharmony_ci 557bf215546Sopenharmony_ci const struct vk_pipeline_cache_object_ops *ops = 558bf215546Sopenharmony_ci find_ops_for_type(cache->base.device->physical, type); 559bf215546Sopenharmony_ci 560bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object = 561bf215546Sopenharmony_ci vk_pipeline_cache_object_deserialize(cache, 562bf215546Sopenharmony_ci key_data, key_size, 563bf215546Sopenharmony_ci data, data_size, ops); 564bf215546Sopenharmony_ci if (object == NULL) 565bf215546Sopenharmony_ci continue; 566bf215546Sopenharmony_ci 567bf215546Sopenharmony_ci object = vk_pipeline_cache_add_object(cache, object); 568bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(object); 569bf215546Sopenharmony_ci } 570bf215546Sopenharmony_ci} 571bf215546Sopenharmony_ci 572bf215546Sopenharmony_cistruct vk_pipeline_cache * 573bf215546Sopenharmony_civk_pipeline_cache_create(struct vk_device *device, 574bf215546Sopenharmony_ci const struct vk_pipeline_cache_create_info *info, 575bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator) 576bf215546Sopenharmony_ci{ 577bf215546Sopenharmony_ci static const struct VkPipelineCacheCreateInfo default_create_info = { 578bf215546Sopenharmony_ci .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, 579bf215546Sopenharmony_ci }; 580bf215546Sopenharmony_ci struct vk_pipeline_cache *cache; 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci const struct VkPipelineCacheCreateInfo *pCreateInfo = 583bf215546Sopenharmony_ci info->pCreateInfo != NULL ? info->pCreateInfo : &default_create_info; 584bf215546Sopenharmony_ci 585bf215546Sopenharmony_ci assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO); 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci cache = vk_object_zalloc(device, pAllocator, sizeof(*cache), 588bf215546Sopenharmony_ci VK_OBJECT_TYPE_PIPELINE_CACHE); 589bf215546Sopenharmony_ci if (cache == NULL) 590bf215546Sopenharmony_ci return NULL; 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci cache->flags = pCreateInfo->flags; 593bf215546Sopenharmony_ci 594bf215546Sopenharmony_ci struct VkPhysicalDeviceProperties pdevice_props; 595bf215546Sopenharmony_ci device->physical->dispatch_table.GetPhysicalDeviceProperties( 596bf215546Sopenharmony_ci vk_physical_device_to_handle(device->physical), &pdevice_props); 597bf215546Sopenharmony_ci 598bf215546Sopenharmony_ci cache->header = (struct vk_pipeline_cache_header) { 599bf215546Sopenharmony_ci .header_size = sizeof(struct vk_pipeline_cache_header), 600bf215546Sopenharmony_ci .header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE, 601bf215546Sopenharmony_ci .vendor_id = pdevice_props.vendorID, 602bf215546Sopenharmony_ci .device_id = pdevice_props.deviceID, 603bf215546Sopenharmony_ci }; 604bf215546Sopenharmony_ci memcpy(cache->header.uuid, pdevice_props.pipelineCacheUUID, VK_UUID_SIZE); 605bf215546Sopenharmony_ci 606bf215546Sopenharmony_ci simple_mtx_init(&cache->lock, mtx_plain); 607bf215546Sopenharmony_ci 608bf215546Sopenharmony_ci if (info->force_enable || 609bf215546Sopenharmony_ci env_var_as_boolean("VK_ENABLE_PIPELINE_CACHE", true)) { 610bf215546Sopenharmony_ci cache->object_cache = _mesa_set_create(NULL, object_key_hash, 611bf215546Sopenharmony_ci object_keys_equal); 612bf215546Sopenharmony_ci } 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_ci if (cache->object_cache && pCreateInfo->initialDataSize > 0) { 615bf215546Sopenharmony_ci vk_pipeline_cache_load(cache, pCreateInfo->pInitialData, 616bf215546Sopenharmony_ci pCreateInfo->initialDataSize); 617bf215546Sopenharmony_ci } 618bf215546Sopenharmony_ci 619bf215546Sopenharmony_ci return cache; 620bf215546Sopenharmony_ci} 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_cistatic void 623bf215546Sopenharmony_ciobject_unref_cb(struct set_entry *entry) 624bf215546Sopenharmony_ci{ 625bf215546Sopenharmony_ci vk_pipeline_cache_object_unref((void *)entry->key); 626bf215546Sopenharmony_ci} 627bf215546Sopenharmony_ci 628bf215546Sopenharmony_civoid 629bf215546Sopenharmony_civk_pipeline_cache_destroy(struct vk_pipeline_cache *cache, 630bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator) 631bf215546Sopenharmony_ci{ 632bf215546Sopenharmony_ci if (cache->object_cache) 633bf215546Sopenharmony_ci _mesa_set_destroy(cache->object_cache, object_unref_cb); 634bf215546Sopenharmony_ci simple_mtx_destroy(&cache->lock); 635bf215546Sopenharmony_ci vk_object_free(cache->base.device, pAllocator, cache); 636bf215546Sopenharmony_ci} 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL 639bf215546Sopenharmony_civk_common_CreatePipelineCache(VkDevice _device, 640bf215546Sopenharmony_ci const VkPipelineCacheCreateInfo *pCreateInfo, 641bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator, 642bf215546Sopenharmony_ci VkPipelineCache *pPipelineCache) 643bf215546Sopenharmony_ci{ 644bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_device, device, _device); 645bf215546Sopenharmony_ci struct vk_pipeline_cache *cache; 646bf215546Sopenharmony_ci 647bf215546Sopenharmony_ci struct vk_pipeline_cache_create_info info = { 648bf215546Sopenharmony_ci .pCreateInfo = pCreateInfo, 649bf215546Sopenharmony_ci }; 650bf215546Sopenharmony_ci cache = vk_pipeline_cache_create(device, &info, pAllocator); 651bf215546Sopenharmony_ci if (cache == NULL) 652bf215546Sopenharmony_ci return VK_ERROR_OUT_OF_HOST_MEMORY; 653bf215546Sopenharmony_ci 654bf215546Sopenharmony_ci *pPipelineCache = vk_pipeline_cache_to_handle(cache); 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci return VK_SUCCESS; 657bf215546Sopenharmony_ci} 658bf215546Sopenharmony_ci 659bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL 660bf215546Sopenharmony_civk_common_DestroyPipelineCache(VkDevice device, 661bf215546Sopenharmony_ci VkPipelineCache pipelineCache, 662bf215546Sopenharmony_ci const VkAllocationCallbacks *pAllocator) 663bf215546Sopenharmony_ci{ 664bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_pipeline_cache, cache, pipelineCache); 665bf215546Sopenharmony_ci 666bf215546Sopenharmony_ci if (cache == NULL) 667bf215546Sopenharmony_ci return; 668bf215546Sopenharmony_ci 669bf215546Sopenharmony_ci assert(cache->base.device == vk_device_from_handle(device)); 670bf215546Sopenharmony_ci vk_pipeline_cache_destroy(cache, pAllocator); 671bf215546Sopenharmony_ci} 672bf215546Sopenharmony_ci 673bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL 674bf215546Sopenharmony_civk_common_GetPipelineCacheData(VkDevice _device, 675bf215546Sopenharmony_ci VkPipelineCache pipelineCache, 676bf215546Sopenharmony_ci size_t *pDataSize, 677bf215546Sopenharmony_ci void *pData) 678bf215546Sopenharmony_ci{ 679bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_device, device, _device); 680bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_pipeline_cache, cache, pipelineCache); 681bf215546Sopenharmony_ci 682bf215546Sopenharmony_ci struct blob blob; 683bf215546Sopenharmony_ci if (pData) { 684bf215546Sopenharmony_ci blob_init_fixed(&blob, pData, *pDataSize); 685bf215546Sopenharmony_ci } else { 686bf215546Sopenharmony_ci blob_init_fixed(&blob, NULL, SIZE_MAX); 687bf215546Sopenharmony_ci } 688bf215546Sopenharmony_ci 689bf215546Sopenharmony_ci blob_write_bytes(&blob, &cache->header, sizeof(cache->header)); 690bf215546Sopenharmony_ci 691bf215546Sopenharmony_ci uint32_t count = 0; 692bf215546Sopenharmony_ci intptr_t count_offset = blob_reserve_uint32(&blob); 693bf215546Sopenharmony_ci if (count_offset < 0) { 694bf215546Sopenharmony_ci *pDataSize = 0; 695bf215546Sopenharmony_ci blob_finish(&blob); 696bf215546Sopenharmony_ci return VK_INCOMPLETE; 697bf215546Sopenharmony_ci } 698bf215546Sopenharmony_ci 699bf215546Sopenharmony_ci vk_pipeline_cache_lock(cache); 700bf215546Sopenharmony_ci 701bf215546Sopenharmony_ci VkResult result = VK_SUCCESS; 702bf215546Sopenharmony_ci if (cache->object_cache != NULL) { 703bf215546Sopenharmony_ci set_foreach(cache->object_cache, entry) { 704bf215546Sopenharmony_ci struct vk_pipeline_cache_object *object = (void *)entry->key; 705bf215546Sopenharmony_ci 706bf215546Sopenharmony_ci if (object->ops->serialize == NULL) 707bf215546Sopenharmony_ci continue; 708bf215546Sopenharmony_ci 709bf215546Sopenharmony_ci size_t blob_size_save = blob.size; 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci int32_t type = find_type_for_ops(device->physical, object->ops); 712bf215546Sopenharmony_ci blob_write_uint32(&blob, type); 713bf215546Sopenharmony_ci blob_write_uint32(&blob, object->key_size); 714bf215546Sopenharmony_ci intptr_t data_size_resv = blob_reserve_uint32(&blob); 715bf215546Sopenharmony_ci blob_write_bytes(&blob, object->key_data, object->key_size); 716bf215546Sopenharmony_ci 717bf215546Sopenharmony_ci blob_align(&blob, VK_PIPELINE_CACHE_BLOB_ALIGN); 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci uint32_t data_size; 720bf215546Sopenharmony_ci if (!vk_pipeline_cache_object_serialize(cache, object, 721bf215546Sopenharmony_ci &blob, &data_size)) { 722bf215546Sopenharmony_ci blob.size = blob_size_save; 723bf215546Sopenharmony_ci if (blob.out_of_memory) { 724bf215546Sopenharmony_ci result = VK_INCOMPLETE; 725bf215546Sopenharmony_ci break; 726bf215546Sopenharmony_ci } 727bf215546Sopenharmony_ci 728bf215546Sopenharmony_ci /* Failed for some other reason; keep going */ 729bf215546Sopenharmony_ci continue; 730bf215546Sopenharmony_ci } 731bf215546Sopenharmony_ci 732bf215546Sopenharmony_ci /* vk_pipeline_cache_object_serialize should have failed */ 733bf215546Sopenharmony_ci assert(!blob.out_of_memory); 734bf215546Sopenharmony_ci 735bf215546Sopenharmony_ci assert(data_size_resv >= 0); 736bf215546Sopenharmony_ci blob_overwrite_uint32(&blob, data_size_resv, data_size); 737bf215546Sopenharmony_ci } 738bf215546Sopenharmony_ci } 739bf215546Sopenharmony_ci 740bf215546Sopenharmony_ci vk_pipeline_cache_unlock(cache); 741bf215546Sopenharmony_ci 742bf215546Sopenharmony_ci blob_overwrite_uint32(&blob, count_offset, count); 743bf215546Sopenharmony_ci 744bf215546Sopenharmony_ci *pDataSize = blob.size; 745bf215546Sopenharmony_ci 746bf215546Sopenharmony_ci blob_finish(&blob); 747bf215546Sopenharmony_ci 748bf215546Sopenharmony_ci return result; 749bf215546Sopenharmony_ci} 750bf215546Sopenharmony_ci 751bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL 752bf215546Sopenharmony_civk_common_MergePipelineCaches(VkDevice device, 753bf215546Sopenharmony_ci VkPipelineCache dstCache, 754bf215546Sopenharmony_ci uint32_t srcCacheCount, 755bf215546Sopenharmony_ci const VkPipelineCache *pSrcCaches) 756bf215546Sopenharmony_ci{ 757bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_pipeline_cache, dst, dstCache); 758bf215546Sopenharmony_ci 759bf215546Sopenharmony_ci if (!dst->object_cache) 760bf215546Sopenharmony_ci return VK_SUCCESS; 761bf215546Sopenharmony_ci 762bf215546Sopenharmony_ci vk_pipeline_cache_lock(dst); 763bf215546Sopenharmony_ci 764bf215546Sopenharmony_ci for (uint32_t i = 0; i < srcCacheCount; i++) { 765bf215546Sopenharmony_ci VK_FROM_HANDLE(vk_pipeline_cache, src, pSrcCaches[i]); 766bf215546Sopenharmony_ci 767bf215546Sopenharmony_ci if (!src->object_cache) 768bf215546Sopenharmony_ci continue; 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci assert(src != dst); 771bf215546Sopenharmony_ci if (src == dst) 772bf215546Sopenharmony_ci continue; 773bf215546Sopenharmony_ci 774bf215546Sopenharmony_ci vk_pipeline_cache_lock(src); 775bf215546Sopenharmony_ci 776bf215546Sopenharmony_ci set_foreach(src->object_cache, src_entry) { 777bf215546Sopenharmony_ci struct vk_pipeline_cache_object *src_object = (void *)src_entry->key; 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci bool found_in_dst = false; 780bf215546Sopenharmony_ci struct set_entry *dst_entry = 781bf215546Sopenharmony_ci _mesa_set_search_or_add_pre_hashed(dst->object_cache, 782bf215546Sopenharmony_ci src_entry->hash, 783bf215546Sopenharmony_ci src_object, &found_in_dst); 784bf215546Sopenharmony_ci if (found_in_dst) { 785bf215546Sopenharmony_ci struct vk_pipeline_cache_object *dst_object = (void *)dst_entry->key; 786bf215546Sopenharmony_ci if (dst_object->ops == &raw_data_object_ops && 787bf215546Sopenharmony_ci src_object->ops != &raw_data_object_ops) { 788bf215546Sopenharmony_ci /* Even though dst has the object, it only has the blob version 789bf215546Sopenharmony_ci * which isn't as useful. Replace it with the real object. 790bf215546Sopenharmony_ci */ 791bf215546Sopenharmony_ci vk_pipeline_cache_object_unref(dst_object); 792bf215546Sopenharmony_ci dst_entry->key = vk_pipeline_cache_object_ref(src_object); 793bf215546Sopenharmony_ci } 794bf215546Sopenharmony_ci } else { 795bf215546Sopenharmony_ci /* We inserted src_object in dst so it needs a reference */ 796bf215546Sopenharmony_ci assert(dst_entry->key == (const void *)src_object); 797bf215546Sopenharmony_ci vk_pipeline_cache_object_ref(src_object); 798bf215546Sopenharmony_ci } 799bf215546Sopenharmony_ci } 800bf215546Sopenharmony_ci 801bf215546Sopenharmony_ci vk_pipeline_cache_unlock(src); 802bf215546Sopenharmony_ci } 803bf215546Sopenharmony_ci 804bf215546Sopenharmony_ci vk_pipeline_cache_unlock(dst); 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci return VK_SUCCESS; 807bf215546Sopenharmony_ci} 808