anv/image: Check that anv_image is compatible with its modifier

At end of image creation, check for incompatibilities that
vkGetPhysicalDeviceImageFormatProperties2() has difficulty predicting.

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/1466>
This commit is contained in:
Chad Versace 2021-03-21 17:14:12 -07:00 committed by Marge Bot
parent 96f4568b63
commit a7a59d8dd1
1 changed files with 86 additions and 0 deletions

View File

@ -787,6 +787,88 @@ check_memory_bindings(const struct anv_device *device,
#endif
}
/**
* Check that the fully-initialized anv_image is compatible with its DRM format
* modifier.
*
* Checking compatibility at the end of image creation is prudent, not
* superfluous, because usage of modifiers triggers numerous special cases
* throughout queries and image creation, and because
* vkGetPhysicalDeviceImageFormatProperties2 has difficulty detecting all
* incompatibilities.
*
* Return VK_ERROR_UNKNOWN if the incompatibility is difficult to detect in
* vkGetPhysicalDeviceImageFormatProperties2. Otherwise, assert fail.
*
* Ideally, if vkGetPhysicalDeviceImageFormatProperties2() succeeds with a given
* modifier, then vkCreateImage() produces an image that is compatible with the
* modifier. However, it is difficult to reconcile the two functions to agree
* due to their complexity. For example, isl_surf_get_ccs_surf() may
* unexpectedly fail in vkCreateImage(), eliminating the image's aux surface
* even when the modifier requires one. (Maybe we should reconcile the two
* functions despite the difficulty).
*/
static VkResult MUST_CHECK
check_drm_format_mod(const struct anv_device *device,
const struct anv_image *image)
{
/* Image must have a modifier if and only if it has modifier tiling. */
assert((image->drm_format_mod != DRM_FORMAT_MOD_INVALID) ==
(image->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT));
if (image->drm_format_mod == DRM_FORMAT_MOD_INVALID)
return VK_SUCCESS;
const struct isl_drm_modifier_info *isl_mod_info =
isl_drm_modifier_get_info(image->drm_format_mod);
/* Driver must support the modifier. */
assert(isl_drm_modifier_get_score(&device->info, isl_mod_info->modifier));
/* Enforced by us, not the Vulkan spec. */
assert(image->type == VK_IMAGE_TYPE_2D);
assert(!(image->aspects & VK_IMAGE_ASPECT_DEPTH_BIT));
assert(!(image->aspects & VK_IMAGE_ASPECT_STENCIL_BIT));
assert(image->levels == 1);
assert(image->array_size == 1);
assert(image->samples == 1);
/* FINISHME: Support multi-planar formats with modifiers */
assert(image->n_planes == 1);
assert(image->aspects == VK_IMAGE_ASPECT_COLOR_BIT);
for (int i = 0; i < image->n_planes; ++i) {
const struct anv_image_plane *plane = &image->planes[i];
ASSERTED const struct anv_format_plane *plane_format =
&image->format->planes[i];
ASSERTED const struct isl_format_layout *isl_layout =
isl_format_get_layout(plane_format->isl_format);
/* Enforced by us, not the Vulkan spec. */
assert(isl_layout->txc == ISL_TXC_NONE);
assert(isl_layout->colorspace == ISL_COLORSPACE_LINEAR ||
isl_layout->colorspace == ISL_COLORSPACE_SRGB);
assert(!anv_surface_is_valid(&plane->shadow_surface));
if (isl_mod_info->aux_usage != ISL_AUX_USAGE_NONE) {
/* Reject DISJOINT for consistency with the GL driver. */
assert(!image->disjoint);
/* The modifier's required aux usage mandates the image's aux usage.
* The inverse, however, does not hold; if the modifier has no aux
* usage, then we may enable a private aux surface.
*/
if (plane->aux_usage != isl_mod_info->aux_usage) {
return vk_errorf(device, &image->base, VK_ERROR_UNKNOWN,
"image with modifier unexpectedly has wrong aux "
"usage");
}
}
}
return VK_SUCCESS;
}
static VkResult
add_all_surfaces(struct anv_device *device,
struct anv_image *image,
@ -991,6 +1073,10 @@ anv_image_create(VkDevice _device,
if (r != VK_SUCCESS)
goto fail;
r = check_drm_format_mod(device, image);
if (r != VK_SUCCESS)
goto fail;
*pImage = anv_image_to_handle(image);
return VK_SUCCESS;