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