Edit

IABSD.fr/xenocara/lib/mesa/src/amd/vulkan/radv_pipeline_binary.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2025-06-05 11:23:11
    Hash : 67d6f117
    Message : Import Mesa 25.0.7

  • lib/mesa/src/amd/vulkan/radv_pipeline_binary.c
  • /*
     * 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);
       const struct radv_physical_device *pdev = radv_device_physical(device);
       VkResult result;
    
       memset(pPipelineKey->key, 0, sizeof(pPipelineKey->key));
    
       /* Return the global key that applies to all pipelines. */
       if (!pPipelineCreateInfo) {
          struct mesa_blake3 ctx;
    
          static_assert(sizeof(blake3_hash) <= sizeof(pPipelineKey->key), "mismatch pipeline binary key size");
    
          _mesa_blake3_init(&ctx);
          _mesa_blake3_update(&ctx, pdev->cache_uuid, sizeof(pdev->cache_uuid));
          _mesa_blake3_update(&ctx, device->cache_hash, sizeof(device->cache_hash));
          _mesa_blake3_final(&ctx, pPipelineKey->key);
    
          pPipelineKey->keySize = sizeof(blake3_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, BLAKE3_OUT_LEN);
    
       *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));
       if (rt_stage_info)
          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;
    
       memcpy(pPipelineBinaryKey->key, pipeline_binary->key, sizeof(pipeline_binary->key));
       pPipelineBinaryKey->keySize = sizeof(pipeline_binary->key);
    
       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;
    
       return VK_SUCCESS;
    }
    
    VKAPI_ATTR VkResult VKAPI_CALL
    radv_ReleaseCapturedPipelineDataKHR(VkDevice _device, const VkReleaseCapturedPipelineDataInfoKHR *pInfo,
                                        const VkAllocationCallbacks *pAllocator)
    {
       /* no-op */
       return VK_SUCCESS;
    }