anv: fix capture/replay of sparse images with descriptor buffer

We were not implementing vkGetImageOpaqueCaptureDescriptorDataEXT,
relying on the common implementation that does nothing. That works well
enough for regular images because the fixed address needed for
capture/replay is handled by the memory allocation path, but for sparse
images we initialize the sparse bindings at image creation time.

Here we implement the function to retrieve the addresses of all the
used bindings for the image, then use all of them at creation time.
Also, set the correct alloc_flags for this to work.

Fixes: 43b57ee8a5 ("anv: add capture/replay support for image with descriptor buffers")
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35872>
(cherry picked from commit 20f546d6c1)
This commit is contained in:
Iván Briano 2025-06-30 14:21:09 -07:00 committed by Eric Engestrom
parent 5cb6fbb491
commit 1c3c022f7d
4 changed files with 85 additions and 6 deletions

View file

@ -7884,7 +7884,7 @@
"description": "anv: fix capture/replay of sparse images with descriptor buffer",
"nominated": true,
"nomination_type": 2,
"resolution": 0,
"resolution": 1,
"main_sha": null,
"because_sha": "43b57ee8a5612758f9078848ee2e725f2a239d95",
"notes": null

View file

@ -1482,8 +1482,24 @@ alloc_private_binding(struct anv_device *device,
if (binding->memory_range.size == 0)
return VK_SUCCESS;
enum anv_bo_alloc_flags alloc_flags = 0;
uint64_t explicit_address = 0;
if (create_info->flags & VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT) {
alloc_flags |= ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS;
const VkOpaqueCaptureDescriptorDataCreateInfoEXT *opaque_info =
vk_find_struct_const(create_info->pNext,
OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT);
if (opaque_info) {
const struct anv_image_opaque_capture_data *explicit_addresses =
opaque_info->opaqueCaptureDescriptorData;
explicit_address = explicit_addresses->private_binding;
}
}
VkResult result = anv_device_alloc_bo(device, "image-binding-private",
binding->memory_range.size, 0, 0,
binding->memory_range.size,
alloc_flags, explicit_address,
&binding->address.bo);
ANV_DMR_BO_ALLOC(&image->vk.base, binding->address.bo, result);
@ -1520,15 +1536,15 @@ anv_image_init_sparse_bindings(struct anv_image *image,
assert(anv_image_is_sparse(image));
enum anv_bo_alloc_flags alloc_flags = 0;
uint64_t explicit_address = 0;
const struct anv_image_opaque_capture_data *explicit_addresses = NULL;
if (image->vk.create_flags & VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT) {
alloc_flags |= ANV_BO_ALLOC_FIXED_ADDRESS;
alloc_flags |= ANV_BO_ALLOC_CLIENT_VISIBLE_ADDRESS;
const VkOpaqueCaptureDescriptorDataCreateInfoEXT *opaque_info =
vk_find_struct_const(create_info->vk_info->pNext,
OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT);
if (opaque_info)
explicit_address = *((const uint64_t *)opaque_info->opaqueCaptureDescriptorData);
explicit_addresses = opaque_info->opaqueCaptureDescriptorData;
}
for (int i = 0; i < ANV_IMAGE_MEMORY_BINDING_END; i++) {
@ -1537,6 +1553,25 @@ anv_image_init_sparse_bindings(struct anv_image *image,
if (b->memory_range.size != 0) {
assert(b->sparse_data.size == 0);
uint64_t explicit_address = 0;
if (explicit_addresses) {
switch (i) {
case ANV_IMAGE_MEMORY_BINDING_MAIN:
explicit_address = explicit_addresses->planes[0];
break;
case ANV_IMAGE_MEMORY_BINDING_PLANE_0:
case ANV_IMAGE_MEMORY_BINDING_PLANE_1:
case ANV_IMAGE_MEMORY_BINDING_PLANE_2:
explicit_address = explicit_addresses->planes[i - ANV_IMAGE_MEMORY_BINDING_PLANE_0];
break;
case ANV_IMAGE_MEMORY_BINDING_PRIVATE:
explicit_address = explicit_addresses->private_binding;
break;
default:
unreachable("invalid binding");
}
}
/* From the spec, Custom Sparse Image Block Shapes section:
* "... the size in bytes of the custom sparse image block shape
* will be reported in VkMemoryRequirements::alignment."
@ -2084,6 +2119,41 @@ anv_DestroyImage(VkDevice _device, VkImage _image,
vk_free2(&device->vk.alloc, pAllocator, image);
}
VkResult
anv_GetImageOpaqueCaptureDescriptorDataEXT(VkDevice device,
const VkImageCaptureDescriptorDataInfoEXT *pInfo,
void *pData)
{
ANV_FROM_HANDLE(anv_image, image, pInfo->image);
struct anv_image_opaque_capture_data *bound_addresses = pData;
memset(bound_addresses, 0, sizeof(*bound_addresses));
for (int i = 0; i < ANV_IMAGE_MEMORY_BINDING_END; i++) {
struct anv_image_binding *b = &image->bindings[i];
if (b->memory_range.size != 0) {
uint64_t addr = anv_address_physical(b->address);
switch (i) {
case ANV_IMAGE_MEMORY_BINDING_MAIN:
bound_addresses->planes[0] = addr;
break;
case ANV_IMAGE_MEMORY_BINDING_PLANE_0:
case ANV_IMAGE_MEMORY_BINDING_PLANE_1:
case ANV_IMAGE_MEMORY_BINDING_PLANE_2:
bound_addresses->planes[i - ANV_IMAGE_MEMORY_BINDING_PLANE_0] = addr;
break;
case ANV_IMAGE_MEMORY_BINDING_PRIVATE:
bound_addresses->private_binding = addr;
break;
default:
unreachable("invalid binding");
}
}
}
return VK_SUCCESS;
}
/* We are binding AHardwareBuffer. Get a description, resolve the
* format and prepare anv_image properly.
*/

View file

@ -1632,7 +1632,11 @@ get_properties(const struct anv_physical_device *pdevice,
/* Storing a 64bit address */
props->bufferCaptureReplayDescriptorDataSize = 8;
props->imageCaptureReplayDescriptorDataSize = 8;
/* 4 64bit addresses for the worst case (multiplanar disjoint +
* private binding)
*/
props->imageCaptureReplayDescriptorDataSize =
sizeof(struct anv_image_opaque_capture_data);
/* Offset inside the reserved border color pool */
props->samplerCaptureReplayDescriptorDataSize = 4;

View file

@ -5685,6 +5685,11 @@ struct anv_image {
struct anv_image_memory_range av1_cdf_table;
};
struct anv_image_opaque_capture_data {
uint64_t planes[3];
uint64_t private_binding;
};
static inline bool
anv_image_is_protected(const struct anv_image *image)
{