From be06bfcbed5c366455c49a77b89608b84345f75c Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Mon, 8 Jul 2024 16:42:25 +0200 Subject: [PATCH] radv: add initial support for pipeline binaries Signed-off-by: Samuel Pitoiset Part-of: --- src/amd/vulkan/meson.build | 2 + src/amd/vulkan/radv_pipeline_binary.c | 446 ++++++++++++++++++++++++ src/amd/vulkan/radv_pipeline_binary.h | 42 +++ src/amd/vulkan/radv_pipeline_cache.c | 103 ++++++ src/amd/vulkan/radv_pipeline_cache.h | 5 + src/amd/vulkan/radv_pipeline_graphics.c | 5 + src/amd/vulkan/radv_pipeline_rt.h | 9 + 7 files changed, 612 insertions(+) create mode 100644 src/amd/vulkan/radv_pipeline_binary.c create mode 100644 src/amd/vulkan/radv_pipeline_binary.h diff --git a/src/amd/vulkan/meson.build b/src/amd/vulkan/meson.build index 9dc0a84959f..087b31b5af6 100644 --- a/src/amd/vulkan/meson.build +++ b/src/amd/vulkan/meson.build @@ -127,6 +127,8 @@ libradv_files = files( 'radv_physical_device.c', 'radv_pipeline.c', 'radv_pipeline.h', + 'radv_pipeline_binary.c', + 'radv_pipeline_binary.h', 'radv_pipeline_cache.c', 'radv_pipeline_cache.h', 'radv_pipeline_compute.c', diff --git a/src/amd/vulkan/radv_pipeline_binary.c b/src/amd/vulkan/radv_pipeline_binary.c new file mode 100644 index 00000000000..c7d69ac07ed --- /dev/null +++ b/src/amd/vulkan/radv_pipeline_binary.c @@ -0,0 +1,446 @@ +/* + * Copyright © 2024 Valve Corporation + * + * SPDX-License-Identifier: MIT + */ + +#include "radv_pipeline_binary.h" +#include "util/disk_cache.h" +#include "util/macros.h" +#include "util/mesa-blake3.h" +#include "util/mesa-sha1.h" +#include "util/u_atomic.h" +#include "util/u_debug.h" +#include "nir_serialize.h" +#include "radv_debug.h" +#include "radv_device.h" +#include "radv_entrypoints.h" +#include "radv_pipeline_cache.h" +#include "radv_pipeline_graphics.h" +#include "radv_pipeline_rt.h" +#include "radv_shader.h" +#include "vk_log.h" +#include "vk_pipeline.h" +#include "vk_util.h" + +static VkResult +radv_get_pipeline_key(struct radv_device *device, const VkPipelineCreateInfoKHR *pPipelineCreateInfo, + unsigned char *key) +{ + VkResult result = VK_SUCCESS; + + switch (((VkBaseInStructure *)pPipelineCreateInfo->pNext)->sType) { + case VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO: { + const VkGraphicsPipelineCreateInfo *graphics_create_info = + (VkGraphicsPipelineCreateInfo *)pPipelineCreateInfo->pNext; + struct radv_graphics_pipeline_state gfx_state; + + result = radv_generate_graphics_pipeline_state(device, graphics_create_info, &gfx_state); + if (result != VK_SUCCESS) + return result; + + radv_graphics_pipeline_hash(device, &gfx_state, key); + radv_graphics_pipeline_state_finish(device, &gfx_state); + break; + } + case VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO: { + const VkComputePipelineCreateInfo *compute_create_info = + (VkComputePipelineCreateInfo *)pPipelineCreateInfo->pNext; + + radv_compute_pipeline_hash(device, compute_create_info, key); + break; + } + case VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR: { + const VkRayTracingPipelineCreateInfoKHR *rt_create_info = + (VkRayTracingPipelineCreateInfoKHR *)pPipelineCreateInfo->pNext; + struct radv_ray_tracing_state_key rt_state; + + result = radv_generate_ray_tracing_state_key(device, rt_create_info, &rt_state); + if (result != VK_SUCCESS) + return result; + + radv_ray_tracing_pipeline_hash(device, rt_create_info, &rt_state, key); + radv_ray_tracing_state_key_finish(&rt_state); + break; + } + default: + unreachable("unsupported pipeline create info struct"); + } + + return result; +} + +VKAPI_ATTR VkResult VKAPI_CALL +radv_GetPipelineKeyKHR(VkDevice _device, const VkPipelineCreateInfoKHR *pPipelineCreateInfo, + VkPipelineBinaryKeyKHR *pPipelineKey) +{ + VK_FROM_HANDLE(radv_device, device, _device); + VkResult result; + + memset(pPipelineKey->key, 0, sizeof(pPipelineKey->key)); + + /* Return the global key that applies to all pipelines. */ + if (!pPipelineCreateInfo) { + static_assert(sizeof(device->cache_hash) <= sizeof(pPipelineKey->key), "mismatch pipeline binary key size"); + + memcpy(pPipelineKey->key, device->cache_hash, sizeof(device->cache_hash)); + pPipelineKey->keySize = sizeof(device->cache_hash); + + return VK_SUCCESS; + } + + result = radv_get_pipeline_key(device, pPipelineCreateInfo, pPipelineKey->key); + if (result != VK_SUCCESS) + return result; + + pPipelineKey->keySize = SHA1_DIGEST_LENGTH; + + return VK_SUCCESS; +} + +static VkResult +radv_create_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator, const blake3_hash key, + const void *data, size_t data_size, struct radv_pipeline_binary **pipeline_binary_out) +{ + struct radv_pipeline_binary *pipeline_binary; + + pipeline_binary = + vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*pipeline_binary), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pipeline_binary == NULL) + return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &pipeline_binary->base, VK_OBJECT_TYPE_PIPELINE_BINARY_KHR); + + pipeline_binary->data = (void *)data; + pipeline_binary->size = data_size; + + memcpy(pipeline_binary->key, key, sizeof(*key)); + + *pipeline_binary_out = pipeline_binary; + return VK_SUCCESS; +} + +static VkResult +radv_create_pipeline_binary_from_data(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + const VkPipelineBinaryDataKHR *pData, const VkPipelineBinaryKeyKHR *pKey, + struct util_dynarray *pipeline_binaries, uint32_t *num_binaries) +{ + struct radv_pipeline_binary *pipeline_binary; + VkResult result; + void *data; + + if (!pipeline_binaries) { + (*num_binaries)++; + return VK_SUCCESS; + } + + data = malloc(pData->dataSize); + if (!data) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + memcpy(data, pData->pData, pData->dataSize); + + result = radv_create_pipeline_binary(device, pAllocator, pKey->key, data, pData->dataSize, &pipeline_binary); + if (result != VK_SUCCESS) { + free(data); + return result; + } + + util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary); + return result; +} + +VkResult +radv_create_pipeline_binary_from_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_shader *shader, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries) +{ + struct radv_pipeline_binary *pipeline_binary; + struct blob blob; + size_t data_size; + VkResult result; + void *data; + + if (!pipeline_binaries) { + (*num_binaries)++; + return VK_SUCCESS; + } + + blob_init(&blob); + radv_shader_serialize(shader, &blob); + blob_finish_get_buffer(&blob, &data, &data_size); + + result = radv_create_pipeline_binary(device, pAllocator, shader->hash, data, data_size, &pipeline_binary); + if (result != VK_SUCCESS) { + free(data); + return result; + } + + util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary); + return result; +} + +VkResult +radv_create_pipeline_binary_from_rt_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_shader *shader, bool is_traversal_shader, + const uint8_t stage_sha1[SHA1_DIGEST_LENGTH], + const struct radv_ray_tracing_stage_info *rt_stage_info, uint32_t stack_size, + struct vk_pipeline_cache_object *nir, + struct util_dynarray *pipeline_binaries, uint32_t *num_binaries) +{ + struct radv_pipeline_binary *pipeline_binary; + struct mesa_blake3 ctx; + struct blob blob; + size_t data_size; + blake3_hash key; + VkResult result; + void *data; + + if (!pipeline_binaries) { + (*num_binaries)++; + return VK_SUCCESS; + } + + _mesa_blake3_init(&ctx); + _mesa_blake3_update(&ctx, stage_sha1, sizeof(*stage_sha1)); + _mesa_blake3_final(&ctx, key); + + struct radv_ray_tracing_binary_header header = { + .is_traversal_shader = is_traversal_shader, + .has_shader = !!shader, + .has_nir = !!nir, + .stack_size = stack_size, + }; + + memcpy(header.stage_sha1, stage_sha1, sizeof(header.stage_sha1)); + memcpy(&header.stage_info, rt_stage_info, sizeof(header.stage_info)); + + blob_init(&blob); + blob_write_bytes(&blob, &header, sizeof(header)); + if (header.has_shader) + radv_shader_serialize(shader, &blob); + if (header.has_nir) { + struct vk_raw_data_cache_object *nir_object = container_of(nir, struct vk_raw_data_cache_object, base); + blob_write_bytes(&blob, nir_object->data, nir_object->data_size); + } + blob_finish_get_buffer(&blob, &data, &data_size); + + result = radv_create_pipeline_binary(device, pAllocator, key, data, data_size, &pipeline_binary); + if (result != VK_SUCCESS) { + free(data); + return result; + } + + util_dynarray_append(pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary); + return result; +} + +static VkResult +radv_create_pipeline_binary_from_pipeline(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_pipeline *pipeline, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries) +{ + VkResult result = VK_SUCCESS; + + if (pipeline->type == RADV_PIPELINE_RAY_TRACING) { + struct radv_ray_tracing_pipeline *rt_pipeline = radv_pipeline_to_ray_tracing(pipeline); + + for (uint32_t i = 0; i < rt_pipeline->non_imported_stage_count; i++) { + struct radv_ray_tracing_stage *rt_stage = &rt_pipeline->stages[i]; + + result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, rt_stage->shader, false, + rt_stage->sha1, &rt_stage->info, rt_stage->stack_size, + rt_stage->nir, pipeline_binaries, num_binaries); + if (result != VK_SUCCESS) + return result; + } + + struct radv_shader *traversal_shader = rt_pipeline->base.base.shaders[MESA_SHADER_INTERSECTION]; + if (traversal_shader) { + result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, traversal_shader, true, + traversal_shader->hash, NULL, 0, NULL, pipeline_binaries, + num_binaries); + if (result != VK_SUCCESS) + return result; + } + } else { + for (uint32_t i = 0; i < MESA_VULKAN_SHADER_STAGES; i++) { + if (!pipeline->shaders[i]) + continue; + + result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->shaders[i], pipeline_binaries, + num_binaries); + if (result != VK_SUCCESS) + return result; + } + + if (pipeline->gs_copy_shader) { + result = radv_create_pipeline_binary_from_shader(device, pAllocator, pipeline->gs_copy_shader, + pipeline_binaries, num_binaries); + if (result != VK_SUCCESS) + return result; + } + } + + return result; +} + +static VkResult +radv_create_pipeline_binary_from_cache(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + const VkPipelineCreateInfoKHR *pPipelineCreateInfo, + struct util_dynarray *pipeline_binaries, uint32_t *num_binaries) +{ + unsigned char key[SHA1_DIGEST_LENGTH]; + bool found_in_internal_cache; + VkResult result; + + assert(pPipelineCreateInfo); + + result = radv_get_pipeline_key(device, pPipelineCreateInfo, key); + if (result != VK_SUCCESS) + return result; + + result = radv_pipeline_cache_get_binaries(device, pAllocator, key, pipeline_binaries, num_binaries, + &found_in_internal_cache); + if (result != VK_SUCCESS) + return result; + + return found_in_internal_cache ? VK_SUCCESS : VK_PIPELINE_BINARY_MISSING_KHR; +} + +static VkResult +radv_create_pipeline_binaries(struct radv_device *device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries) +{ + VkResult result = VK_SUCCESS; + + if (pCreateInfo->pKeysAndDataInfo) { + const VkPipelineBinaryKeysAndDataKHR *pKeysAndDataInfo = pCreateInfo->pKeysAndDataInfo; + + for (uint32_t i = 0; i < pKeysAndDataInfo->binaryCount; i++) { + const VkPipelineBinaryDataKHR *pData = &pKeysAndDataInfo->pPipelineBinaryData[i]; + const VkPipelineBinaryKeyKHR *pKey = &pKeysAndDataInfo->pPipelineBinaryKeys[i]; + + result = + radv_create_pipeline_binary_from_data(device, pAllocator, pData, pKey, pipeline_binaries, num_binaries); + if (result != VK_SUCCESS) + return result; + } + } else if (pCreateInfo->pipeline) { + VK_FROM_HANDLE(radv_pipeline, pipeline, pCreateInfo->pipeline); + + result = radv_create_pipeline_binary_from_pipeline(device, pAllocator, pipeline, pipeline_binaries, num_binaries); + } else { + result = radv_create_pipeline_binary_from_cache(device, pAllocator, pCreateInfo->pPipelineCreateInfo, + pipeline_binaries, num_binaries); + } + + return result; +} + +static void +radv_destroy_pipeline_binary(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_pipeline_binary *pipeline_binary) +{ + if (!pipeline_binary) + return; + + free(pipeline_binary->data); + + vk_object_base_finish(&pipeline_binary->base); + vk_free2(&device->vk.alloc, pAllocator, pipeline_binary); +} + +VKAPI_ATTR VkResult VKAPI_CALL +radv_CreatePipelineBinariesKHR(VkDevice _device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, VkPipelineBinaryHandlesInfoKHR *pBinaries) +{ + VK_FROM_HANDLE(radv_device, device, _device); + struct util_dynarray pipeline_binaries; + VkResult result; + + if (!pBinaries->pPipelineBinaries) { + result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, NULL, &pBinaries->pipelineBinaryCount); + return result; + } + + for (uint32_t i = 0; i < pBinaries->pipelineBinaryCount; i++) + pBinaries->pPipelineBinaries[i] = VK_NULL_HANDLE; + + util_dynarray_init(&pipeline_binaries, NULL); + + /* Get all pipeline binaries from the pCreateInfo first to simplify the creation. */ + result = radv_create_pipeline_binaries(device, pCreateInfo, pAllocator, &pipeline_binaries, NULL); + if (result != VK_SUCCESS) { + util_dynarray_foreach (&pipeline_binaries, struct radv_pipeline_binary *, pipeline_binary) + radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary); + util_dynarray_fini(&pipeline_binaries); + return result; + } + + const uint32_t num_binaries = util_dynarray_num_elements(&pipeline_binaries, struct radv_pipeline_binary *); + + for (uint32_t i = 0; i < num_binaries; i++) { + struct radv_pipeline_binary **pipeline_binary = + util_dynarray_element(&pipeline_binaries, struct radv_pipeline_binary *, i); + + if (i < pBinaries->pipelineBinaryCount) { + pBinaries->pPipelineBinaries[i] = radv_pipeline_binary_to_handle(*pipeline_binary); + } else { + /* Free the pipeline binary that couldn't be returned. */ + radv_destroy_pipeline_binary(device, pAllocator, *pipeline_binary); + } + } + + result = pBinaries->pipelineBinaryCount < num_binaries ? VK_INCOMPLETE : result; + pBinaries->pipelineBinaryCount = MIN2(num_binaries, pBinaries->pipelineBinaryCount); + + util_dynarray_fini(&pipeline_binaries); + return result; +} + +VKAPI_ATTR void VKAPI_CALL +radv_DestroyPipelineBinaryKHR(VkDevice _device, VkPipelineBinaryKHR pipelineBinary, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pipelineBinary); + VK_FROM_HANDLE(radv_device, device, _device); + + radv_destroy_pipeline_binary(device, pAllocator, pipeline_binary); +} + +VKAPI_ATTR VkResult VKAPI_CALL +radv_GetPipelineBinaryDataKHR(VkDevice _device, const VkPipelineBinaryDataInfoKHR *pInfo, + VkPipelineBinaryKeyKHR *pPipelineBinaryKey, size_t *pPipelineBinaryDataSize, + void *pPipelineBinaryData) +{ + VK_FROM_HANDLE(radv_pipeline_binary, pipeline_binary, pInfo->pipelineBinary); + const size_t size = pipeline_binary->size; + + if (!pPipelineBinaryData) { + *pPipelineBinaryDataSize = size; + return VK_SUCCESS; + } + + if (*pPipelineBinaryDataSize < size) { + *pPipelineBinaryDataSize = size; + return VK_ERROR_NOT_ENOUGH_SPACE_KHR; + } + + memcpy(pPipelineBinaryData, pipeline_binary->data, size); + *pPipelineBinaryDataSize = size; + + memcpy(pPipelineBinaryKey->key, pipeline_binary->key, sizeof(pipeline_binary->key)); + pPipelineBinaryKey->keySize = sizeof(pipeline_binary->key); + + return VK_SUCCESS; +} + +VKAPI_ATTR VkResult VKAPI_CALL +radv_ReleaseCapturedPipelineDataKHR(VkDevice _device, const VkReleaseCapturedPipelineDataInfoKHR *pInfo, + const VkAllocationCallbacks *pAllocator) +{ + /* no-op */ + return VK_SUCCESS; +} diff --git a/src/amd/vulkan/radv_pipeline_binary.h b/src/amd/vulkan/radv_pipeline_binary.h new file mode 100644 index 00000000000..c7778c2ec94 --- /dev/null +++ b/src/amd/vulkan/radv_pipeline_binary.h @@ -0,0 +1,42 @@ +/* + * Copyright © 2024 Valve Corporation + * + * SPDX-License-Identifier: MIT + */ + +#ifndef RADV_PIPELINE_BINARY_H +#define RADV_PIPELINE_BINARY_H + +#include "vk_object.h" + +#include "util/mesa-blake3.h" +#include "util/mesa-sha1.h" + +struct radv_device; +struct radv_ray_tracing_stage_info; +struct radv_shader; +struct util_dynarray; +struct vk_pipeline_cache_object; + +struct radv_pipeline_binary { + struct vk_object_base base; + + blake3_hash key; + void *data; + size_t size; +}; + +VK_DEFINE_NONDISP_HANDLE_CASTS(radv_pipeline_binary, base, VkPipelineBinaryKHR, VK_OBJECT_TYPE_PIPELINE_BINARY_KHR) + +VkResult radv_create_pipeline_binary_from_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_shader *shader, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries); + +VkResult radv_create_pipeline_binary_from_rt_shader(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + struct radv_shader *shader, bool is_traversal_shader, + const uint8_t stage_sha1[SHA1_DIGEST_LENGTH], + const struct radv_ray_tracing_stage_info *rt_stage_info, + uint32_t stack_size, struct vk_pipeline_cache_object *nir, + struct util_dynarray *pipeline_binaries, uint32_t *num_binaries); + +#endif /* RADV_PIPELINE_BINARY_H */ diff --git a/src/amd/vulkan/radv_pipeline_cache.c b/src/amd/vulkan/radv_pipeline_cache.c index b971779ff13..e5947235370 100644 --- a/src/amd/vulkan/radv_pipeline_cache.c +++ b/src/amd/vulkan/radv_pipeline_cache.c @@ -17,6 +17,7 @@ #include "radv_pipeline.h" #include "radv_pipeline_compute.h" #include "radv_pipeline_graphics.h" +#include "radv_pipeline_binary.h" #include "radv_pipeline_rt.h" #include "radv_shader.h" #include "vk_pipeline.h" @@ -627,3 +628,105 @@ radv_pipeline_cache_nir_to_handle(struct radv_device *device, struct vk_pipeline free(data); return object; } + +VkResult +radv_pipeline_cache_get_binaries(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + const unsigned char *sha1, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries, bool *found_in_internal_cache) +{ + struct vk_pipeline_cache *cache = device->mem_cache; + VkResult result; + + *found_in_internal_cache = false; + + if (radv_is_cache_disabled(device, cache)) + return VK_SUCCESS; + + struct vk_pipeline_cache_object *object = + vk_pipeline_cache_lookup_object(cache, sha1, SHA1_DIGEST_LENGTH, &radv_pipeline_ops, NULL); + if (!object) + return VK_SUCCESS; + + struct radv_pipeline_cache_object *pipeline_obj = container_of(object, struct radv_pipeline_cache_object, base); + + bool complete = true; + bool is_rt = false; + for (unsigned i = 0; i < pipeline_obj->num_shaders; i++) { + if (gl_shader_stage_is_rt(pipeline_obj->shaders[i]->info.stage)) { + is_rt = true; + break; + } + } + + if (is_rt) { + struct radv_ray_tracing_pipeline_cache_data *data = pipeline_obj->data; + struct radv_shader *traversal_shader = NULL; + unsigned idx = 0; + + if (data->has_traversal_shader) + traversal_shader = pipeline_obj->shaders[idx++]; + + for (unsigned i = 0; i < data->num_stages; i++) { + const struct radv_ray_tracing_stage_cache_data *stage_data = &data->stages[i]; + struct vk_pipeline_cache_object *nir = NULL; + struct radv_shader *shader = NULL; + + if (stage_data->has_shader) + shader = pipeline_obj->shaders[idx++]; + + if (data->is_library) + nir = radv_pipeline_cache_lookup_nir_handle(device, cache, data->stages[i].sha1); + + result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, shader, false, data->stages[i].sha1, + &stage_data->info, stage_data->stack_size, nir, + pipeline_binaries, num_binaries); + + if (data->is_library) + complete &= nir != NULL; + + if (nir) + vk_pipeline_cache_object_unref(&device->vk, nir); + + if (result != VK_SUCCESS) + goto fail; + } + + if (traversal_shader) { + result = radv_create_pipeline_binary_from_rt_shader(device, pAllocator, traversal_shader, true, + traversal_shader->hash, NULL, 0, NULL, pipeline_binaries, + num_binaries); + if (result != VK_SUCCESS) + goto fail; + } + } else { + struct radv_shader *gs_copy_shader = NULL; + + for (unsigned i = 0; i < pipeline_obj->num_shaders; i++) { + struct radv_shader *shader = pipeline_obj->shaders[i]; + gl_shader_stage s = shader->info.stage; + + if (s == MESA_SHADER_VERTEX && i > 0) { + /* The GS copy-shader is a VS placed after all other stages */ + gs_copy_shader = shader; + } else { + result = + radv_create_pipeline_binary_from_shader(device, pAllocator, shader, pipeline_binaries, num_binaries); + if (result != VK_SUCCESS) + goto fail; + } + } + + if (gs_copy_shader) { + result = radv_create_pipeline_binary_from_shader(device, pAllocator, gs_copy_shader, pipeline_binaries, + num_binaries); + if (result != VK_SUCCESS) + goto fail; + } + } + + *found_in_internal_cache = complete; + +fail: + vk_pipeline_cache_object_unref(&device->vk, &pipeline_obj->base); + return result; +} diff --git a/src/amd/vulkan/radv_pipeline_cache.h b/src/amd/vulkan/radv_pipeline_cache.h index bb65d828dce..de8665f9a4b 100644 --- a/src/amd/vulkan/radv_pipeline_cache.h +++ b/src/amd/vulkan/radv_pipeline_cache.h @@ -29,6 +29,7 @@ struct radv_ray_tracing_stage; struct radv_shader_binary; struct radv_shader_stage; struct radv_spirv_to_nir_options; +struct util_dynarray; void radv_hash_graphics_spirv_to_nir(blake3_hash hash, const struct radv_shader_stage *stage, const struct radv_spirv_to_nir_options *options); @@ -75,4 +76,8 @@ void radv_shader_serialize(struct radv_shader *shader, struct blob *blob); struct radv_shader *radv_shader_deserialize(struct radv_device *device, const void *key_data, size_t key_size, struct blob_reader *blob); +VkResult radv_pipeline_cache_get_binaries(struct radv_device *device, const VkAllocationCallbacks *pAllocator, + const unsigned char *sha1, struct util_dynarray *pipeline_binaries, + uint32_t *num_binaries, bool *found_in_internal_cache); + #endif /* RADV_PIPELINE_CACHE_H */ diff --git a/src/amd/vulkan/radv_pipeline_graphics.c b/src/amd/vulkan/radv_pipeline_graphics.c index caa17d546ae..24fce9b93cb 100644 --- a/src/amd/vulkan/radv_pipeline_graphics.c +++ b/src/amd/vulkan/radv_pipeline_graphics.c @@ -2505,11 +2505,16 @@ radv_is_fast_linking_enabled(const VkGraphicsPipelineCreateInfo *pCreateInfo) static bool radv_skip_graphics_pipeline_compile(const struct radv_device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo) { + const VkPipelineBinaryInfoKHR *binary_info = vk_find_struct_const(pCreateInfo->pNext, PIPELINE_BINARY_INFO_KHR); const VkPipelineCreateFlags2KHR create_flags = vk_graphics_pipeline_create_flags(pCreateInfo); const struct radv_physical_device *pdev = radv_device_physical(device); VkShaderStageFlagBits binary_stages = 0; VkShaderStageFlags active_stages = 0; + /* No compilation when pipeline binaries are imported. */ + if (binary_info) + return true; + /* Do not skip for libraries. */ if (create_flags & VK_PIPELINE_CREATE_2_LIBRARY_BIT_KHR) return false; diff --git a/src/amd/vulkan/radv_pipeline_rt.h b/src/amd/vulkan/radv_pipeline_rt.h index 1f5bfee9c2e..99c00673259 100644 --- a/src/amd/vulkan/radv_pipeline_rt.h +++ b/src/amd/vulkan/radv_pipeline_rt.h @@ -121,4 +121,13 @@ VkResult radv_generate_ray_tracing_state_key(struct radv_device *device, void radv_ray_tracing_state_key_finish(struct radv_ray_tracing_state_key *rt_state); +struct radv_ray_tracing_binary_header { + uint32_t is_traversal_shader : 1; + uint32_t has_shader : 1; + uint32_t has_nir : 1; + uint8_t stage_sha1[SHA1_DIGEST_LENGTH]; + uint32_t stack_size; + struct radv_ray_tracing_stage_info stage_info; +}; + #endif /* RADV_PIPELINE_RT */