anv/image: Make memory layout more explicit

Future patches for VK_EXT_image_drm_format_modifier will, in some cases,
place the aux surface and fast clear state into a driver-private bo.
This increases the complexity of image memory layout to such a degree
that, to maintain sanity, we must improve how we track the layout.

Define new types:
  - anv_image_memory_range
  - anv_image_memory_binding
  - anv_image_binding

Delete many fields in anv_image (and its children), and replace them
with the new types.

This patch does not change how anv_image tracks (or, rather, does not
track) the memory of gen12 implicit ccs. We should probably do that, but
that's left as a future exercise.

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8097>
This commit is contained in:
Chad Versace
2020-12-14 20:13:30 -08:00
committed by chadversary
parent 4dfabac493
commit d978383966
6 changed files with 429 additions and 203 deletions

View File

@@ -534,10 +534,13 @@ anv_image_from_gralloc(VkDevice device_h,
goto fail_size;
}
assert(!image->disjoint);
assert(image->n_planes == 1);
assert(image->planes[0].address.offset == 0);
image->planes[0].address.bo = bo;
assert(image->planes[0].primary_surface.memory_range.binding ==
ANV_IMAGE_MEMORY_BINDING_MAIN);
assert(image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address.bo == NULL);
assert(image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address.offset == 0);
image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address.bo = bo;
image->from_gralloc = true;
/* Don't clobber the out-parameter until success is certain. */

View File

@@ -219,7 +219,7 @@ get_blorp_surf_for_anv_image(const struct anv_device *device,
const struct anv_surface *surface = &image->planes[plane].primary_surface;
const struct anv_address address =
anv_image_address(image, plane, surface->offset);
anv_image_address(image, &surface->memory_range);
*blorp_surf = (struct blorp_surf) {
.surf = &surface->isl,
@@ -233,15 +233,18 @@ get_blorp_surf_for_anv_image(const struct anv_device *device,
if (aux_usage != ISL_AUX_USAGE_NONE) {
const struct anv_surface *aux_surface = &image->planes[plane].aux_surface;
const struct anv_address aux_address =
anv_image_address(image, plane, aux_surface->offset);
anv_image_address(image, &aux_surface->memory_range);
blorp_surf->aux_surf = &aux_surface->isl,
blorp_surf->aux_usage = aux_usage;
blorp_surf->aux_surf = &aux_surface->isl;
if (!anv_address_is_null(aux_address)) {
blorp_surf->aux_addr = (struct blorp_address) {
.buffer = aux_address.bo,
.offset = aux_address.offset,
.mocs = anv_mocs(device, aux_address.bo, 0),
};
blorp_surf->aux_usage = aux_usage;
}
/* If we're doing a partial resolve, then we need the indirect clear
* color. If we are doing a fast clear and want to store/update the
@@ -287,7 +290,7 @@ get_blorp_surf_for_anv_shadow_image(const struct anv_device *device,
const struct anv_surface *surface = &image->planes[plane].shadow_surface;
const struct anv_address address =
anv_image_address(image, plane, surface->offset);
anv_image_address(image, &surface->memory_range);
*blorp_surf = (struct blorp_surf) {
.surf = &surface->isl,

View File

@@ -43,6 +43,83 @@ vk_to_isl_surf_dim[] = {
[VK_IMAGE_TYPE_3D] = ISL_SURF_DIM_3D,
};
static uint64_t MUST_CHECK
memory_range_end(struct anv_image_memory_range memory_range)
{
assert(anv_is_aligned(memory_range.offset, memory_range.alignment));
return memory_range.offset + memory_range.size;
}
/**
* Extend the memory binding's range by appending a new memory range with the
* given size and alignment. Return the appended range.
*
* The given binding must not be ANV_IMAGE_MEMORY_BINDING_MAIN. The function
* converts to MAIN as needed.
*/
static struct anv_image_memory_range
image_binding_grow(struct anv_image *image,
enum anv_image_memory_binding binding,
uint64_t size,
uint32_t alignment)
{
assert(size > 0);
assert(util_is_power_of_two_or_zero(alignment));
switch (binding) {
case ANV_IMAGE_MEMORY_BINDING_MAIN:
/* The caller must not pre-translate BINDING_PLANE_i to BINDING_MAIN. */
unreachable("ANV_IMAGE_MEMORY_BINDING_MAIN");
case ANV_IMAGE_MEMORY_BINDING_PLANE_0:
case ANV_IMAGE_MEMORY_BINDING_PLANE_1:
case ANV_IMAGE_MEMORY_BINDING_PLANE_2:
if (!image->disjoint)
binding = ANV_IMAGE_MEMORY_BINDING_MAIN;
break;
case ANV_IMAGE_MEMORY_BINDING_END:
unreachable("ANV_IMAGE_MEMORY_BINDING_END");
}
struct anv_image_memory_range *container =
&image->bindings[binding].memory_range;
struct anv_image_memory_range new = {
.binding = container->binding,
.offset = align_u64(container->offset + container->size, alignment),
.size = size,
.alignment = alignment,
};
container->size = new.offset + new.size;
container->alignment = MAX2(container->alignment, new.alignment);
return new;
}
/**
* Adjust range 'a' to contain range 'b'.
*
* For simplicity's sake, the offset of 'a' must be 0 and remains 0.
* If 'a' and 'b' target different bindings, then no merge occurs.
*/
static void
memory_range_merge(struct anv_image_memory_range *a,
const struct anv_image_memory_range b)
{
if (b.size == 0)
return;
if (a->binding != b.binding)
return;
assert(a->offset == 0);
assert(anv_is_aligned(a->offset, a->alignment));
assert(anv_is_aligned(b.offset, b.alignment));
a->alignment = MAX2(a->alignment, b.alignment);
a->size = MAX2(a->size, b.offset + b.size);
}
static isl_surf_usage_flags_t
choose_isl_surf_usage(VkImageCreateFlags vk_create_flags,
VkImageUsageFlags vk_usage,
@@ -141,27 +218,22 @@ choose_isl_tiling_flags(const struct gen_device_info *devinfo,
return flags;
}
/**
* Set the surface's anv_image_memory_range and add it to the given binding's
* memory range.
*
* \see image_binding_grow()
*/
static void
add_surface(struct anv_image *image, struct anv_surface *surf, uint32_t plane)
add_surface(struct anv_image *image,
enum anv_image_memory_binding binding,
struct anv_surface *surf)
{
assert(surf->isl.size_B > 0); /* isl surface must be initialized */
/* isl surface must be initialized */
assert(surf->isl.size_B > 0);
if (image->disjoint) {
surf->offset = align_u32(image->planes[plane].size,
surf->isl.alignment_B);
/* Plane offset is always 0 when it's disjoint. */
} else {
surf->offset = align_u32(image->size, surf->isl.alignment_B);
/* Determine plane's offset only once when the first surface is added. */
if (image->planes[plane].size == 0)
image->planes[plane].offset = image->size;
}
image->size = surf->offset + surf->isl.size_B;
image->planes[plane].size = (surf->offset + surf->isl.size_B) - image->planes[plane].offset;
image->alignment = MAX2(image->alignment, surf->isl.alignment_B);
image->planes[plane].alignment = MAX2(image->planes[plane].alignment,
surf->memory_range = image_binding_grow(image, binding,
surf->isl.size_B,
surf->isl.alignment_B);
}
@@ -299,30 +371,14 @@ anv_formats_ccs_e_compatible(const struct gen_device_info *devinfo,
* blorp and it knows to copy the clear color.
*/
static void
add_aux_state_tracking_buffer(struct anv_image *image,
uint32_t plane,
const struct anv_device *device)
add_aux_state_tracking_buffer(struct anv_device *device,
struct anv_image *image,
uint32_t plane)
{
assert(image && device);
assert(image->planes[plane].aux_usage != ISL_AUX_USAGE_NONE &&
image->aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV);
/* Compressed images must be tiled and therefore everything should be 4K
* aligned. The CCS has the same alignment requirements. This is good
* because we need at least dword-alignment for MI_LOAD/STORE operations.
*/
assert(image->alignment % 4 == 0);
assert((image->planes[plane].offset + image->planes[plane].size) % 4 == 0);
/* This buffer should be at the very end of the plane. */
if (image->disjoint) {
assert(image->planes[plane].size ==
(image->planes[plane].offset + image->planes[plane].size));
} else {
assert(image->size ==
(image->planes[plane].offset + image->planes[plane].size));
}
const unsigned clear_color_state_size = device->info.gen >= 10 ?
device->isl_dev.ss.clear_color_state_size :
device->isl_dev.ss.clear_value_size;
@@ -340,20 +396,12 @@ add_aux_state_tracking_buffer(struct anv_image *image,
}
}
/* Add some padding to make sure the fast clear color state buffer starts at
* a 4K alignment. We believe that 256B might be enough, but due to lack of
* testing we will leave this as 4K for now.
/* We believe that 256B alignment may be sufficient, but we choose 4K due to
* lack of testing. And MI_LOAD/STORE operations require dword-alignment.
*/
image->planes[plane].size = align_u64(image->planes[plane].size, 4096);
image->size = align_u64(image->size, 4096);
assert(image->planes[plane].offset % 4096 == 0);
image->planes[plane].fast_clear_state_offset =
image->planes[plane].offset + image->planes[plane].size;
image->planes[plane].size += state_size;
image->size += state_size;
image->planes[plane].fast_clear_memory_range =
image_binding_grow(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane,
state_size, 4096);
}
/**
@@ -436,7 +484,9 @@ add_aux_surface_if_supported(struct anv_device *device,
assert(device->info.gen >= 12);
image->planes[plane].aux_usage = ISL_AUX_USAGE_HIZ_CCS;
}
add_surface(image, &image->planes[plane].aux_surface, plane);
add_surface(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane,
&image->planes[plane].aux_surface);
} else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT) {
if (INTEL_DEBUG & DEBUG_NO_RBC)
@@ -526,9 +576,10 @@ add_aux_surface_if_supported(struct anv_device *device,
}
if (!device->physical->has_implicit_ccs)
add_surface(image, &image->planes[plane].aux_surface, plane);
add_surface(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane,
&image->planes[plane].aux_surface);
add_aux_state_tracking_buffer(image, plane, device);
add_aux_state_tracking_buffer(device, image, plane);
} else if ((aspect & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV) && image->samples > 1) {
assert(!(image->usage & VK_IMAGE_USAGE_STORAGE_BIT));
ok = isl_surf_get_mcs_surf(&device->isl_dev,
@@ -538,8 +589,9 @@ add_aux_surface_if_supported(struct anv_device *device,
return VK_SUCCESS;
image->planes[plane].aux_usage = ISL_AUX_USAGE_MCS;
add_surface(image, &image->planes[plane].aux_surface, plane);
add_aux_state_tracking_buffer(image, plane, device);
add_surface(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane,
&image->planes[plane].aux_surface);
add_aux_state_tracking_buffer(device, image, plane);
}
return VK_SUCCESS;
@@ -576,7 +628,8 @@ add_shadow_surface(struct anv_device *device,
*/
assert(ok);
add_surface(image, &image->planes[plane].shadow_surface, plane);
add_surface(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane,
&image->planes[plane].shadow_surface);
return VK_SUCCESS;
}
@@ -593,9 +646,8 @@ add_primary_surface(struct anv_device *device,
isl_tiling_flags_t isl_tiling_flags,
isl_surf_usage_flags_t isl_usage)
{
bool ok;
struct anv_surface *anv_surf = &image->planes[plane].primary_surface;
bool ok;
ok = isl_surf_init(&device->isl_dev, &anv_surf->isl,
.dim = vk_to_isl_surf_dim[image->type],
@@ -616,39 +668,122 @@ add_primary_surface(struct anv_device *device,
image->planes[plane].aux_usage = ISL_AUX_USAGE_NONE;
add_surface(image, anv_surf, plane);
add_surface(image, ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane, anv_surf);
return VK_SUCCESS;
}
#ifdef DEBUG
static bool MUST_CHECK
memory_range_is_aligned(struct anv_image_memory_range memory_range)
{
return anv_is_aligned(memory_range.offset, memory_range.alignment);
}
#endif
/**
* 'plane' must be the most recently added plane.
* Validate the image's memory bindings *after* all its surfaces and memory
* ranges are final.
*
* For simplicity's sake, we do not validate free-form layout of the image's
* memory bindings. We validate the layout described in the comments of struct
* anv_image.
*/
static void
check_surfaces(const struct anv_image *image,
const struct anv_image_plane *plane)
check_memory_bindings(const struct anv_device *device,
const struct anv_image *image)
{
#ifdef DEBUG
/* FINISHME: Check the shadow surface. */
/* XXX: This looks buggy. If the aux surface starts before the primary
* surface, then it derives a meaningless value by adding the primary's size
* to the aux's offset.
/* As we inspect each part of the image, we merge the part's memory range
* into these accumulation ranges.
*/
uintmax_t plane_end = plane->offset + plane->size;
const struct anv_surface *primary_surface = &plane->primary_surface;
const struct anv_surface *aux_surface = &plane->aux_surface;
uintmax_t last_surface_offset = MAX2(primary_surface->offset, aux_surface->offset);
uintmax_t last_surface_size = anv_surface_is_valid(aux_surface)
? aux_surface->isl.size_B
: primary_surface->isl.size_B;
uintmax_t last_surface_end = last_surface_offset + last_surface_size;
struct anv_image_memory_range accum_ranges[ANV_IMAGE_MEMORY_BINDING_END];
for (int i = 0; i < ANV_IMAGE_MEMORY_BINDING_END; ++i) {
accum_ranges[i] = (struct anv_image_memory_range) {
.binding = i,
};
}
if (plane->aux_usage != ISL_AUX_USAGE_NONE)
assert(plane->fast_clear_state_offset < plane_end);
const struct anv_image_memory_range *prev_range = NULL;
assert(last_surface_end <= plane_end);
assert(plane_end == image->size);
for (uint32_t p = 0; p < image->n_planes; ++p) {
const struct anv_image_plane *plane = &image->planes[p];
/* The memory range to which the plane's primary surface belongs.
* If the image is non-disjoint, then this accumulates over all planes.
*/
struct anv_image_memory_range *primary_range;
if (image->disjoint) {
prev_range = NULL;
primary_range = &accum_ranges[ANV_IMAGE_MEMORY_BINDING_PLANE_0 + p];
} else {
primary_range = &accum_ranges[ANV_IMAGE_MEMORY_BINDING_MAIN];
}
/* Check primary surface */
assert(anv_surface_is_valid(&plane->primary_surface));
assert(plane->primary_surface.memory_range.binding ==
primary_range->binding);
assert(memory_range_is_aligned(plane->primary_surface.memory_range));
assert(plane->primary_surface.memory_range.alignment ==
plane->primary_surface.isl.alignment_B);
memory_range_merge(primary_range, plane->primary_surface.memory_range);
prev_range = &plane->primary_surface.memory_range;
/* Check shadow surface */
if (anv_surface_is_valid(&plane->shadow_surface)) {
assert(plane->shadow_surface.memory_range.binding ==
primary_range->binding);
assert(plane->shadow_surface.memory_range.offset >=
memory_range_end(*prev_range));
assert(plane->shadow_surface.memory_range.alignment ==
plane->shadow_surface.isl.alignment_B);
assert(memory_range_is_aligned(plane->shadow_surface.memory_range));
memory_range_merge(primary_range, plane->shadow_surface.memory_range);
prev_range = &plane->shadow_surface.memory_range;
}
/* Check aux_surface */
if (anv_surface_is_valid(&plane->aux_surface)) {
assert(plane->aux_surface.memory_range.binding ==
primary_range->binding);
assert(plane->aux_surface.memory_range.alignment ==
plane->aux_surface.isl.alignment_B);
assert(memory_range_is_aligned(plane->aux_surface.memory_range));
/* Display hardware requires that the aux surface start at
* a higher address than the primary surface. The 3D hardware
* doesn't care, but we enforce the display requirement in case
* the image is sent to display.
*/
assert(plane->aux_surface.memory_range.offset >=
memory_range_end(*prev_range));
memory_range_merge(primary_range, plane->aux_surface.memory_range);
prev_range = &plane->aux_surface.memory_range;
}
/* Check fast clear state */
assert((plane->fast_clear_memory_range.size > 0) ==
(plane->aux_usage != ISL_AUX_USAGE_NONE &&
image->aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV));
if (plane->fast_clear_memory_range.size > 0) {
/* We believe that 256B alignment may be sufficient, but we choose 4K
* due to lack of testing. And MI_LOAD/STORE operations require
* dword-alignment.
*/
assert(plane->fast_clear_memory_range.binding ==
primary_range->binding);
assert(plane->fast_clear_memory_range.offset >=
memory_range_end(*prev_range));
assert(memory_range_is_aligned(plane->fast_clear_memory_range));
assert(plane->fast_clear_memory_range.alignment == 4096);
memory_range_merge(primary_range, plane->fast_clear_memory_range);
prev_range = &plane->fast_clear_memory_range;
}
}
#endif
}
@@ -690,14 +825,12 @@ add_all_surfaces(struct anv_device *device,
isl_tiling_flags, isl_usage);
if (result != VK_SUCCESS)
return result;
check_surfaces(image, &image->planes[plane]);
if (needs_shadow) {
result = add_shadow_surface(device, image, plane, plane_format, stride,
vk_usage);
if (result != VK_SUCCESS)
return result;
check_surfaces(image, &image->planes[plane]);
}
result = add_aux_surface_if_supported(device, image, plane, plane_format,
@@ -705,9 +838,10 @@ add_all_surfaces(struct anv_device *device,
isl_extra_usage_flags);
if (result != VK_SUCCESS)
return result;
check_surfaces(image, &image->planes[plane]);
}
check_memory_bindings(device, image);
return VK_SUCCESS;
}
@@ -828,6 +962,12 @@ anv_image_create(VkDevice _device,
}
}
for (int i = 0; i < ANV_IMAGE_MEMORY_BINDING_END; ++i) {
image->bindings[i] = (struct anv_image_binding) {
.memory_range = { .binding = i },
};
}
/* In case of external format, We don't know format yet,
* so skip the rest for now.
*/
@@ -982,40 +1122,18 @@ anv_DestroyImage(VkDevice _device, VkImage _image,
return;
if (image->from_gralloc) {
assert(!image->disjoint);
assert(image->n_planes == 1);
assert(image->planes[0].address.bo != NULL);
anv_device_release_bo(device, image->planes[0].address.bo);
assert(image->planes[0].primary_surface.memory_range.binding ==
ANV_IMAGE_MEMORY_BINDING_MAIN);
assert(image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address.bo != NULL);
anv_device_release_bo(device, image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address.bo);
}
vk_object_base_finish(&image->base);
vk_free2(&device->vk.alloc, pAllocator, image);
}
static void anv_image_bind_memory_plane(struct anv_device *device,
struct anv_image *image,
uint32_t plane,
struct anv_device_memory *memory,
uint32_t memory_offset)
{
assert(!image->from_gralloc);
if (!memory) {
image->planes[plane].address = ANV_NULL_ADDRESS;
return;
}
image->planes[plane].address = (struct anv_address) {
.bo = memory->bo,
.offset = memory_offset,
};
/* If we're on a platform that uses implicit CCS and our buffer does not
* have any implicit CCS data, disable compression on that image.
*/
if (device->physical->has_implicit_ccs && !memory->bo->has_implicit_ccs)
image->planes[plane].aux_usage = ISL_AUX_USAGE_NONE;
}
/* We are binding AHardwareBuffer. Get a description, resolve the
* format and prepare anv_image properly.
*/
@@ -1118,13 +1236,14 @@ void anv_GetImageMemoryRequirements2(
plane_reqs = (const VkImagePlaneMemoryRequirementsInfo *) ext;
uint32_t plane = anv_image_aspect_to_plane(image->aspects,
plane_reqs->planeAspect);
const struct anv_image_binding *binding =
&image->bindings[ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane];
assert(image->planes[plane].offset == 0);
pMemoryRequirements->memoryRequirements.size = image->planes[plane].size;
pMemoryRequirements->memoryRequirements.alignment =
image->planes[plane].alignment;
pMemoryRequirements->memoryRequirements.memoryTypeBits = memory_types;
pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
.size = binding->memory_range.size,
.alignment = binding->memory_range.alignment,
.memoryTypeBits = memory_types,
};
break;
}
@@ -1172,9 +1291,14 @@ void anv_GetImageMemoryRequirements2(
assert(image->disjoint == (plane_reqs != NULL));
if (!image->disjoint) {
pMemoryRequirements->memoryRequirements.size = image->size;
pMemoryRequirements->memoryRequirements.alignment = image->alignment;
pMemoryRequirements->memoryRequirements.memoryTypeBits = memory_types;
const struct anv_image_binding *binding =
&image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN];
pMemoryRequirements->memoryRequirements = (VkMemoryRequirements) {
.size = binding->memory_range.size,
.alignment = binding->memory_range.alignment,
.memoryTypeBits = memory_types,
};
}
}
@@ -1207,19 +1331,39 @@ VkResult anv_BindImageMemory2(
const VkBindImageMemoryInfo *bind_info = &pBindInfos[i];
ANV_FROM_HANDLE(anv_device_memory, mem, bind_info->memory);
ANV_FROM_HANDLE(anv_image, image, bind_info->image);
bool did_bind = false;
/* Resolve will alter the image's aspects, do this first. */
if (mem && mem->ahw)
resolve_ahw_image(device, image, mem);
VkImageAspectFlags aspects = image->aspects;
vk_foreach_struct_const(s, bind_info->pNext) {
switch (s->sType) {
case VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO: {
const VkBindImagePlaneMemoryInfo *plane_info =
(const VkBindImagePlaneMemoryInfo *) s;
uint32_t plane = anv_image_aspect_to_plane(image->aspects,
plane_info->planeAspect);
aspects = plane_info->planeAspect;
/* Unlike VkImagePlaneMemoryRequirementsInfo, which requires that
* the image be disjoint (that is, multi-planar format and
* VK_IMAGE_CREATE_DISJOINT_BIT), VkBindImagePlaneMemoryInfo allows
* the image to be non-disjoint and requires only that the image
* have the DISJOINT flag. (This may be a spec bug). In this case,
* we continue as if VkImagePlaneMemoryRequirementsInfo was omitted.
*/
if (!image->disjoint) {
assert(plane == 0);
break;
}
image->bindings[ANV_IMAGE_MEMORY_BINDING_PLANE_0 + plane].address =
(struct anv_address) {
.bo = mem->bo,
.offset = bind_info->memoryOffset,
};
did_bind = true;
break;
}
case VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR: {
@@ -1232,15 +1376,16 @@ VkResult anv_BindImageMemory2(
assert(image->aspects == swapchain_image->aspects);
assert(mem == NULL);
anv_foreach_image_aspect_bit(aspect_bit, image, aspects) {
uint32_t plane =
anv_image_aspect_to_plane(image->aspects, 1UL << aspect_bit);
struct anv_device_memory mem = {
.bo = swapchain_image->planes[plane].address.bo,
};
anv_image_bind_memory_plane(device, image, plane,
&mem, bind_info->memoryOffset);
}
/* The Vulkan 1.2 spec ensures that the image is not disjoint. See
* the table of implied image creation parameters for swapchains
* <vkspec.html#swapchain-wsi-image-create-info>.
*/
assert(!swapchain_image->disjoint);
image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address =
swapchain_image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address;
did_bind = true;
break;
}
default:
@@ -1249,18 +1394,30 @@ VkResult anv_BindImageMemory2(
}
}
/* VkBindImageMemorySwapchainInfoKHR requires memory to be
* VK_NULL_HANDLE. In such case, just carry one with the next bind
* item.
*/
if (!mem)
continue;
if (!did_bind) {
assert(!image->disjoint);
anv_foreach_image_aspect_bit(aspect_bit, image, aspects) {
uint32_t plane =
anv_image_aspect_to_plane(image->aspects, 1UL << aspect_bit);
anv_image_bind_memory_plane(device, image, plane,
mem, bind_info->memoryOffset);
image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address =
(struct anv_address) {
.bo = mem->bo,
.offset = bind_info->memoryOffset,
};
did_bind = true;
}
/* On platforms that use implicit CCS, if the plane's bo lacks implicit
* CCS then disable compression on the plane.
*/
for (int p = 0; p < image->n_planes; ++p) {
enum anv_image_memory_binding binding =
image->planes[p].primary_surface.memory_range.binding;
const struct anv_bo *bo =
image->bindings[binding].address.bo;
if (bo && !bo->has_implicit_ccs &&
device->physical->has_implicit_ccs)
image->planes[p].aux_usage = ISL_AUX_USAGE_NONE;
}
}
@@ -1279,6 +1436,11 @@ void anv_GetImageSubresourceLayout(
if (subresource->aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT &&
image->drm_format_mod != DRM_FORMAT_MOD_INVALID &&
isl_drm_modifier_has_aux(image->drm_format_mod)) {
/* If the memory binding differs between primary and aux, then the
* returned offset will be incorrect.
*/
assert(image->planes[0].aux_surface.memory_range.binding ==
image->planes[0].primary_surface.memory_range.binding);
surface = &image->planes[0].aux_surface;
} else {
uint32_t plane = anv_image_aspect_to_plane(image->aspects,
@@ -1288,7 +1450,7 @@ void anv_GetImageSubresourceLayout(
assert(__builtin_popcount(subresource->aspectMask) == 1);
layout->offset = surface->offset;
layout->offset = surface->memory_range.offset;
layout->rowPitch = surface->isl.row_pitch_B;
layout->depthPitch = isl_surf_get_array_pitch(&surface->isl);
layout->arrayPitch = isl_surf_get_array_pitch(&surface->isl);
@@ -1307,7 +1469,7 @@ void anv_GetImageSubresourceLayout(
subresource->mipLevel) *
image->extent.depth;
} else {
layout->size = surface->isl.size_B;
layout->size = surface->memory_range.size;
}
}
@@ -1897,7 +2059,7 @@ anv_image_fill_surface_state(struct anv_device *device,
clear_color = &default_clear_color;
const struct anv_address address =
anv_image_address(image, plane, surface->offset);
anv_image_address(image, &surface->memory_range);
if (view_usage == ISL_SURF_USAGE_STORAGE_BIT &&
!(flags & ANV_IMAGE_VIEW_STATE_STORAGE_WRITE_ONLY) &&
@@ -1983,9 +2145,8 @@ anv_image_fill_surface_state(struct anv_device *device,
state_inout->address = anv_address_add(address, offset_B);
struct anv_address aux_address = ANV_NULL_ADDRESS;
if (aux_usage != ISL_AUX_USAGE_NONE) {
aux_address = anv_image_address(image, plane, aux_surface->offset);
}
if (aux_usage != ISL_AUX_USAGE_NONE)
aux_address = anv_image_address(image, &aux_surface->memory_range);
state_inout->aux_address = aux_address;
struct anv_address clear_address = ANV_NULL_ADDRESS;
@@ -2020,10 +2181,12 @@ anv_image_fill_surface_state(struct anv_device *device,
* are used to store other information. This should be ok, however,
* because the surface buffer addresses are always 4K page aligned.
*/
if (!anv_address_is_null(aux_address)) {
uint32_t *aux_addr_dw = state_inout->state.map +
device->isl_dev.ss.aux_addr_offset;
assert((aux_address.offset & 0xfff) == 0);
state_inout->aux_address.offset |= *aux_addr_dw & 0xfff;
}
if (device->info.gen >= 10 && clear_address.bo) {
uint32_t *clear_addr_dw = state_inout->state.map +

View File

@@ -79,7 +79,20 @@ VkResult anv_CreateDmaBufImageINTEL(
if (result != VK_SUCCESS)
goto fail_import;
VkDeviceSize aligned_image_size = align_u64(image->size, 4096);
VkImageMemoryRequirementsInfo2 mem_reqs_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
.image = image_h,
};
VkMemoryRequirements2 mem_reqs = {
.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2,
};
anv_GetImageMemoryRequirements2(_device, &mem_reqs_info, &mem_reqs);
VkDeviceSize aligned_image_size =
align_u64(mem_reqs.memoryRequirements.size,
mem_reqs.memoryRequirements.alignment);
if (mem->bo->size < aligned_image_size) {
result = vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,
@@ -90,7 +103,7 @@ VkResult anv_CreateDmaBufImageINTEL(
goto fail_import;
}
image->planes[0].address = (struct anv_address) {
image->bindings[ANV_IMAGE_MEMORY_BINDING_MAIN].address = (struct anv_address) {
.bo = mem->bo,
.offset = 0,
};

View File

@@ -3707,22 +3707,62 @@ anv_swizzle_for_render(struct isl_swizzle swizzle)
void
anv_pipeline_setup_l3_config(struct anv_pipeline *pipeline, bool needs_slm);
/**
* Describes how each part of anv_image will be bound to memory.
*/
struct anv_image_memory_range {
/**
* Disjoint bindings into which each portion of the image will be bound.
*
* Binding images to memory can be complicated and invold binding different
* portions of the image to different memory objects or regions. For most
* images, everything lives in the MAIN binding and gets bound by
* vkBindImageMemory. For disjoint multi-planar images, each plane has
* a unique, disjoint binding and gets bound by vkBindImageMemory2 with
* VkBindImagePlaneMemoryInfo. There may also exist bits of memory which are
* implicit or driver-managed and live in special-case bindings.
*/
enum anv_image_memory_binding {
/**
* Used if and only if image is not multi-planar disjoint. Bound by
* vkBindImageMemory2 without VkBindImagePlaneMemoryInfo.
*/
ANV_IMAGE_MEMORY_BINDING_MAIN,
/**
* Used if and only if image is multi-planar disjoint. Bound by
* vkBindImageMemory2 with VkBindImagePlaneMemoryInfo.
*/
ANV_IMAGE_MEMORY_BINDING_PLANE_0,
ANV_IMAGE_MEMORY_BINDING_PLANE_1,
ANV_IMAGE_MEMORY_BINDING_PLANE_2,
/** Sentinel */
ANV_IMAGE_MEMORY_BINDING_END,
} binding;
/**
* Offset is relative to the start of the binding created by
* vkBindImageMemory, not to the start of the bo.
*/
uint64_t offset;
uint64_t size;
uint32_t alignment;
};
/**
* Subsurface of an anv_image.
*/
struct anv_surface {
struct isl_surf isl;
/**
* Offset from VkImage's base address, as bound by vkBindImageMemory().
*/
uint32_t offset;
struct anv_image_memory_range memory_range;
};
static inline bool MUST_CHECK
anv_surface_is_valid(const struct anv_surface *surface)
{
return surface->isl.size_B > 0;
return surface->isl.size_B > 0 && surface->memory_range.size > 0;
}
struct anv_image {
@@ -3761,9 +3801,6 @@ struct anv_image {
*/
uint64_t drm_format_mod;
VkDeviceSize size;
uint32_t alignment;
/**
* Image has multi-planar format and was created with
* VK_IMAGE_CREATE_DISJOINT_BIT.
@@ -3779,6 +3816,23 @@ struct anv_image {
*/
bool from_gralloc;
/**
* The memory bindings created by vkCreateImage and vkBindImageMemory.
*
* vkCreateImage constructs the `memory_range` for each
* anv_image_memory_binding. After vkCreateImage, each binding is valid if
* and only if `memory_range::size > 0`.
*
* vkBindImageMemory binds each valid `memory_range` to an `address`.
* Usually, the app will provide the address via the parameters of
* vkBindImageMemory. However, special-case bindings may be bound to
* driver-private memory.
*/
struct anv_image_binding {
struct anv_image_memory_range memory_range;
struct anv_address address;
} bindings[ANV_IMAGE_MEMORY_BINDING_END];
/**
* Image subsurfaces
*
@@ -3816,15 +3870,6 @@ struct anv_image {
* -----------------------
*/
struct anv_image_plane {
/**
* Offset of the entire plane (whenever the image is disjoint this is
* set to 0).
*/
uint32_t offset;
VkDeviceSize size;
uint32_t alignment;
struct anv_surface primary_surface;
/**
@@ -3843,16 +3888,8 @@ struct anv_image {
struct anv_surface aux_surface;
/**
* Offset of the fast clear state (used to compute the
* fast_clear_state_offset of the following planes).
*/
uint32_t fast_clear_state_offset;
/**
* BO associated with this plane, set when bound.
*/
struct anv_address address;
/** Location of the fast clear state. */
struct anv_image_memory_range fast_clear_memory_range;
} planes[3];
};
@@ -3901,10 +3938,15 @@ anv_image_aux_layers(const struct anv_image * const image,
static inline struct anv_address MUST_CHECK
anv_image_address(const struct anv_image *image,
uint32_t plane, uint64_t offset)
const struct anv_image_memory_range *mem_range)
{
assert(image->planes[plane].address.offset == 0);
return anv_address_add(image->planes[plane].address, offset);
const struct anv_image_binding *binding = &image->bindings[mem_range->binding];
assert(binding->memory_range.offset == 0);
if (mem_range->size == 0)
return ANV_NULL_ADDRESS;
return anv_address_add(binding->address, mem_range->offset);
}
static inline struct anv_address
@@ -3915,8 +3957,10 @@ anv_image_get_clear_color_addr(UNUSED const struct anv_device *device,
assert(image->aspects & VK_IMAGE_ASPECT_ANY_COLOR_BIT_ANV);
uint32_t plane = anv_image_aspect_to_plane(image->aspects, aspect);
return anv_image_address(image, plane,
image->planes[plane].fast_clear_state_offset);
const struct anv_image_memory_range *mem_range =
&image->planes[plane].fast_clear_memory_range;
return anv_image_address(image, mem_range);
}
static inline struct anv_address
@@ -3958,7 +4002,7 @@ anv_image_get_compression_state_addr(const struct anv_device *device,
offset += array_layer * 4;
assert(offset < image->planes[plane].offset + image->planes[plane].size);
assert(offset < image->planes[plane].fast_clear_memory_range.size);
return anv_address_add(
anv_image_get_fast_clear_type_addr(device, image, aspect),

View File

@@ -466,7 +466,7 @@ anv_image_init_aux_tt(struct anv_cmd_buffer *cmd_buffer,
const struct anv_surface *surface = &image->planes[plane].primary_surface;
uint64_t base_address =
anv_address_physical(anv_image_address(image, plane, surface->offset));
anv_address_physical(anv_image_address(image, &surface->memory_range));
const struct isl_surf *isl_surf = &image->planes[plane].primary_surface.isl;
uint64_t format_bits = gen_aux_map_format_bits_for_isl_surf(isl_surf);
@@ -5206,7 +5206,7 @@ cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
const struct anv_surface *depth_surface =
&image->planes[depth_plane].primary_surface;
const struct anv_address depth_address =
anv_image_address(image, depth_plane, depth_surface->offset);
anv_image_address(image, &depth_surface->memory_range);
info.depth_surf = &depth_surface->isl;
@@ -5226,7 +5226,7 @@ cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
const struct anv_surface *hiz_surface =
&image->planes[depth_plane].aux_surface;
const struct anv_address hiz_address =
anv_image_address(image, depth_plane, hiz_surface->offset);
anv_image_address(image, &hiz_surface->memory_range);
info.hiz_surf = &hiz_surface->isl;
@@ -5245,7 +5245,7 @@ cmd_buffer_emit_depth_stencil(struct anv_cmd_buffer *cmd_buffer)
const struct anv_surface *stencil_surface =
&image->planes[stencil_plane].primary_surface;
const struct anv_address stencil_address =
anv_image_address(image, stencil_plane, stencil_surface->offset);
anv_image_address(image, &stencil_surface->memory_range);
info.stencil_surf = &stencil_surface->isl;