From 542538cf0212c4e24db01cda59b9ece55f51615e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 22 Jun 2022 04:14:38 -0700 Subject: [PATCH] vulkan: Add a vk_pipeline_hash_shader_stage() helper All drivers implement some sort of shader hashing, but each of them does it slightly differently. Let's provide a generic helper to avoid new copies of the same logic and encourage new drivers to use one of the already implemented function. Reviewed-by: Samuel Pitoiset Reviewed-by: Jason Ekstrand Part-of: --- src/vulkan/runtime/vk_pipeline.c | 60 ++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_pipeline.h | 15 ++++++++ 2 files changed, 75 insertions(+) diff --git a/src/vulkan/runtime/vk_pipeline.c b/src/vulkan/runtime/vk_pipeline.c index 9eac775b7f2..76d5d25aa91 100644 --- a/src/vulkan/runtime/vk_pipeline.c +++ b/src/vulkan/runtime/vk_pipeline.c @@ -28,6 +28,10 @@ #include "vk_shader_module.h" #include "vk_util.h" +#include "nir_serialize.h" + +#include "util/mesa-sha1.h" + VkResult vk_pipeline_shader_stage_to_nir(struct vk_device *device, const VkPipelineShaderStageCreateInfo *info, @@ -86,3 +90,59 @@ vk_pipeline_shader_stage_to_nir(struct vk_device *device, return VK_SUCCESS; } + +void +vk_pipeline_hash_shader_stage(const VkPipelineShaderStageCreateInfo *info, + unsigned char *stage_sha1) +{ + VK_FROM_HANDLE(vk_shader_module, module, info->module); + + if (module && module->nir) { + /* Internal NIR module: serialize and hash the NIR shader. + * We don't need to hash other info fields since they should match the + * NIR data. + */ + assert(module->nir->info.stage == vk_to_mesa_shader_stage(info->stage)); + ASSERTED nir_function_impl *entrypoint = nir_shader_get_entrypoint(module->nir); + assert(strcmp(entrypoint->function->name, info->pName) == 0); + assert(info->pSpecializationInfo == NULL); + + struct blob blob; + + blob_init(&blob); + nir_serialize(&blob, module->nir, false); + assert(!blob.out_of_memory); + _mesa_sha1_compute(blob.data, blob.size, stage_sha1); + blob_finish(&blob); + return; + } + + struct mesa_sha1 ctx; + + _mesa_sha1_init(&ctx); + if (module) { + _mesa_sha1_update(&ctx, module->sha1, sizeof(module->sha1)); + } else { + const VkShaderModuleCreateInfo *minfo = + vk_find_struct_const(info->pNext, SHADER_MODULE_CREATE_INFO); + unsigned char spirv_sha1[SHA1_DIGEST_LENGTH]; + + assert(minfo); + _mesa_sha1_compute(minfo->pCode, minfo->codeSize, spirv_sha1); + _mesa_sha1_update(&ctx, spirv_sha1, sizeof(spirv_sha1)); + } + + _mesa_sha1_update(&ctx, info->pName, strlen(info->pName)); + + assert(util_bitcount(info->stage) == 1); + _mesa_sha1_update(&ctx, &info->stage, sizeof(info->stage)); + + if (info->pSpecializationInfo) { + _mesa_sha1_update(&ctx, info->pSpecializationInfo->pMapEntries, + info->pSpecializationInfo->mapEntryCount * + sizeof(*info->pSpecializationInfo->pMapEntries)); + _mesa_sha1_update(&ctx, info->pSpecializationInfo->pData, + info->pSpecializationInfo->dataSize); + } + _mesa_sha1_final(&ctx, stage_sha1); +} diff --git a/src/vulkan/runtime/vk_pipeline.h b/src/vulkan/runtime/vk_pipeline.h index 41f99880379..a5bff1d55e8 100644 --- a/src/vulkan/runtime/vk_pipeline.h +++ b/src/vulkan/runtime/vk_pipeline.h @@ -42,6 +42,21 @@ vk_pipeline_shader_stage_to_nir(struct vk_device *device, const struct nir_shader_compiler_options *nir_options, void *mem_ctx, struct nir_shader **nir_out); +/** Hash VkPipelineShaderStageCreateInfo info + * + * Returns the hash of a VkPipelineShaderStageCreateInfo: + * SHA1(info->module->sha1, + * info->pName, + * vk_stage_to_mesa_stage(info->stage), + * info->pSpecializationInfo) + * + * Can only be used if VkPipelineShaderStageCreateInfo::module is a + * vk_shader_module object. + */ +void +vk_pipeline_hash_shader_stage(const VkPipelineShaderStageCreateInfo *info, + unsigned char *stage_sha1); + #ifdef __cplusplus } #endif