diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c index d6d36738be7..95324aecb8e 100644 --- a/src/intel/vulkan/anv_image.c +++ b/src/intel/vulkan/anv_image.c @@ -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;