ddf2aa3a4d
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>
363 lines
11 KiB
C
363 lines
11 KiB
C
/*
|
|
* Copyright © 2024 Valve Corporation
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "radv_printf.h"
|
|
#include "radv_device.h"
|
|
#include "radv_physical_device.h"
|
|
|
|
#include "util/hash_table.h"
|
|
#include "util/strndup.h"
|
|
#include "util/u_printf.h"
|
|
|
|
#include "nir.h"
|
|
#include "nir_builder.h"
|
|
|
|
static struct hash_table *device_ht = NULL;
|
|
|
|
VkResult
|
|
radv_printf_data_init(struct radv_device *device)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
|
|
util_dynarray_init(&device->printf.formats, NULL);
|
|
|
|
device->printf.buffer_size = debug_get_num_option("RADV_PRINTF_BUFFER_SIZE", 0);
|
|
if (device->printf.buffer_size < sizeof(struct radv_printf_buffer_header))
|
|
return VK_SUCCESS;
|
|
|
|
VkBufferCreateInfo buffer_create_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.pNext =
|
|
&(VkBufferUsageFlags2CreateInfo){
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_USAGE_FLAGS_2_CREATE_INFO,
|
|
.usage = VK_BUFFER_USAGE_2_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_2_SHADER_DEVICE_ADDRESS_BIT,
|
|
},
|
|
.size = device->printf.buffer_size,
|
|
};
|
|
|
|
VkDevice _device = radv_device_to_handle(device);
|
|
VkResult result = device->vk.dispatch_table.CreateBuffer(_device, &buffer_create_info, NULL, &device->printf.buffer);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
VkMemoryRequirements requirements;
|
|
device->vk.dispatch_table.GetBufferMemoryRequirements(_device, device->printf.buffer, &requirements);
|
|
|
|
VkMemoryAllocateInfo alloc_info = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = requirements.size,
|
|
.memoryTypeIndex =
|
|
radv_find_memory_index(pdev, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT),
|
|
};
|
|
|
|
result = device->vk.dispatch_table.AllocateMemory(_device, &alloc_info, NULL, &device->printf.memory);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
result = device->vk.dispatch_table.MapMemory(_device, device->printf.memory, 0, VK_WHOLE_SIZE, 0,
|
|
(void **)&device->printf.data);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
result = device->vk.dispatch_table.BindBufferMemory(_device, device->printf.buffer, device->printf.memory, 0);
|
|
if (result != VK_SUCCESS)
|
|
return result;
|
|
|
|
struct radv_printf_buffer_header *header = device->printf.data;
|
|
header->offset = sizeof(struct radv_printf_buffer_header);
|
|
header->size = device->printf.buffer_size;
|
|
|
|
VkBufferDeviceAddressInfo addr_info = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,
|
|
.buffer = device->printf.buffer,
|
|
};
|
|
device->printf.buffer_addr = device->vk.dispatch_table.GetBufferDeviceAddress(_device, &addr_info);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
void
|
|
radv_printf_data_finish(struct radv_device *device)
|
|
{
|
|
VkDevice _device = radv_device_to_handle(device);
|
|
|
|
device->vk.dispatch_table.DestroyBuffer(_device, device->printf.buffer, NULL);
|
|
if (device->printf.memory)
|
|
device->vk.dispatch_table.UnmapMemory(_device, device->printf.memory);
|
|
device->vk.dispatch_table.FreeMemory(_device, device->printf.memory, NULL);
|
|
|
|
util_dynarray_foreach (&device->printf.formats, struct radv_printf_format, format)
|
|
free(format->string);
|
|
|
|
util_dynarray_fini(&device->printf.formats);
|
|
}
|
|
|
|
static bool
|
|
radv_shader_printf_enabled(nir_shader *shader)
|
|
{
|
|
if (!device_ht)
|
|
return false;
|
|
|
|
struct radv_device *device = _mesa_hash_table_search(device_ht, shader)->data;
|
|
return !!device->printf.buffer_addr;
|
|
}
|
|
|
|
void
|
|
radv_build_printf_args(nir_builder *b, nir_def *cond, const char *format_string, uint32_t argc, nir_def **in_args)
|
|
{
|
|
if (!radv_shader_printf_enabled(b->shader))
|
|
return;
|
|
|
|
struct radv_printf_format format = {0};
|
|
format.string = strdup(format_string);
|
|
if (!format.string)
|
|
return;
|
|
|
|
struct radv_device *device = _mesa_hash_table_search(device_ht, b->shader)->data;
|
|
uint32_t format_index = util_dynarray_num_elements(&device->printf.formats, struct radv_printf_format);
|
|
|
|
if (cond)
|
|
nir_push_if(b, cond);
|
|
|
|
if (b->shader->info.stage == MESA_SHADER_FRAGMENT)
|
|
nir_push_if(b, nir_inot(b, nir_is_helper_invocation(b, 1)));
|
|
|
|
nir_def *size = nir_imm_int(b, 4);
|
|
|
|
nir_def **args = malloc(argc * sizeof(nir_def *));
|
|
nir_def **strides = malloc(argc * sizeof(nir_def *));
|
|
|
|
nir_def *ballot = nir_ballot(b, 1, 64, nir_imm_true(b));
|
|
nir_def *active_invocation_count = nir_bit_count(b, ballot);
|
|
|
|
for (uint32_t i = 0; i < argc; i++) {
|
|
nir_def *arg = in_args[i];
|
|
bool divergent = arg->divergent;
|
|
|
|
if (arg->bit_size == 1)
|
|
arg = nir_b2i32(b, arg);
|
|
|
|
args[i] = arg;
|
|
|
|
uint32_t arg_size = arg->bit_size == 1 ? 32 : arg->bit_size / 8;
|
|
format.element_sizes[i] = arg_size;
|
|
|
|
if (divergent) {
|
|
strides[i] = nir_imul_imm(b, active_invocation_count, arg_size);
|
|
format.divergence_mask |= BITFIELD_BIT(i);
|
|
} else {
|
|
strides[i] = nir_imm_int(b, arg_size);
|
|
}
|
|
|
|
size = nir_iadd(b, size, strides[i]);
|
|
}
|
|
|
|
nir_def *offset;
|
|
nir_def *undef;
|
|
|
|
nir_push_if(b, nir_elect(b, 1));
|
|
{
|
|
offset = nir_global_atomic(
|
|
b, 32, nir_imm_int64(b, device->printf.buffer_addr + offsetof(struct radv_printf_buffer_header, offset)), size,
|
|
.atomic_op = nir_atomic_op_iadd);
|
|
}
|
|
nir_push_else(b, NULL);
|
|
{
|
|
undef = nir_undef(b, 1, 32);
|
|
}
|
|
nir_pop_if(b, NULL);
|
|
|
|
offset = nir_read_first_invocation(b, nir_if_phi(b, offset, undef));
|
|
|
|
nir_def *buffer_size = nir_load_global(
|
|
b, nir_imm_int64(b, device->printf.buffer_addr + offsetof(struct radv_printf_buffer_header, size)), 4, 1, 32);
|
|
|
|
nir_push_if(b, nir_ige(b, buffer_size, nir_iadd(b, offset, size)));
|
|
{
|
|
nir_def *addr = nir_iadd_imm(b, nir_u2u64(b, offset), device->printf.buffer_addr);
|
|
|
|
/* header */
|
|
nir_store_global(b, addr, 4, nir_ior_imm(b, active_invocation_count, format_index << 16), 1);
|
|
addr = nir_iadd_imm(b, addr, 4);
|
|
|
|
for (uint32_t i = 0; i < argc; i++) {
|
|
nir_def *arg = args[i];
|
|
|
|
if (arg->divergent) {
|
|
nir_def *invocation_index = nir_mbcnt_amd(b, ballot, nir_imm_int(b, 0));
|
|
nir_store_global(
|
|
b, nir_iadd(b, addr, nir_u2u64(b, nir_imul_imm(b, invocation_index, format.element_sizes[i]))), 4, arg,
|
|
1);
|
|
} else {
|
|
nir_store_global(b, addr, 4, arg, 1);
|
|
}
|
|
|
|
addr = nir_iadd(b, addr, nir_u2u64(b, strides[i]));
|
|
}
|
|
}
|
|
nir_pop_if(b, NULL);
|
|
|
|
if (cond)
|
|
nir_pop_if(b, NULL);
|
|
|
|
if (b->shader->info.stage == MESA_SHADER_FRAGMENT)
|
|
nir_pop_if(b, NULL);
|
|
|
|
free(args);
|
|
free(strides);
|
|
|
|
util_dynarray_append(&device->printf.formats, struct radv_printf_format, format);
|
|
}
|
|
|
|
void
|
|
radv_build_printf(nir_builder *b, nir_def *cond, const char *format_string, ...)
|
|
{
|
|
if (!radv_shader_printf_enabled(b->shader))
|
|
return;
|
|
|
|
va_list arg_list;
|
|
va_start(arg_list, format_string);
|
|
|
|
uint32_t num_args = 0;
|
|
for (uint32_t i = 0; i < strlen(format_string); i++)
|
|
if (format_string[i] == '%')
|
|
num_args++;
|
|
|
|
nir_def **args = malloc(num_args * sizeof(nir_def *));
|
|
|
|
for (uint32_t i = 0; i < num_args; i++)
|
|
args[i] = va_arg(arg_list, nir_def *);
|
|
|
|
va_end(arg_list);
|
|
|
|
radv_build_printf_args(b, cond, format_string, num_args, args);
|
|
|
|
free(args);
|
|
}
|
|
|
|
void
|
|
radv_dump_printf_data(struct radv_device *device, FILE *out)
|
|
{
|
|
if (!device->printf.data)
|
|
return;
|
|
|
|
device->vk.dispatch_table.DeviceWaitIdle(radv_device_to_handle(device));
|
|
|
|
struct radv_printf_buffer_header *header = device->printf.data;
|
|
uint8_t *data = device->printf.data;
|
|
|
|
for (uint32_t offset = sizeof(struct radv_printf_buffer_header); offset < header->offset;) {
|
|
uint32_t printf_header = *(uint32_t *)&data[offset];
|
|
offset += sizeof(uint32_t);
|
|
|
|
uint32_t format_index = printf_header >> 16;
|
|
struct radv_printf_format *printf_format =
|
|
util_dynarray_element(&device->printf.formats, struct radv_printf_format, format_index);
|
|
|
|
uint32_t invocation_count = printf_header & 0xFFFF;
|
|
|
|
uint32_t num_args = 0;
|
|
for (uint32_t i = 0; i < strlen(printf_format->string); i++)
|
|
if (printf_format->string[i] == '%')
|
|
num_args++;
|
|
|
|
char *format = printf_format->string;
|
|
|
|
for (uint32_t i = 0; i <= num_args; i++) {
|
|
size_t spec_pos = util_printf_next_spec_pos(format, 0);
|
|
|
|
if (spec_pos == -1) {
|
|
fprintf(out, "%s", format);
|
|
continue;
|
|
}
|
|
|
|
const char *token = util_printf_prev_tok(&format[spec_pos]);
|
|
char *next_format = &format[spec_pos + 1];
|
|
|
|
/* print the part before the format token */
|
|
if (token != format)
|
|
fwrite(format, token - format, 1, out);
|
|
|
|
char *print_str = strndup(token, next_format - token);
|
|
/* rebase spec_pos so we can use it with print_str */
|
|
spec_pos += format - token;
|
|
|
|
size_t element_size = printf_format->element_sizes[i];
|
|
bool is_float = strpbrk(print_str, "fFeEgGaA") != NULL;
|
|
|
|
uint32_t lane_count = (printf_format->divergence_mask & BITFIELD_BIT(i)) ? invocation_count : 1;
|
|
for (uint32_t lane = 0; lane < lane_count; lane++) {
|
|
switch (element_size) {
|
|
case 1: {
|
|
uint8_t v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
break;
|
|
}
|
|
case 2: {
|
|
uint16_t v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
break;
|
|
}
|
|
case 4: {
|
|
if (is_float) {
|
|
float v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
} else {
|
|
uint32_t v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
}
|
|
break;
|
|
}
|
|
case 8: {
|
|
if (is_float) {
|
|
double v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
} else {
|
|
uint64_t v;
|
|
memcpy(&v, &data[offset], element_size);
|
|
fprintf(out, print_str, v);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
UNREACHABLE("Unsupported data type");
|
|
}
|
|
|
|
if (lane != lane_count - 1)
|
|
fprintf(out, " ");
|
|
|
|
offset += element_size;
|
|
}
|
|
|
|
/* rebase format */
|
|
format = next_format;
|
|
free(print_str);
|
|
}
|
|
}
|
|
|
|
fflush(out);
|
|
|
|
header->offset = sizeof(struct radv_printf_buffer_header);
|
|
}
|
|
|
|
void
|
|
radv_device_associate_nir(struct radv_device *device, nir_shader *nir)
|
|
{
|
|
if (!device->printf.buffer_addr)
|
|
return;
|
|
|
|
if (!device_ht)
|
|
device_ht = _mesa_pointer_hash_table_create(NULL);
|
|
|
|
_mesa_hash_table_insert(device_ht, nir, device);
|
|
}
|