1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 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 "util/debug.h"
25bf215546Sopenharmony_ci#include "util/disk_cache.h"
26bf215546Sopenharmony_ci#include "util/macros.h"
27bf215546Sopenharmony_ci#include "util/mesa-sha1.h"
28bf215546Sopenharmony_ci#include "util/u_atomic.h"
29bf215546Sopenharmony_ci#include "vulkan/util/vk_util.h"
30bf215546Sopenharmony_ci#include "radv_debug.h"
31bf215546Sopenharmony_ci#include "radv_private.h"
32bf215546Sopenharmony_ci#include "radv_shader.h"
33bf215546Sopenharmony_ci#include "aco_interface.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_cistruct cache_entry {
36bf215546Sopenharmony_ci   union {
37bf215546Sopenharmony_ci      unsigned char sha1[20];
38bf215546Sopenharmony_ci      uint32_t sha1_dw[5];
39bf215546Sopenharmony_ci   };
40bf215546Sopenharmony_ci   uint32_t binary_sizes[MESA_VULKAN_SHADER_STAGES];
41bf215546Sopenharmony_ci   uint32_t num_stack_sizes;
42bf215546Sopenharmony_ci   struct radv_shader *shaders[MESA_VULKAN_SHADER_STAGES];
43bf215546Sopenharmony_ci   struct radv_pipeline_slab *slab;
44bf215546Sopenharmony_ci   char code[0];
45bf215546Sopenharmony_ci};
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_cistatic void
48bf215546Sopenharmony_ciradv_pipeline_cache_lock(struct radv_pipeline_cache *cache)
49bf215546Sopenharmony_ci{
50bf215546Sopenharmony_ci   if (cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT)
51bf215546Sopenharmony_ci      return;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   mtx_lock(&cache->mutex);
54bf215546Sopenharmony_ci}
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_cistatic void
57bf215546Sopenharmony_ciradv_pipeline_cache_unlock(struct radv_pipeline_cache *cache)
58bf215546Sopenharmony_ci{
59bf215546Sopenharmony_ci   if (cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT)
60bf215546Sopenharmony_ci      return;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   mtx_unlock(&cache->mutex);
63bf215546Sopenharmony_ci}
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_cistatic bool
66bf215546Sopenharmony_ciradv_is_cache_disabled(struct radv_device *device)
67bf215546Sopenharmony_ci{
68bf215546Sopenharmony_ci   /* Pipeline caches can be disabled with RADV_DEBUG=nocache, with MESA_GLSL_CACHE_DISABLE=1 and
69bf215546Sopenharmony_ci    * when ACO_DEBUG is used. MESA_GLSL_CACHE_DISABLE is done elsewhere.
70bf215546Sopenharmony_ci    */
71bf215546Sopenharmony_ci   return (device->instance->debug_flags & RADV_DEBUG_NO_CACHE) ||
72bf215546Sopenharmony_ci          (device->physical_device->use_llvm ? 0 : aco_get_codegen_flags());
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_civoid
76bf215546Sopenharmony_ciradv_pipeline_cache_init(struct radv_pipeline_cache *cache, struct radv_device *device)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   vk_object_base_init(&device->vk, &cache->base, VK_OBJECT_TYPE_PIPELINE_CACHE);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   cache->device = device;
81bf215546Sopenharmony_ci   mtx_init(&cache->mutex, mtx_plain);
82bf215546Sopenharmony_ci   cache->flags = 0;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   cache->modified = false;
85bf215546Sopenharmony_ci   cache->kernel_count = 0;
86bf215546Sopenharmony_ci   cache->total_size = 0;
87bf215546Sopenharmony_ci   cache->table_size = 1024;
88bf215546Sopenharmony_ci   const size_t byte_size = cache->table_size * sizeof(cache->hash_table[0]);
89bf215546Sopenharmony_ci   cache->hash_table = malloc(byte_size);
90bf215546Sopenharmony_ci
91bf215546Sopenharmony_ci   /* We don't consider allocation failure fatal, we just start with a 0-sized
92bf215546Sopenharmony_ci    * cache. Disable caching when we want to keep shader debug info, since
93bf215546Sopenharmony_ci    * we don't get the debug info on cached shaders. */
94bf215546Sopenharmony_ci   if (cache->hash_table == NULL || radv_is_cache_disabled(device))
95bf215546Sopenharmony_ci      cache->table_size = 0;
96bf215546Sopenharmony_ci   else
97bf215546Sopenharmony_ci      memset(cache->hash_table, 0, byte_size);
98bf215546Sopenharmony_ci}
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_civoid
101bf215546Sopenharmony_ciradv_pipeline_cache_finish(struct radv_pipeline_cache *cache)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   for (unsigned i = 0; i < cache->table_size; ++i)
104bf215546Sopenharmony_ci      if (cache->hash_table[i]) {
105bf215546Sopenharmony_ci         for (int j = 0; j < MESA_VULKAN_SHADER_STAGES; ++j) {
106bf215546Sopenharmony_ci            if (cache->hash_table[i]->shaders[j])
107bf215546Sopenharmony_ci               radv_shader_destroy(cache->device, cache->hash_table[i]->shaders[j]);
108bf215546Sopenharmony_ci         }
109bf215546Sopenharmony_ci         if (cache->hash_table[i]->slab)
110bf215546Sopenharmony_ci            radv_pipeline_slab_destroy(cache->device, cache->hash_table[i]->slab);
111bf215546Sopenharmony_ci         vk_free(&cache->alloc, cache->hash_table[i]);
112bf215546Sopenharmony_ci      }
113bf215546Sopenharmony_ci   mtx_destroy(&cache->mutex);
114bf215546Sopenharmony_ci   free(cache->hash_table);
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   vk_object_base_finish(&cache->base);
117bf215546Sopenharmony_ci}
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_cistatic uint32_t
120bf215546Sopenharmony_cientry_size(struct cache_entry *entry)
121bf215546Sopenharmony_ci{
122bf215546Sopenharmony_ci   size_t ret = sizeof(*entry);
123bf215546Sopenharmony_ci   for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i)
124bf215546Sopenharmony_ci      if (entry->binary_sizes[i])
125bf215546Sopenharmony_ci         ret += entry->binary_sizes[i];
126bf215546Sopenharmony_ci   ret += sizeof(struct radv_pipeline_shader_stack_size) * entry->num_stack_sizes;
127bf215546Sopenharmony_ci   ret = align(ret, alignof(struct cache_entry));
128bf215546Sopenharmony_ci   return ret;
129bf215546Sopenharmony_ci}
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_civoid
132bf215546Sopenharmony_ciradv_hash_shaders(unsigned char *hash, const struct radv_pipeline_stage *stages,
133bf215546Sopenharmony_ci                  const struct radv_pipeline_layout *layout, const struct radv_pipeline_key *key,
134bf215546Sopenharmony_ci                  uint32_t flags)
135bf215546Sopenharmony_ci{
136bf215546Sopenharmony_ci   struct mesa_sha1 ctx;
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   _mesa_sha1_init(&ctx);
139bf215546Sopenharmony_ci   if (key)
140bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, key, sizeof(*key));
141bf215546Sopenharmony_ci   if (layout)
142bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, layout->sha1, sizeof(layout->sha1));
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   for (unsigned s = 0; s < MESA_VULKAN_SHADER_STAGES; s++) {
145bf215546Sopenharmony_ci      if (!stages[s].entrypoint)
146bf215546Sopenharmony_ci         continue;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, stages[s].shader_sha1, sizeof(stages[s].shader_sha1));
149bf215546Sopenharmony_ci   }
150bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, &flags, 4);
151bf215546Sopenharmony_ci   _mesa_sha1_final(&ctx, hash);
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_civoid
155bf215546Sopenharmony_ciradv_hash_rt_shaders(unsigned char *hash, const VkRayTracingPipelineCreateInfoKHR *pCreateInfo,
156bf215546Sopenharmony_ci                     uint32_t flags)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_pipeline_layout, layout, pCreateInfo->layout);
159bf215546Sopenharmony_ci   struct mesa_sha1 ctx;
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci   _mesa_sha1_init(&ctx);
162bf215546Sopenharmony_ci   if (layout)
163bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, layout->sha1, sizeof(layout->sha1));
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->stageCount; ++i) {
166bf215546Sopenharmony_ci      RADV_FROM_HANDLE(vk_shader_module, module, pCreateInfo->pStages[i].module);
167bf215546Sopenharmony_ci      const VkSpecializationInfo *spec_info = pCreateInfo->pStages[i].pSpecializationInfo;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci      const VkPipelineShaderStageModuleIdentifierCreateInfoEXT *iinfo =
170bf215546Sopenharmony_ci         vk_find_struct_const(pCreateInfo->pStages[i].pNext,
171bf215546Sopenharmony_ci               PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT);
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci      if (module) {
174bf215546Sopenharmony_ci         _mesa_sha1_update(&ctx, module->sha1, sizeof(module->sha1));
175bf215546Sopenharmony_ci      } else {
176bf215546Sopenharmony_ci         assert(iinfo);
177bf215546Sopenharmony_ci         assert(iinfo->identifierSize <= VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT);
178bf215546Sopenharmony_ci         _mesa_sha1_update(&ctx, iinfo->pIdentifier, iinfo->identifierSize);
179bf215546Sopenharmony_ci      }
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, pCreateInfo->pStages[i].pName, strlen(pCreateInfo->pStages[i].pName));
182bf215546Sopenharmony_ci      if (spec_info && spec_info->mapEntryCount) {
183bf215546Sopenharmony_ci         _mesa_sha1_update(&ctx, spec_info->pMapEntries,
184bf215546Sopenharmony_ci                           spec_info->mapEntryCount * sizeof spec_info->pMapEntries[0]);
185bf215546Sopenharmony_ci         _mesa_sha1_update(&ctx, spec_info->pData, spec_info->dataSize);
186bf215546Sopenharmony_ci      }
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   for (uint32_t i = 0; i < pCreateInfo->groupCount; i++) {
190bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->pGroups[i].type,
191bf215546Sopenharmony_ci                        sizeof(pCreateInfo->pGroups[i].type));
192bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->pGroups[i].generalShader,
193bf215546Sopenharmony_ci                        sizeof(pCreateInfo->pGroups[i].generalShader));
194bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->pGroups[i].anyHitShader,
195bf215546Sopenharmony_ci                        sizeof(pCreateInfo->pGroups[i].anyHitShader));
196bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->pGroups[i].closestHitShader,
197bf215546Sopenharmony_ci                        sizeof(pCreateInfo->pGroups[i].closestHitShader));
198bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->pGroups[i].intersectionShader,
199bf215546Sopenharmony_ci                        sizeof(pCreateInfo->pGroups[i].intersectionShader));
200bf215546Sopenharmony_ci   }
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   if (!radv_rt_pipeline_has_dynamic_stack_size(pCreateInfo))
203bf215546Sopenharmony_ci      _mesa_sha1_update(&ctx, &pCreateInfo->maxPipelineRayRecursionDepth, 4);
204bf215546Sopenharmony_ci   _mesa_sha1_update(&ctx, &flags, 4);
205bf215546Sopenharmony_ci   _mesa_sha1_final(&ctx, hash);
206bf215546Sopenharmony_ci}
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_cistatic struct cache_entry *
209bf215546Sopenharmony_ciradv_pipeline_cache_search_unlocked(struct radv_pipeline_cache *cache, const unsigned char *sha1)
210bf215546Sopenharmony_ci{
211bf215546Sopenharmony_ci   const uint32_t mask = cache->table_size - 1;
212bf215546Sopenharmony_ci   const uint32_t start = (*(uint32_t *)sha1);
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci   if (cache->table_size == 0)
215bf215546Sopenharmony_ci      return NULL;
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   for (uint32_t i = 0; i < cache->table_size; i++) {
218bf215546Sopenharmony_ci      const uint32_t index = (start + i) & mask;
219bf215546Sopenharmony_ci      struct cache_entry *entry = cache->hash_table[index];
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci      if (!entry)
222bf215546Sopenharmony_ci         return NULL;
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci      if (memcmp(entry->sha1, sha1, sizeof(entry->sha1)) == 0) {
225bf215546Sopenharmony_ci         return entry;
226bf215546Sopenharmony_ci      }
227bf215546Sopenharmony_ci   }
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci   unreachable("hash table should never be full");
230bf215546Sopenharmony_ci}
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_cistatic struct cache_entry *
233bf215546Sopenharmony_ciradv_pipeline_cache_search(struct radv_pipeline_cache *cache, const unsigned char *sha1)
234bf215546Sopenharmony_ci{
235bf215546Sopenharmony_ci   struct cache_entry *entry;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   radv_pipeline_cache_lock(cache);
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   entry = radv_pipeline_cache_search_unlocked(cache, sha1);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   radv_pipeline_cache_unlock(cache);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   return entry;
244bf215546Sopenharmony_ci}
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_cistatic void
247bf215546Sopenharmony_ciradv_pipeline_cache_set_entry(struct radv_pipeline_cache *cache, struct cache_entry *entry)
248bf215546Sopenharmony_ci{
249bf215546Sopenharmony_ci   const uint32_t mask = cache->table_size - 1;
250bf215546Sopenharmony_ci   const uint32_t start = entry->sha1_dw[0];
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   /* We'll always be able to insert when we get here. */
253bf215546Sopenharmony_ci   assert(cache->kernel_count < cache->table_size / 2);
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci   for (uint32_t i = 0; i < cache->table_size; i++) {
256bf215546Sopenharmony_ci      const uint32_t index = (start + i) & mask;
257bf215546Sopenharmony_ci      if (!cache->hash_table[index]) {
258bf215546Sopenharmony_ci         cache->hash_table[index] = entry;
259bf215546Sopenharmony_ci         break;
260bf215546Sopenharmony_ci      }
261bf215546Sopenharmony_ci   }
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   cache->total_size += entry_size(entry);
264bf215546Sopenharmony_ci   cache->kernel_count++;
265bf215546Sopenharmony_ci}
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_cistatic VkResult
268bf215546Sopenharmony_ciradv_pipeline_cache_grow(struct radv_pipeline_cache *cache)
269bf215546Sopenharmony_ci{
270bf215546Sopenharmony_ci   const uint32_t table_size = cache->table_size * 2;
271bf215546Sopenharmony_ci   const uint32_t old_table_size = cache->table_size;
272bf215546Sopenharmony_ci   const size_t byte_size = table_size * sizeof(cache->hash_table[0]);
273bf215546Sopenharmony_ci   struct cache_entry **table;
274bf215546Sopenharmony_ci   struct cache_entry **old_table = cache->hash_table;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   table = malloc(byte_size);
277bf215546Sopenharmony_ci   if (table == NULL)
278bf215546Sopenharmony_ci      return vk_error(cache, VK_ERROR_OUT_OF_HOST_MEMORY);
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   cache->hash_table = table;
281bf215546Sopenharmony_ci   cache->table_size = table_size;
282bf215546Sopenharmony_ci   cache->kernel_count = 0;
283bf215546Sopenharmony_ci   cache->total_size = 0;
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   memset(cache->hash_table, 0, byte_size);
286bf215546Sopenharmony_ci   for (uint32_t i = 0; i < old_table_size; i++) {
287bf215546Sopenharmony_ci      struct cache_entry *entry = old_table[i];
288bf215546Sopenharmony_ci      if (!entry)
289bf215546Sopenharmony_ci         continue;
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci      radv_pipeline_cache_set_entry(cache, entry);
292bf215546Sopenharmony_ci   }
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   free(old_table);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   return VK_SUCCESS;
297bf215546Sopenharmony_ci}
298bf215546Sopenharmony_ci
299bf215546Sopenharmony_cistatic void
300bf215546Sopenharmony_ciradv_pipeline_cache_add_entry(struct radv_pipeline_cache *cache, struct cache_entry *entry)
301bf215546Sopenharmony_ci{
302bf215546Sopenharmony_ci   if (cache->kernel_count == cache->table_size / 2)
303bf215546Sopenharmony_ci      radv_pipeline_cache_grow(cache);
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   /* Failing to grow that hash table isn't fatal, but may mean we don't
306bf215546Sopenharmony_ci    * have enough space to add this new kernel. Only add it if there's room.
307bf215546Sopenharmony_ci    */
308bf215546Sopenharmony_ci   if (cache->kernel_count < cache->table_size / 2)
309bf215546Sopenharmony_ci      radv_pipeline_cache_set_entry(cache, entry);
310bf215546Sopenharmony_ci}
311bf215546Sopenharmony_ci
312bf215546Sopenharmony_cibool
313bf215546Sopenharmony_ciradv_create_shaders_from_pipeline_cache(
314bf215546Sopenharmony_ci   struct radv_device *device, struct radv_pipeline_cache *cache, const unsigned char *sha1,
315bf215546Sopenharmony_ci   struct radv_pipeline *pipeline, struct radv_pipeline_shader_stack_size **stack_sizes,
316bf215546Sopenharmony_ci   uint32_t *num_stack_sizes, bool *found_in_application_cache)
317bf215546Sopenharmony_ci{
318bf215546Sopenharmony_ci   struct cache_entry *entry;
319bf215546Sopenharmony_ci   VkResult result;
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   if (!cache) {
322bf215546Sopenharmony_ci      cache = device->mem_cache;
323bf215546Sopenharmony_ci      *found_in_application_cache = false;
324bf215546Sopenharmony_ci   }
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   radv_pipeline_cache_lock(cache);
327bf215546Sopenharmony_ci
328bf215546Sopenharmony_ci   entry = radv_pipeline_cache_search_unlocked(cache, sha1);
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   if (!entry) {
331bf215546Sopenharmony_ci      *found_in_application_cache = false;
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci      /* Don't cache when we want debug info, since this isn't
334bf215546Sopenharmony_ci       * present in the cache.
335bf215546Sopenharmony_ci       */
336bf215546Sopenharmony_ci      if (radv_is_cache_disabled(device) || !device->physical_device->disk_cache) {
337bf215546Sopenharmony_ci         radv_pipeline_cache_unlock(cache);
338bf215546Sopenharmony_ci         return false;
339bf215546Sopenharmony_ci      }
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci      uint8_t disk_sha1[20];
342bf215546Sopenharmony_ci      disk_cache_compute_key(device->physical_device->disk_cache, sha1, 20, disk_sha1);
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci      entry =
345bf215546Sopenharmony_ci         (struct cache_entry *)disk_cache_get(device->physical_device->disk_cache, disk_sha1, NULL);
346bf215546Sopenharmony_ci      if (!entry) {
347bf215546Sopenharmony_ci         radv_pipeline_cache_unlock(cache);
348bf215546Sopenharmony_ci         return false;
349bf215546Sopenharmony_ci      } else {
350bf215546Sopenharmony_ci         size_t size = entry_size(entry);
351bf215546Sopenharmony_ci         struct cache_entry *new_entry =
352bf215546Sopenharmony_ci            vk_alloc(&cache->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE);
353bf215546Sopenharmony_ci         if (!new_entry) {
354bf215546Sopenharmony_ci            free(entry);
355bf215546Sopenharmony_ci            radv_pipeline_cache_unlock(cache);
356bf215546Sopenharmony_ci            return false;
357bf215546Sopenharmony_ci         }
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci         memcpy(new_entry, entry, entry_size(entry));
360bf215546Sopenharmony_ci         free(entry);
361bf215546Sopenharmony_ci         entry = new_entry;
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci         if (!(device->instance->debug_flags & RADV_DEBUG_NO_MEMORY_CACHE) ||
364bf215546Sopenharmony_ci             cache != device->mem_cache)
365bf215546Sopenharmony_ci            radv_pipeline_cache_add_entry(cache, new_entry);
366bf215546Sopenharmony_ci      }
367bf215546Sopenharmony_ci   }
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   struct radv_shader_binary *binaries[MESA_VULKAN_SHADER_STAGES] = {NULL};
370bf215546Sopenharmony_ci   struct radv_shader_binary *gs_copy_binary = NULL;
371bf215546Sopenharmony_ci   bool needs_upload = false;
372bf215546Sopenharmony_ci   char *p = entry->code;
373bf215546Sopenharmony_ci   for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i) {
374bf215546Sopenharmony_ci      if (!entry->shaders[i] && entry->binary_sizes[i]) {
375bf215546Sopenharmony_ci         struct radv_shader_binary *binary = calloc(1, entry->binary_sizes[i]);
376bf215546Sopenharmony_ci         memcpy(binary, p, entry->binary_sizes[i]);
377bf215546Sopenharmony_ci         p += entry->binary_sizes[i];
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci         entry->shaders[i] = radv_shader_create(device, binary, false, true, NULL);
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci         needs_upload = true;
382bf215546Sopenharmony_ci         binaries[i] = binary;
383bf215546Sopenharmony_ci      } else if (entry->binary_sizes[i]) {
384bf215546Sopenharmony_ci         p += entry->binary_sizes[i];
385bf215546Sopenharmony_ci      }
386bf215546Sopenharmony_ci   }
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci   memcpy(pipeline->shaders, entry->shaders, sizeof(entry->shaders));
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   if (pipeline->shaders[MESA_SHADER_GEOMETRY] &&
391bf215546Sopenharmony_ci       !pipeline->shaders[MESA_SHADER_GEOMETRY]->info.is_ngg) {
392bf215546Sopenharmony_ci      /* For the GS copy shader, RADV uses the compute shader slot to avoid a new cache entry. */
393bf215546Sopenharmony_ci      pipeline->gs_copy_shader = pipeline->shaders[MESA_SHADER_COMPUTE];
394bf215546Sopenharmony_ci      pipeline->shaders[MESA_SHADER_COMPUTE] = NULL;
395bf215546Sopenharmony_ci      gs_copy_binary = binaries[MESA_SHADER_COMPUTE];
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   if (needs_upload) {
399bf215546Sopenharmony_ci      result = radv_upload_shaders(device, pipeline, binaries, gs_copy_binary);
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci      for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i) {
402bf215546Sopenharmony_ci         if (pipeline->shaders[i])
403bf215546Sopenharmony_ci            free(binaries[i]);
404bf215546Sopenharmony_ci      }
405bf215546Sopenharmony_ci      free(gs_copy_binary);
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci      if (result != VK_SUCCESS) {
408bf215546Sopenharmony_ci         radv_pipeline_cache_unlock(cache);
409bf215546Sopenharmony_ci         return false;
410bf215546Sopenharmony_ci      }
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci      entry->slab = pipeline->slab;
413bf215546Sopenharmony_ci   } else {
414bf215546Sopenharmony_ci      pipeline->slab = entry->slab;
415bf215546Sopenharmony_ci      pipeline->slab_bo = pipeline->slab->alloc->arena->bo;
416bf215546Sopenharmony_ci   }
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci   if (num_stack_sizes) {
419bf215546Sopenharmony_ci      *num_stack_sizes = entry->num_stack_sizes;
420bf215546Sopenharmony_ci      if (entry->num_stack_sizes) {
421bf215546Sopenharmony_ci         *stack_sizes = malloc(entry->num_stack_sizes * sizeof(**stack_sizes));
422bf215546Sopenharmony_ci         memcpy(*stack_sizes, p, entry->num_stack_sizes * sizeof(**stack_sizes));
423bf215546Sopenharmony_ci      }
424bf215546Sopenharmony_ci   } else {
425bf215546Sopenharmony_ci      assert(!entry->num_stack_sizes);
426bf215546Sopenharmony_ci   }
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   p += entry->num_stack_sizes * sizeof(**stack_sizes);
429bf215546Sopenharmony_ci
430bf215546Sopenharmony_ci   if (device->instance->debug_flags & RADV_DEBUG_NO_MEMORY_CACHE && cache == device->mem_cache)
431bf215546Sopenharmony_ci      vk_free(&cache->alloc, entry);
432bf215546Sopenharmony_ci   else {
433bf215546Sopenharmony_ci      for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i)
434bf215546Sopenharmony_ci         if (entry->shaders[i])
435bf215546Sopenharmony_ci            p_atomic_inc(&entry->shaders[i]->ref_count);
436bf215546Sopenharmony_ci      p_atomic_inc(&entry->slab->ref_count);
437bf215546Sopenharmony_ci   }
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci   assert((uintptr_t)p <= (uintptr_t)entry + entry_size(entry));
440bf215546Sopenharmony_ci   radv_pipeline_cache_unlock(cache);
441bf215546Sopenharmony_ci   return true;
442bf215546Sopenharmony_ci}
443bf215546Sopenharmony_ci
444bf215546Sopenharmony_civoid
445bf215546Sopenharmony_ciradv_pipeline_cache_insert_shaders(struct radv_device *device, struct radv_pipeline_cache *cache,
446bf215546Sopenharmony_ci                                   const unsigned char *sha1, struct radv_pipeline *pipeline,
447bf215546Sopenharmony_ci                                   struct radv_shader_binary *const *binaries,
448bf215546Sopenharmony_ci                                   const struct radv_pipeline_shader_stack_size *stack_sizes,
449bf215546Sopenharmony_ci                                   uint32_t num_stack_sizes)
450bf215546Sopenharmony_ci{
451bf215546Sopenharmony_ci   if (!cache)
452bf215546Sopenharmony_ci      cache = device->mem_cache;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   radv_pipeline_cache_lock(cache);
455bf215546Sopenharmony_ci   struct cache_entry *entry = radv_pipeline_cache_search_unlocked(cache, sha1);
456bf215546Sopenharmony_ci   if (entry) {
457bf215546Sopenharmony_ci      for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i) {
458bf215546Sopenharmony_ci         if (!entry->shaders[i])
459bf215546Sopenharmony_ci            continue;
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci         radv_shader_destroy(cache->device, pipeline->shaders[i]);
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci         pipeline->shaders[i] = entry->shaders[i];
464bf215546Sopenharmony_ci         p_atomic_inc(&pipeline->shaders[i]->ref_count);
465bf215546Sopenharmony_ci      }
466bf215546Sopenharmony_ci
467bf215546Sopenharmony_ci      radv_pipeline_slab_destroy(cache->device, pipeline->slab);
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci      pipeline->slab = entry->slab;
470bf215546Sopenharmony_ci      p_atomic_inc(&pipeline->slab->ref_count);
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
473bf215546Sopenharmony_ci      return;
474bf215546Sopenharmony_ci   }
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci   /* Don't cache when we want debug info, since this isn't
477bf215546Sopenharmony_ci    * present in the cache.
478bf215546Sopenharmony_ci    */
479bf215546Sopenharmony_ci   if (radv_is_cache_disabled(device)) {
480bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
481bf215546Sopenharmony_ci      return;
482bf215546Sopenharmony_ci   }
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci   size_t size = sizeof(*entry) + sizeof(*stack_sizes) * num_stack_sizes;
485bf215546Sopenharmony_ci   for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i)
486bf215546Sopenharmony_ci      if (pipeline->shaders[i])
487bf215546Sopenharmony_ci         size += binaries[i]->total_size;
488bf215546Sopenharmony_ci   const size_t size_without_align = size;
489bf215546Sopenharmony_ci   size = align(size_without_align, alignof(struct cache_entry));
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci   entry = vk_alloc(&cache->alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE);
492bf215546Sopenharmony_ci   if (!entry) {
493bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
494bf215546Sopenharmony_ci      return;
495bf215546Sopenharmony_ci   }
496bf215546Sopenharmony_ci
497bf215546Sopenharmony_ci   memset(entry, 0, sizeof(*entry));
498bf215546Sopenharmony_ci   memcpy(entry->sha1, sha1, 20);
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci   char *p = entry->code;
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci   for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i) {
503bf215546Sopenharmony_ci      if (!pipeline->shaders[i])
504bf215546Sopenharmony_ci         continue;
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci      entry->binary_sizes[i] = binaries[i]->total_size;
507bf215546Sopenharmony_ci
508bf215546Sopenharmony_ci      memcpy(p, binaries[i], binaries[i]->total_size);
509bf215546Sopenharmony_ci      p += binaries[i]->total_size;
510bf215546Sopenharmony_ci   }
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci   if (num_stack_sizes) {
513bf215546Sopenharmony_ci      memcpy(p, stack_sizes, sizeof(*stack_sizes) * num_stack_sizes);
514bf215546Sopenharmony_ci      p += sizeof(*stack_sizes) * num_stack_sizes;
515bf215546Sopenharmony_ci   }
516bf215546Sopenharmony_ci   entry->num_stack_sizes = num_stack_sizes;
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   // Make valgrind happy by filling the alignment hole at the end.
519bf215546Sopenharmony_ci   assert(p == (char *)entry + size_without_align);
520bf215546Sopenharmony_ci   assert(sizeof(*entry) + (p - entry->code) == size_without_align);
521bf215546Sopenharmony_ci   memset((char *)entry + size_without_align, 0, size - size_without_align);
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci   /* Always add cache items to disk. This will allow collection of
524bf215546Sopenharmony_ci    * compiled shaders by third parties such as steam, even if the app
525bf215546Sopenharmony_ci    * implements its own pipeline cache.
526bf215546Sopenharmony_ci    *
527bf215546Sopenharmony_ci    * Make sure to exclude meta shaders because they are stored in a different cache file.
528bf215546Sopenharmony_ci    */
529bf215546Sopenharmony_ci   if (device->physical_device->disk_cache && cache != &device->meta_state.cache) {
530bf215546Sopenharmony_ci      uint8_t disk_sha1[20];
531bf215546Sopenharmony_ci      disk_cache_compute_key(device->physical_device->disk_cache, sha1, 20, disk_sha1);
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci      disk_cache_put(device->physical_device->disk_cache, disk_sha1, entry, entry_size(entry),
534bf215546Sopenharmony_ci                     NULL);
535bf215546Sopenharmony_ci   }
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   if (device->instance->debug_flags & RADV_DEBUG_NO_MEMORY_CACHE && cache == device->mem_cache) {
538bf215546Sopenharmony_ci      vk_free2(&cache->alloc, NULL, entry);
539bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
540bf215546Sopenharmony_ci      return;
541bf215546Sopenharmony_ci   }
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci   /* We delay setting the shader so we have reproducible disk cache
544bf215546Sopenharmony_ci    * items.
545bf215546Sopenharmony_ci    */
546bf215546Sopenharmony_ci   for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i) {
547bf215546Sopenharmony_ci      if (!pipeline->shaders[i])
548bf215546Sopenharmony_ci         continue;
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci      entry->shaders[i] = pipeline->shaders[i];
551bf215546Sopenharmony_ci      p_atomic_inc(&pipeline->shaders[i]->ref_count);
552bf215546Sopenharmony_ci   }
553bf215546Sopenharmony_ci
554bf215546Sopenharmony_ci   entry->slab = pipeline->slab;
555bf215546Sopenharmony_ci   p_atomic_inc(&pipeline->slab->ref_count);
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci   radv_pipeline_cache_add_entry(cache, entry);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   cache->modified = true;
560bf215546Sopenharmony_ci   radv_pipeline_cache_unlock(cache);
561bf215546Sopenharmony_ci   return;
562bf215546Sopenharmony_ci}
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_cibool
565bf215546Sopenharmony_ciradv_pipeline_cache_load(struct radv_pipeline_cache *cache, const void *data, size_t size)
566bf215546Sopenharmony_ci{
567bf215546Sopenharmony_ci   struct radv_device *device = cache->device;
568bf215546Sopenharmony_ci   struct vk_pipeline_cache_header header;
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_ci   if (size < sizeof(header))
571bf215546Sopenharmony_ci      return false;
572bf215546Sopenharmony_ci   memcpy(&header, data, sizeof(header));
573bf215546Sopenharmony_ci   if (header.header_size < sizeof(header))
574bf215546Sopenharmony_ci      return false;
575bf215546Sopenharmony_ci   if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
576bf215546Sopenharmony_ci      return false;
577bf215546Sopenharmony_ci   if (header.vendor_id != ATI_VENDOR_ID)
578bf215546Sopenharmony_ci      return false;
579bf215546Sopenharmony_ci   if (header.device_id != device->physical_device->rad_info.pci_id)
580bf215546Sopenharmony_ci      return false;
581bf215546Sopenharmony_ci   if (memcmp(header.uuid, device->physical_device->cache_uuid, VK_UUID_SIZE) != 0)
582bf215546Sopenharmony_ci      return false;
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_ci   char *end = (char *)data + size;
585bf215546Sopenharmony_ci   char *p = (char *)data + header.header_size;
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   while (end - p >= sizeof(struct cache_entry)) {
588bf215546Sopenharmony_ci      struct cache_entry *entry = (struct cache_entry *)p;
589bf215546Sopenharmony_ci      struct cache_entry *dest_entry;
590bf215546Sopenharmony_ci      size_t size_of_entry = entry_size(entry);
591bf215546Sopenharmony_ci      if (end - p < size_of_entry)
592bf215546Sopenharmony_ci         break;
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci      dest_entry = vk_alloc(&cache->alloc, size_of_entry, 8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE);
595bf215546Sopenharmony_ci      if (dest_entry) {
596bf215546Sopenharmony_ci         memcpy(dest_entry, entry, size_of_entry);
597bf215546Sopenharmony_ci         for (int i = 0; i < MESA_VULKAN_SHADER_STAGES; ++i)
598bf215546Sopenharmony_ci            dest_entry->shaders[i] = NULL;
599bf215546Sopenharmony_ci         dest_entry->slab = NULL;
600bf215546Sopenharmony_ci         radv_pipeline_cache_add_entry(cache, dest_entry);
601bf215546Sopenharmony_ci      }
602bf215546Sopenharmony_ci      p += size_of_entry;
603bf215546Sopenharmony_ci   }
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci   return true;
606bf215546Sopenharmony_ci}
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL
609bf215546Sopenharmony_ciradv_CreatePipelineCache(VkDevice _device, const VkPipelineCacheCreateInfo *pCreateInfo,
610bf215546Sopenharmony_ci                         const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache)
611bf215546Sopenharmony_ci{
612bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_device, device, _device);
613bf215546Sopenharmony_ci   struct radv_pipeline_cache *cache;
614bf215546Sopenharmony_ci
615bf215546Sopenharmony_ci   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO);
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci   cache = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*cache), 8,
618bf215546Sopenharmony_ci                     VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
619bf215546Sopenharmony_ci   if (cache == NULL)
620bf215546Sopenharmony_ci      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
621bf215546Sopenharmony_ci
622bf215546Sopenharmony_ci   if (pAllocator)
623bf215546Sopenharmony_ci      cache->alloc = *pAllocator;
624bf215546Sopenharmony_ci   else
625bf215546Sopenharmony_ci      cache->alloc = device->vk.alloc;
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci   radv_pipeline_cache_init(cache, device);
628bf215546Sopenharmony_ci   cache->flags = pCreateInfo->flags;
629bf215546Sopenharmony_ci
630bf215546Sopenharmony_ci   if (pCreateInfo->initialDataSize > 0) {
631bf215546Sopenharmony_ci      radv_pipeline_cache_load(cache, pCreateInfo->pInitialData, pCreateInfo->initialDataSize);
632bf215546Sopenharmony_ci   }
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   *pPipelineCache = radv_pipeline_cache_to_handle(cache);
635bf215546Sopenharmony_ci
636bf215546Sopenharmony_ci   return VK_SUCCESS;
637bf215546Sopenharmony_ci}
638bf215546Sopenharmony_ci
639bf215546Sopenharmony_ciVKAPI_ATTR void VKAPI_CALL
640bf215546Sopenharmony_ciradv_DestroyPipelineCache(VkDevice _device, VkPipelineCache _cache,
641bf215546Sopenharmony_ci                          const VkAllocationCallbacks *pAllocator)
642bf215546Sopenharmony_ci{
643bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_device, device, _device);
644bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_pipeline_cache, cache, _cache);
645bf215546Sopenharmony_ci
646bf215546Sopenharmony_ci   if (!cache)
647bf215546Sopenharmony_ci      return;
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_ci   radv_pipeline_cache_finish(cache);
650bf215546Sopenharmony_ci   vk_free2(&device->vk.alloc, pAllocator, cache);
651bf215546Sopenharmony_ci}
652bf215546Sopenharmony_ci
653bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL
654bf215546Sopenharmony_ciradv_GetPipelineCacheData(VkDevice _device, VkPipelineCache _cache, size_t *pDataSize, void *pData)
655bf215546Sopenharmony_ci{
656bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_device, device, _device);
657bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_pipeline_cache, cache, _cache);
658bf215546Sopenharmony_ci   struct vk_pipeline_cache_header *header;
659bf215546Sopenharmony_ci   VkResult result = VK_SUCCESS;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   radv_pipeline_cache_lock(cache);
662bf215546Sopenharmony_ci
663bf215546Sopenharmony_ci   const size_t size = sizeof(*header) + cache->total_size;
664bf215546Sopenharmony_ci   if (pData == NULL) {
665bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
666bf215546Sopenharmony_ci      *pDataSize = size;
667bf215546Sopenharmony_ci      return VK_SUCCESS;
668bf215546Sopenharmony_ci   }
669bf215546Sopenharmony_ci   if (*pDataSize < sizeof(*header)) {
670bf215546Sopenharmony_ci      radv_pipeline_cache_unlock(cache);
671bf215546Sopenharmony_ci      *pDataSize = 0;
672bf215546Sopenharmony_ci      return VK_INCOMPLETE;
673bf215546Sopenharmony_ci   }
674bf215546Sopenharmony_ci   void *p = pData, *end = (char *)pData + *pDataSize;
675bf215546Sopenharmony_ci   header = p;
676bf215546Sopenharmony_ci   header->header_size = align(sizeof(*header), alignof(struct cache_entry));
677bf215546Sopenharmony_ci   header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
678bf215546Sopenharmony_ci   header->vendor_id = ATI_VENDOR_ID;
679bf215546Sopenharmony_ci   header->device_id = device->physical_device->rad_info.pci_id;
680bf215546Sopenharmony_ci   memcpy(header->uuid, device->physical_device->cache_uuid, VK_UUID_SIZE);
681bf215546Sopenharmony_ci   p = (char *)p + header->header_size;
682bf215546Sopenharmony_ci
683bf215546Sopenharmony_ci   struct cache_entry *entry;
684bf215546Sopenharmony_ci   for (uint32_t i = 0; i < cache->table_size; i++) {
685bf215546Sopenharmony_ci      if (!cache->hash_table[i])
686bf215546Sopenharmony_ci         continue;
687bf215546Sopenharmony_ci      entry = cache->hash_table[i];
688bf215546Sopenharmony_ci      const uint32_t size_of_entry = entry_size(entry);
689bf215546Sopenharmony_ci      if ((char *)end < (char *)p + size_of_entry) {
690bf215546Sopenharmony_ci         result = VK_INCOMPLETE;
691bf215546Sopenharmony_ci         break;
692bf215546Sopenharmony_ci      }
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci      memcpy(p, entry, size_of_entry);
695bf215546Sopenharmony_ci      for (int j = 0; j < MESA_VULKAN_SHADER_STAGES; ++j)
696bf215546Sopenharmony_ci         ((struct cache_entry *)p)->shaders[j] = NULL;
697bf215546Sopenharmony_ci      ((struct cache_entry *)p)->slab = NULL;
698bf215546Sopenharmony_ci      p = (char *)p + size_of_entry;
699bf215546Sopenharmony_ci   }
700bf215546Sopenharmony_ci   *pDataSize = (char *)p - (char *)pData;
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci   radv_pipeline_cache_unlock(cache);
703bf215546Sopenharmony_ci   return result;
704bf215546Sopenharmony_ci}
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_cistatic void
707bf215546Sopenharmony_ciradv_pipeline_cache_merge(struct radv_pipeline_cache *dst, struct radv_pipeline_cache *src)
708bf215546Sopenharmony_ci{
709bf215546Sopenharmony_ci   for (uint32_t i = 0; i < src->table_size; i++) {
710bf215546Sopenharmony_ci      struct cache_entry *entry = src->hash_table[i];
711bf215546Sopenharmony_ci      if (!entry || radv_pipeline_cache_search(dst, entry->sha1))
712bf215546Sopenharmony_ci         continue;
713bf215546Sopenharmony_ci
714bf215546Sopenharmony_ci      radv_pipeline_cache_add_entry(dst, entry);
715bf215546Sopenharmony_ci
716bf215546Sopenharmony_ci      src->hash_table[i] = NULL;
717bf215546Sopenharmony_ci   }
718bf215546Sopenharmony_ci}
719bf215546Sopenharmony_ci
720bf215546Sopenharmony_ciVKAPI_ATTR VkResult VKAPI_CALL
721bf215546Sopenharmony_ciradv_MergePipelineCaches(VkDevice _device, VkPipelineCache destCache, uint32_t srcCacheCount,
722bf215546Sopenharmony_ci                         const VkPipelineCache *pSrcCaches)
723bf215546Sopenharmony_ci{
724bf215546Sopenharmony_ci   RADV_FROM_HANDLE(radv_pipeline_cache, dst, destCache);
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_ci   for (uint32_t i = 0; i < srcCacheCount; i++) {
727bf215546Sopenharmony_ci      RADV_FROM_HANDLE(radv_pipeline_cache, src, pSrcCaches[i]);
728bf215546Sopenharmony_ci
729bf215546Sopenharmony_ci      radv_pipeline_cache_merge(dst, src);
730bf215546Sopenharmony_ci   }
731bf215546Sopenharmony_ci
732bf215546Sopenharmony_ci   return VK_SUCCESS;
733bf215546Sopenharmony_ci}
734