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