From 21c16fe343e0ff3ac8255e7e2c6d2d8db08326ee Mon Sep 17 00:00:00 2001 From: Alyssa Rosenzweig Date: Fri, 6 Dec 2024 10:49:01 -0500 Subject: [PATCH] asahi,hk: wire up printf, abort Signed-off-by: Alyssa Rosenzweig Reviewed-by: Mary Guillemard Part-of: --- src/asahi/clc/asahi_clc.c | 8 ++++++++ src/asahi/clc/asahi_clc.h | 12 ++++++++++++ src/asahi/lib/agx_device.c | 23 +++++++++++++++++++++++ src/asahi/lib/agx_device.h | 3 +++ src/asahi/vulkan/hk_device.c | 12 ++++++++++++ src/asahi/vulkan/hk_queue.c | 19 +++++++++++++++++-- 6 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/asahi/clc/asahi_clc.h diff --git a/src/asahi/clc/asahi_clc.c b/src/asahi/clc/asahi_clc.c index 7e0910a5da8..433bdbc54de 100644 --- a/src/asahi/clc/asahi_clc.c +++ b/src/asahi/clc/asahi_clc.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: MIT */ +#include "asahi_clc.h" #include "asahi/compiler/agx_compile.h" #include "asahi/compiler/agx_nir.h" #include "compiler/glsl_types.h" @@ -36,6 +37,7 @@ static const struct spirv_to_nir_options spirv_options = { .temp_addr_format = nir_address_format_62bit_generic, .constant_addr_format = nir_address_format_64bit_global, .create_library = true, + .printf = true, }; /* Standard optimization loop */ @@ -94,6 +96,12 @@ compile(void *memctx, const uint32_t *spirv, size_t spirv_size) nir_lower_compute_system_values_options cs = {.global_id_is_32bit = true}; NIR_PASS(_, nir, nir_lower_compute_system_values, &cs); + NIR_PASS(_, nir, nir_lower_printf, + &(const struct nir_lower_printf_options){ + .buffer_address = LIBAGX_PRINTF_BUFFER_ADDRESS, + .max_buffer_size = LIBAGX_PRINTF_BUFFER_SIZE - 8, + }); + /* We have to lower away local constant initializers right before we * inline functions. That way they get properly initialized at the top * of the function and not at the top of its caller. diff --git a/src/asahi/clc/asahi_clc.h b/src/asahi/clc/asahi_clc.h new file mode 100644 index 00000000000..524146911ef --- /dev/null +++ b/src/asahi/clc/asahi_clc.h @@ -0,0 +1,12 @@ +/* + * Copyright 2024 Valve Corporation + * SPDX-License-Identifier: MIT + */ + +#pragma once + +/* The libagx printf/abort buffer addresses is fixed at compile-time for + * simplicity. + */ +#define LIBAGX_PRINTF_BUFFER_ADDRESS (1ull << 36) +#define LIBAGX_PRINTF_BUFFER_SIZE (16384) diff --git a/src/asahi/lib/agx_device.c b/src/asahi/lib/agx_device.c index eccb5503994..c69a76dc703 100644 --- a/src/asahi/lib/agx_device.c +++ b/src/asahi/lib/agx_device.c @@ -7,6 +7,8 @@ #include "agx_device.h" #include +#include "clc/asahi_clc.h" +#include "util/macros.h" #include "util/ralloc.h" #include "util/timespec.h" #include "agx_bo.h" @@ -587,6 +589,12 @@ agx_open_device(void *memctx, struct agx_device *dev) */ uint64_t reservation = (1ull << 36); + /* Also reserve VA space for the printf buffer at a stable address, avoiding + * the need for relocs in precompiled shaders. + */ + assert(reservation == LIBAGX_PRINTF_BUFFER_ADDRESS); + reservation += LIBAGX_PRINTF_BUFFER_SIZE; + dev->guard_size = dev->params.vm_page_size; if (dev->params.vm_usc_start) { dev->shader_base = dev->params.vm_usc_start; @@ -671,12 +679,27 @@ agx_open_device(void *memctx, struct agx_device *dev) dev->chip = AGX_CHIP_G13G; } + void *bo = agx_bo_create(dev, LIBAGX_PRINTF_BUFFER_SIZE, 0, AGX_BO_WRITEBACK, + "Printf/abort"); + + ret = dev->ops.bo_bind(dev, bo, LIBAGX_PRINTF_BUFFER_ADDRESS, + LIBAGX_PRINTF_BUFFER_SIZE, 0, + ASAHI_BIND_READ | ASAHI_BIND_WRITE, false); + if (ret) { + fprintf(stderr, "Failed to bind printf buffer"); + return false; + } + + u_printf_init(&dev->printf, bo, agx_bo_map(bo)); + return true; } void agx_close_device(struct agx_device *dev) { + agx_bo_unreference(dev, dev->printf.bo); + u_printf_destroy(&dev->printf); ralloc_free((void *)dev->libagx); agx_bo_cache_evict_all(dev); util_sparse_array_finish(&dev->bo_map); diff --git a/src/asahi/lib/agx_device.h b/src/asahi/lib/agx_device.h index 4e5ef335457..5955ae00deb 100644 --- a/src/asahi/lib/agx_device.h +++ b/src/asahi/lib/agx_device.h @@ -11,6 +11,7 @@ #include "util/simple_mtx.h" #include "util/sparse_array.h" #include "util/timespec.h" +#include "util/u_printf.h" #include "util/vma.h" #include "agx_bo.h" #include "agx_pack.h" @@ -172,6 +173,8 @@ struct agx_device { uint64_t num; uint64_t den; } user_timestamp_to_ns; + + struct u_printf_ctx printf; }; static inline void * diff --git a/src/asahi/vulkan/hk_device.c b/src/asahi/vulkan/hk_device.c index e9ded668b64..5e7e4d824ea 100644 --- a/src/asahi/vulkan/hk_device.c +++ b/src/asahi/vulkan/hk_device.c @@ -27,6 +27,8 @@ #include "vulkan/wsi/wsi_common.h" #include "vk_cmd_enqueue_entrypoints.h" #include "vk_common_entrypoints.h" +#include "vk_debug_utils.h" +#include "vk_device.h" #include "vk_pipeline_cache.h" #include @@ -276,6 +278,15 @@ hk_sampler_heap_remove(struct hk_device *dev, struct hk_rc_sampler *rc) simple_mtx_unlock(&h->lock); } +static VkResult +hk_check_status(struct vk_device *device) +{ + struct hk_device *dev = container_of(device, struct hk_device, vk); + return vk_check_printf_status(&dev->vk, &dev->dev.printf, + dev->dev.libagx->printf_info, + dev->dev.libagx->printf_info_count); +} + /* * To implement nullDescriptor, the descriptor set code will reference * preuploaded null descriptors at fixed offsets in the image heap. Here we @@ -387,6 +398,7 @@ hk_CreateDevice(VkPhysicalDevice physicalDevice, vk_device_set_drm_fd(&dev->vk, dev->dev.fd); dev->vk.command_buffer_ops = &hk_cmd_buffer_ops; + dev->vk.check_status = hk_check_status; result = hk_descriptor_table_init(dev, &dev->images, AGX_TEXTURE_LENGTH, 1024, 1024 * 1024); diff --git a/src/asahi/vulkan/hk_queue.c b/src/asahi/vulkan/hk_queue.c index a08050725e2..fdebfc6be02 100644 --- a/src/asahi/vulkan/hk_queue.c +++ b/src/asahi/vulkan/hk_queue.c @@ -606,9 +606,24 @@ hk_queue_submit(struct vk_queue *vk_queue, struct vk_queue_submit *submit) VkResult result = queue_submit(dev, queue, submit); if (result != VK_SUCCESS) - return vk_queue_set_lost(&queue->vk, "Submit failed"); + result = vk_queue_set_lost(&queue->vk, "Submit failed"); - return VK_SUCCESS; + if (dev->dev.debug & AGX_DBG_SYNC) { + /* Wait for completion */ + int err = drmSyncobjTimelineWait( + dev->dev.fd, &queue->drm.syncobj, &queue->drm.timeline_value, 1, + INT64_MAX, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, NULL); + + if (err) { + result = vk_queue_set_lost(&queue->vk, "Wait failed"); + } else { + VkResult res = dev->vk.check_status(&dev->vk); + if (result == VK_SUCCESS) + result = res; + } + } + + return result; } static uint32_t