radv: Add image layout with drm format modifiers.
authorBas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
Tue, 17 Nov 2020 04:10:20 +0000 (05:10 +0100)
committerMarge Bot <eric+marge@anholt.net>
Tue, 2 Feb 2021 00:43:56 +0000 (00:43 +0000)
Half of it is passing the right modifier to ac_surface, the other half
is applying the offset/strides.

Reviewed-By: Chad Versace <chad@kiwitree.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/7667>

src/amd/vulkan/radv_device.c
src/amd/vulkan/radv_image.c
src/amd/vulkan/radv_private.h

index a7b2cdb..fad1f46 100644 (file)
@@ -5323,7 +5323,8 @@ static VkResult radv_alloc_memory(struct radv_device *device,
                        /* This gives a basic ability to import radeonsi images
                         * that don't have DCC. This is not guaranteed by any
                         * spec and can be removed after we support modifiers. */
-                       result = radv_image_create_layout(device, create_info, mem->image);
+                       result = radv_image_create_layout(device, create_info, NULL,
+                                                         mem->image);
                        if (result != VK_SUCCESS) {
                                device->ws->buffer_destroy(mem->bo);
                                goto fail;
index 60934cb..6a0c667 100644 (file)
@@ -1349,6 +1349,7 @@ radv_image_reset_layout(struct radv_image *image)
 VkResult
 radv_image_create_layout(struct radv_device *device,
                          struct radv_image_create_info create_info,
+                         const struct VkImageDrmFormatModifierExplicitCreateInfoEXT *mod_info,
                          struct radv_image *image)
 {
        /* Clear the pCreateInfo pointer so we catch issues in the delayed case when we test in the
@@ -1360,11 +1361,14 @@ radv_image_create_layout(struct radv_device *device,
        if (result != VK_SUCCESS)
                return result;
 
+       assert(!mod_info || mod_info->drmFormatModifierPlaneCount == image->plane_count);
+
        radv_image_reset_layout(image);
 
        for (unsigned plane = 0; plane < image->plane_count; ++plane) {
                struct ac_surf_info info = image_info;
                uint64_t offset;
+               unsigned stride;
 
                if (plane) {
                        const struct vk_format_description *desc = vk_format_description(image->vk_format);
@@ -1383,15 +1387,42 @@ radv_image_create_layout(struct radv_device *device,
 
                device->ws->surface_init(device->ws, &info, &image->planes[plane].surface);
 
-               if (!create_info.no_metadata_planes && image->plane_count == 1)
+               if (!create_info.no_metadata_planes && image->plane_count == 1 &&
+                   !mod_info)
                        radv_image_alloc_single_sample_cmask(device, image, &image->planes[plane].surface);
 
-               offset = align(image->size, image->planes[plane].surface.alignment);
-               ac_surface_override_offset_stride(&device->physical_device->rad_info,
-                                                 &image->planes[plane].surface,
-                                                 image->info.levels,
-                                                 offset,
-                                                 0);
+               if (mod_info) {
+                       if (mod_info->pPlaneLayouts[plane].rowPitch % image->planes[plane].surface.bpe ||
+                           !mod_info->pPlaneLayouts[plane].rowPitch)
+                               return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
+
+                       offset = mod_info->pPlaneLayouts[plane].offset;
+                       stride  = mod_info->pPlaneLayouts[plane].rowPitch / image->planes[plane].surface.bpe;
+               } else {
+                       offset = align(image->size, image->planes[plane].surface.alignment);
+                       stride = 0;  /* 0 means no override */
+               }
+
+               if (!ac_surface_override_offset_stride(&device->physical_device->rad_info,
+                                                     &image->planes[plane].surface,
+                                                     image->info.levels,
+                                                     offset,
+                                                     stride))
+                       return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
+
+               /* Validate DCC offsets in modifier layout. */
+               if (image->plane_count == 1 && mod_info) {
+                       unsigned mem_planes = ac_surface_get_nplanes(&image->planes[plane].surface);
+                       if (mod_info->drmFormatModifierPlaneCount != mem_planes)
+                               return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
+
+                       for (unsigned i = 1; i < mem_planes; ++i) {
+                               if (ac_surface_get_plane_offset(device->physical_device->rad_info.chip_class,
+                                                               &image->planes[plane].surface, i, 0) !=
+                                   mod_info->pPlaneLayouts[i].offset)
+                                       return VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT;
+                       }
+               }
 
                image->size = MAX2(image->size, offset + image->planes[plane].surface.total_size);
                image->alignment = MAX2(image->alignment, image->planes[plane].surface.alignment);
@@ -1405,6 +1436,8 @@ radv_image_create_layout(struct radv_device *device,
        radv_image_alloc_values(device, image);
 
        assert(image->planes[0].surface.surf_size);
+       assert(ac_modifier_has_dcc(image->planes[0].surface.modifier) ==
+              radv_image_has_dcc(image));
        return VK_SUCCESS;
 }
 
@@ -1482,6 +1515,46 @@ radv_image_can_fast_clear(const struct radv_device *device,
        return true;
 }
 
+static uint64_t
+radv_select_modifier(const struct radv_device *dev,
+                     VkFormat format,
+                     const struct VkImageDrmFormatModifierListCreateInfoEXT *mod_list)
+{
+       const struct radv_physical_device *pdev = dev->physical_device;
+       unsigned mod_count;
+
+       assert(mod_list->drmFormatModifierCount);
+
+       /* We can allow everything here as it does not affect order and the application
+        * is only allowed to specify modifiers that we support. */
+       const struct ac_modifier_options modifier_options = {
+               .dcc = true,
+               .dcc_retile = true,
+       };
+
+       ac_get_supported_modifiers(&pdev->rad_info, &modifier_options,
+                                  vk_format_to_pipe_format(format), &mod_count, NULL);
+
+       uint64_t *mods = calloc(mod_count, sizeof(*mods));
+
+       /* If allocations fail, fall back to a dumber solution. */
+       if (!mods)
+               return mod_list->pDrmFormatModifiers[0];
+
+       ac_get_supported_modifiers(&pdev->rad_info, &modifier_options,
+                                  vk_format_to_pipe_format(format), &mod_count, mods);
+
+       for (unsigned i = 0; i < mod_count; ++i) {
+               for (uint32_t j = 0; j < mod_list->drmFormatModifierCount; ++j) {
+                       if (mods[i] == mod_list->pDrmFormatModifiers[j]) {
+                               free(mods);
+                               return mod_list->pDrmFormatModifiers[j];
+                       }
+               }
+       }
+       unreachable("App specified an invalid modifier");
+}
+
 VkResult
 radv_image_create(VkDevice _device,
                  const struct radv_image_create_info *create_info,
@@ -1490,9 +1563,14 @@ radv_image_create(VkDevice _device,
 {
        RADV_FROM_HANDLE(radv_device, device, _device);
        const VkImageCreateInfo *pCreateInfo = create_info->vk_info;
+       uint64_t modifier = DRM_FORMAT_MOD_INVALID;
        struct radv_image *image = NULL;
        VkFormat format = radv_select_android_external_format(pCreateInfo->pNext,
                                                              pCreateInfo->format);
+       const struct VkImageDrmFormatModifierListCreateInfoEXT *mod_list =
+               vk_find_struct_const(pCreateInfo->pNext, IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
+       const struct VkImageDrmFormatModifierExplicitCreateInfoEXT *explicit_mod =
+               vk_find_struct_const(pCreateInfo->pNext, IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
        assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
 
        const unsigned plane_count = vk_format_get_plane_count(format);
@@ -1544,14 +1622,20 @@ radv_image_create(VkDevice _device,
 
        image->shareable = external_info;
        if (!vk_format_is_depth_or_stencil(format) && !image->shareable &&
-           !(image->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT)) {
+           !(image->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) &&
+           pCreateInfo->tiling != VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
                image->info.surf_index = &device->image_mrt_offset_counter;
        }
 
+       if (mod_list)
+               modifier = radv_select_modifier(device, format, mod_list);
+       else if (explicit_mod)
+               modifier = explicit_mod->drmFormatModifier;
+
        for (unsigned plane = 0; plane < image->plane_count; ++plane) {
                image->planes[plane].surface.flags =
                        radv_get_surface_flags(device, image, plane, pCreateInfo, format);
-               image->planes[plane].surface.modifier = DRM_FORMAT_MOD_INVALID;
+               image->planes[plane].surface.modifier = modifier;
        }
 
        bool delay_layout = external_info &&
@@ -1563,7 +1647,7 @@ radv_image_create(VkDevice _device,
                return VK_SUCCESS;
        }
 
-       ASSERTED VkResult result = radv_image_create_layout(device, *create_info, image);
+       ASSERTED VkResult result = radv_image_create_layout(device, *create_info, explicit_mod, image);
        assert(result == VK_SUCCESS);
 
        if (image->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
index f28e616..56c281b 100644 (file)
@@ -2175,6 +2175,7 @@ struct radv_image_create_info {
 VkResult
 radv_image_create_layout(struct radv_device *device,
                          struct radv_image_create_info create_info,
+                         const struct VkImageDrmFormatModifierExplicitCreateInfoEXT *mod_info,
                          struct radv_image *image);
 
 VkResult radv_image_create(VkDevice _device,