From cca8803e6bd19bd4c9f11239b5d79a662be986ce Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Tue, 14 Dec 2021 09:54:07 +0100 Subject: [PATCH] radv/winsys: update sparse mappings with OP_REPLACE instead of OP_MAP/OP_UNMAP When the BO is NULL, AMDGPU will reset the PTE VA range to the initial state. Otherwise, it will first unmap all existing VA that overlap the requested range and then map. This seems better than using MAP/UNMAP. This reduces stuttering in Forza Horizon 5. Signed-off-by: Samuel Pitoiset Reviewed-by: Bas Nieuwenhuizen Part-of: --- src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c | 79 ++++++------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c index 79e1265b063..42e6c086ae4 100644 --- a/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c +++ b/src/amd/vulkan/winsys/amdgpu/radv_amdgpu_bo.c @@ -65,42 +65,6 @@ radv_amdgpu_bo_va_op(struct radv_amdgpu_winsys *ws, amdgpu_bo_handle bo, uint64_ return amdgpu_bo_va_op_raw(ws->dev, bo, offset, size, addr, flags, ops); } -static void -radv_amdgpu_winsys_virtual_map(struct radv_amdgpu_winsys *ws, struct radv_amdgpu_winsys_bo *bo, - const struct radv_amdgpu_map_range *range) -{ - uint64_t internal_flags = 0; - assert(range->size); - - if (!range->bo) { - internal_flags |= AMDGPU_VM_PAGE_PRT; - } - - int r = radv_amdgpu_bo_va_op(ws, range->bo ? range->bo->bo : NULL, range->bo_offset, range->size, - range->offset + bo->base.va, 0, internal_flags, AMDGPU_VA_OP_MAP); - if (r) - abort(); -} - -static void -radv_amdgpu_winsys_virtual_unmap(struct radv_amdgpu_winsys *ws, struct radv_amdgpu_winsys_bo *bo, - const struct radv_amdgpu_map_range *range) -{ - uint64_t internal_flags = 0; - assert(range->size); - - if (!range->bo) { - /* Even though this is an unmap, if we don't set this flag, - AMDGPU is going to complain about the missing buffer. */ - internal_flags |= AMDGPU_VM_PAGE_PRT; - } - - int r = radv_amdgpu_bo_va_op(ws, range->bo ? range->bo->bo : NULL, range->bo_offset, range->size, - range->offset + bo->base.va, 0, internal_flags, AMDGPU_VA_OP_UNMAP); - if (r) - abort(); -} - static int bo_comparator(const void *ap, const void *bp) { @@ -151,10 +115,27 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins int first = 0, last; struct radv_amdgpu_map_range new_first, new_last; VkResult result; + int r; assert(parent->is_virtual); assert(!bo || !bo->is_virtual); + /* When the BO is NULL, AMDGPU will reset the PTE VA range to the initial state. Otherwise, it + * will first unmap all existing VA that overlap the requested range and then map. + */ + if (bo) { + r = radv_amdgpu_bo_va_op(ws, bo->bo, bo_offset, size, parent->base.va + offset, 0, 0, + AMDGPU_VA_OP_REPLACE); + } else { + r = radv_amdgpu_bo_va_op(ws, NULL, 0, size, parent->base.va + offset, 0, AMDGPU_VM_PAGE_PRT, + AMDGPU_VA_OP_REPLACE); + } + + if (r) { + fprintf(stderr, "amdgpu: Failed to replace a PRT VA region (%d).\n", r); + return VK_ERROR_OUT_OF_DEVICE_MEMORY; + } + /* We have at most 2 new ranges (1 by the bind, and another one by splitting a range that * contains the newly bound range). */ if (parent->range_capacity - parent->range_count < 2) { @@ -186,7 +167,6 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins * whether to not create the corresponding split part. */ bool remove_first = parent->ranges[first].offset == offset; bool remove_last = parent->ranges[last].offset + parent->ranges[last].size == offset + size; - bool unmapped_first = false; assert(parent->ranges[first].offset <= offset); assert(parent->ranges[last].offset + parent->ranges[last].size >= offset + size); @@ -212,11 +192,6 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins range_count_delta = 1 - (last - first + 1) + !remove_first + !remove_last; new_idx = first + !remove_first; - /* Any range between first and last is going to be entirely covered by the new range so just - * unmap them. */ - for (int i = first + 1; i < last; ++i) - radv_amdgpu_winsys_virtual_unmap(ws, parent, parent->ranges + i); - /* If the first/last range are not left alone we unmap then and optionally map * them again after modifications. Not that this implicitly can do the splitting * if first == last. */ @@ -224,24 +199,16 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins new_last = parent->ranges[last]; if (parent->ranges[first].offset + parent->ranges[first].size > offset || remove_first) { - radv_amdgpu_winsys_virtual_unmap(ws, parent, parent->ranges + first); - unmapped_first = true; - if (!remove_first) { new_first.size = offset - new_first.offset; - radv_amdgpu_winsys_virtual_map(ws, parent, &new_first); } } if (parent->ranges[last].offset < offset + size || remove_last) { - if (first != last || !unmapped_first) - radv_amdgpu_winsys_virtual_unmap(ws, parent, parent->ranges + last); - if (!remove_last) { new_last.size -= offset + size - new_last.offset; new_last.bo_offset += (offset + size - new_last.offset); new_last.offset = offset + size; - radv_amdgpu_winsys_virtual_map(ws, parent, &new_last); } } @@ -261,8 +228,6 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins parent->ranges[new_idx].bo = bo; parent->ranges[new_idx].bo_offset = bo_offset; - radv_amdgpu_winsys_virtual_map(ws, parent, parent->ranges + new_idx); - parent->range_count += range_count_delta; result = radv_amdgpu_winsys_rebuild_bo_list(parent); @@ -446,7 +411,15 @@ radv_amdgpu_winsys_bo_create(struct radeon_winsys *_ws, uint64_t size, unsigned bo->ranges[0].bo = NULL; bo->ranges[0].bo_offset = 0; - radv_amdgpu_winsys_virtual_map(ws, bo, bo->ranges); + /* Reserve a PRT VA region. */ + r = radv_amdgpu_bo_va_op(ws, NULL, 0, size, bo->base.va, 0, AMDGPU_VM_PAGE_PRT, + AMDGPU_VA_OP_MAP); + if (r) { + fprintf(stderr, "amdgpu: Failed to reserve a PRT VA region (%d).\n", r); + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + goto error_ranges_alloc; + } + radv_amdgpu_log_bo(ws, bo, false); *out_bo = (struct radeon_winsys_bo *)bo;