mesa/src/amd/vulkan/radv_pipeline_binary.c
Antonio Ospite ddf2aa3a4d build: avoid redefining unreachable() which is standard in C23
In the C23 standard unreachable() is now a predefined function-like
macro in <stddef.h>

See https://android.googlesource.com/platform/bionic/+/HEAD/docs/c23.md#is-now-a-predefined-function_like-macro-in

And this causes build errors when building for C23:

-----------------------------------------------------------------------
In file included from ../src/util/log.h:30,
                 from ../src/util/log.c:30:
../src/util/macros.h:123:9: warning: "unreachable" redefined
  123 | #define unreachable(str)    \
      |         ^~~~~~~~~~~
In file included from ../src/util/macros.h:31:
/usr/lib/gcc/x86_64-linux-gnu/14/include/stddef.h:456:9: note: this is the location of the previous definition
  456 | #define unreachable() (__builtin_unreachable ())
      |         ^~~~~~~~~~~
-----------------------------------------------------------------------

So don't redefine it with the same name, but use the name UNREACHABLE()
to also signify it's a macro.

Using a different name also makes sense because the behavior of the
macro was extending the one of __builtin_unreachable() anyway, and it
also had a different signature, accepting one argument, compared to the
standard unreachable() with no arguments.

This change improves the chances of building mesa with the C23 standard,
which for instance is the default in recent AOSP versions.

All the instances of the macro, including the definition, were updated
with the following command line:

  git grep -l '[^_]unreachable(' -- "src/**" | sort | uniq | \
  while read file; \
  do \
    sed -e 's/\([^_]\)unreachable(/\1UNREACHABLE(/g' -i "$file"; \
  done && \
  sed -e 's/#undef unreachable/#undef UNREACHABLE/g' -i src/intel/isl/isl_aux_info.c

Reviewed-by: Erik Faye-Lund <erik.faye-lund@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/36437>
2025-07-31 17:49:42 +00:00

454 lines
16 KiB
C

/*
* Copyright © 2024 Valve Corporation
*
* SPDX-License-Identifier: MIT
*/
#include "radv_pipeline_binary.h"
#include "util/blob.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 "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;
}