diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/amd/vulkan/radv_image.c | 110 |
1 files changed, 99 insertions, 11 deletions
diff --git a/src/amd/vulkan/radv_image.c b/src/amd/vulkan/radv_image.c index 883d065af85..baf49c6b65a 100644 --- a/src/amd/vulkan/radv_image.c +++ b/src/amd/vulkan/radv_image.c @@ -244,6 +244,25 @@ radv_use_tc_compat_cmask_for_image(struct radv_device *device, return true; } +static uint32_t si_get_bo_metadata_word1(const struct radv_device *device) +{ + return (ATI_VENDOR_ID << 16) | device->physical_device->rad_info.pci_id; +} + +static bool +radv_is_valid_opaque_metadata(const struct radv_device *device, + const struct radeon_bo_metadata *md) +{ + if (md->metadata[0] != 1 || + md->metadata[1] != si_get_bo_metadata_word1(device)) + return false; + + if (md->size_metadata < 40) + return false; + + return true; +} + static void radv_patch_surface_from_metadata(struct radv_device *device, struct radeon_surf *surface, @@ -276,11 +295,79 @@ radv_patch_surface_from_metadata(struct radv_device *device, } } -static void +static VkResult +radv_patch_image_dimensions(struct radv_device *device, + struct radv_image *image, + const struct radv_image_create_info *create_info, + struct ac_surf_info *image_info) +{ + unsigned width = image->info.width; + unsigned height = image->info.height; + + /* + * minigbm sometimes allocates bigger images which is going to result in + * weird strides and other properties. Lets be lenient where possible and + * fail it on GFX10 (as we cannot cope there). + * + * Example hack: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/1457777/ + */ + if (create_info->bo_metadata && + radv_is_valid_opaque_metadata(device, create_info->bo_metadata)) { + const struct radeon_bo_metadata *md = create_info->bo_metadata; + + if (device->physical_device->rad_info.chip_class >= GFX10) { + width = G_00A004_WIDTH_LO(md->metadata[3]) + + (G_00A008_WIDTH_HI(md->metadata[4]) << 2) + 1; + height = S_00A008_HEIGHT(md->metadata[4]) + 1; + } else { + width = G_008F18_WIDTH(md->metadata[4]) + 1; + height = G_008F18_HEIGHT(md->metadata[4]) + 1; + } + } + + if (image->info.width == width && image->info.height == height) + return VK_SUCCESS; + + if (width < image->info.width || height < image->info.height) { + fprintf(stderr, + "The imported image has smaller dimensions than the internal\n" + "dimensions. Using it is going to fail badly, so we reject\n" + "this import.\n" + "(internal dimensions: %d x %d, external dimensions: %d x %d)\n", + image->info.width, image->info.height, width, height); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } else if (device->physical_device->rad_info.chip_class >= GFX10) { + fprintf(stderr, + "Tried to import an image with inconsistent width on GFX10.\n" + "As GFX10 has no separate stride fields we cannot cope with\n" + "an inconsistency in width and will fail this import.\n" + "(internal dimensions: %d x %d, external dimensions: %d x %d)\n", + image->info.width, image->info.height, width, height); + return VK_ERROR_INVALID_EXTERNAL_HANDLE; + } else { + fprintf(stderr, + "Tried to import an image with inconsistent width on pre-GFX10.\n" + "As GFX10 has no separate stride fields we cannot cope with\n" + "an inconsistency and would fail on GFX10.\n" + "(internal dimensions: %d x %d, external dimensions: %d x %d)\n", + image->info.width, image->info.height, width, height); + } + image_info->width = width; + image_info->height = height; + + return VK_SUCCESS; +} + +static VkResult radv_patch_image_from_extra_info(struct radv_device *device, struct radv_image *image, - const struct radv_image_create_info *create_info) + const struct radv_image_create_info *create_info, + struct ac_surf_info *image_info) { + VkResult result = radv_patch_image_dimensions(device, image, create_info, image_info); + if (result != VK_SUCCESS) + return result; + for (unsigned plane = 0; plane < image->plane_count; ++plane) { if (create_info->bo_metadata) { radv_patch_surface_from_metadata(device, &image->planes[plane].surface, @@ -294,6 +381,7 @@ radv_patch_image_from_extra_info(struct radv_device *device, image->info.surf_index = NULL; } } + return VK_SUCCESS; } static int @@ -365,11 +453,6 @@ radv_init_surface(struct radv_device *device, return 0; } -static uint32_t si_get_bo_metadata_word1(struct radv_device *device) -{ - return (ATI_VENDOR_ID << 16) | device->physical_device->rad_info.pci_id; -} - static inline unsigned si_tile_mode_index(const struct radv_image_plane *plane, unsigned level, bool stencil) { @@ -1263,7 +1346,7 @@ static void radv_image_disable_htile(struct radv_image *image) image->planes[i].surface.htile_size = 0; } -static void +static VkResult radv_image_create_layout(struct radv_device *device, const struct radv_image_create_info *create_info, struct radv_image *image) @@ -1271,12 +1354,15 @@ radv_image_create_layout(struct radv_device *device, /* Check that we did not initialize things earlier */ assert(!image->planes[0].surface.surf_size); - radv_patch_image_from_extra_info(device, image, create_info); + struct ac_surf_info image_info = image->info; + VkResult result = radv_patch_image_from_extra_info(device, image, create_info, &image_info); + if (result != VK_SUCCESS) + return result; image->size = 0; image->alignment = 1; for (unsigned plane = 0; plane < image->plane_count; ++plane) { - struct ac_surf_info info = image->info; + struct ac_surf_info info = image_info; if (plane) { const struct vk_format_description *desc = vk_format_description(image->vk_format); @@ -1337,6 +1423,7 @@ radv_image_create_layout(struct radv_device *device, } assert(image->planes[0].surface.surf_size); + return VK_SUCCESS; } VkResult @@ -1401,7 +1488,8 @@ radv_image_create(VkDevice _device, radv_init_surface(device, image, &image->planes[plane].surface, plane, pCreateInfo); } - radv_image_create_layout(device, create_info, image); + ASSERTED VkResult result = radv_image_create_layout(device, create_info, image); + assert(result == VK_SUCCESS); if (image->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) { image->alignment = MAX2(image->alignment, 4096); |