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