17ec681f3Smrg/*
27ec681f3Smrg * Copyright © 2021 Collabora Ltd.
37ec681f3Smrg *
47ec681f3Smrg * Derived from tu_image.c which is:
57ec681f3Smrg * Copyright © 2016 Red Hat.
67ec681f3Smrg * Copyright © 2016 Bas Nieuwenhuizen
77ec681f3Smrg * Copyright © 2015 Intel Corporation
87ec681f3Smrg *
97ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
107ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
117ec681f3Smrg * to deal in the Software without restriction, including without limitation
127ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
137ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
147ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
157ec681f3Smrg *
167ec681f3Smrg * The above copyright notice and this permission notice (including the next
177ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
187ec681f3Smrg * Software.
197ec681f3Smrg *
207ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
217ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
227ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
237ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
247ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
257ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
267ec681f3Smrg * DEALINGS IN THE SOFTWARE.
277ec681f3Smrg */
287ec681f3Smrg
297ec681f3Smrg#include "panvk_private.h"
307ec681f3Smrg#include "panfrost-quirks.h"
317ec681f3Smrg
327ec681f3Smrg#include "util/debug.h"
337ec681f3Smrg#include "util/u_atomic.h"
347ec681f3Smrg#include "vk_format.h"
357ec681f3Smrg#include "vk_object.h"
367ec681f3Smrg#include "vk_util.h"
377ec681f3Smrg#include "drm-uapi/drm_fourcc.h"
387ec681f3Smrg
397ec681f3Smrgunsigned
407ec681f3Smrgpanvk_image_get_plane_size(const struct panvk_image *image, unsigned plane)
417ec681f3Smrg{
427ec681f3Smrg   assert(!plane);
437ec681f3Smrg   return image->pimage.layout.data_size;
447ec681f3Smrg}
457ec681f3Smrg
467ec681f3Smrgunsigned
477ec681f3Smrgpanvk_image_get_total_size(const struct panvk_image *image)
487ec681f3Smrg{
497ec681f3Smrg   assert(util_format_get_num_planes(image->pimage.layout.format) == 1);
507ec681f3Smrg   return image->pimage.layout.data_size;
517ec681f3Smrg}
527ec681f3Smrg
537ec681f3Smrgstatic enum mali_texture_dimension
547ec681f3Smrgpanvk_image_type_to_mali_tex_dim(VkImageType type)
557ec681f3Smrg{
567ec681f3Smrg   switch (type) {
577ec681f3Smrg   case VK_IMAGE_TYPE_1D: return MALI_TEXTURE_DIMENSION_1D;
587ec681f3Smrg   case VK_IMAGE_TYPE_2D: return MALI_TEXTURE_DIMENSION_2D;
597ec681f3Smrg   case VK_IMAGE_TYPE_3D: return MALI_TEXTURE_DIMENSION_3D;
607ec681f3Smrg   default: unreachable("Invalid image type");
617ec681f3Smrg   }
627ec681f3Smrg}
637ec681f3Smrg
647ec681f3Smrgstatic VkResult
657ec681f3Smrgpanvk_image_create(VkDevice _device,
667ec681f3Smrg                   const VkImageCreateInfo *pCreateInfo,
677ec681f3Smrg                   const VkAllocationCallbacks *alloc,
687ec681f3Smrg                   VkImage *pImage,
697ec681f3Smrg                   uint64_t modifier,
707ec681f3Smrg                   const VkSubresourceLayout *plane_layouts)
717ec681f3Smrg{
727ec681f3Smrg   VK_FROM_HANDLE(panvk_device, device, _device);
737ec681f3Smrg   const struct panfrost_device *pdev = &device->physical_device->pdev;
747ec681f3Smrg   struct panvk_image *image = NULL;
757ec681f3Smrg   assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO);
767ec681f3Smrg
777ec681f3Smrg   assert(pCreateInfo->mipLevels > 0);
787ec681f3Smrg   assert(pCreateInfo->arrayLayers > 0);
797ec681f3Smrg   assert(pCreateInfo->samples > 0);
807ec681f3Smrg   assert(pCreateInfo->extent.width > 0);
817ec681f3Smrg   assert(pCreateInfo->extent.height > 0);
827ec681f3Smrg   assert(pCreateInfo->extent.depth > 0);
837ec681f3Smrg
847ec681f3Smrg   image = vk_object_zalloc(&device->vk, alloc, sizeof(*image),
857ec681f3Smrg                            VK_OBJECT_TYPE_IMAGE);
867ec681f3Smrg   if (!image)
877ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
887ec681f3Smrg
897ec681f3Smrg   image->type = pCreateInfo->imageType;
907ec681f3Smrg
917ec681f3Smrg   image->vk_format = pCreateInfo->format;
927ec681f3Smrg   image->tiling = pCreateInfo->tiling;
937ec681f3Smrg   image->usage = pCreateInfo->usage;
947ec681f3Smrg   image->flags = pCreateInfo->flags;
957ec681f3Smrg   image->extent = pCreateInfo->extent;
967ec681f3Smrg   pan_image_layout_init(pdev, &image->pimage.layout, modifier,
977ec681f3Smrg                         vk_format_to_pipe_format(pCreateInfo->format),
987ec681f3Smrg                         panvk_image_type_to_mali_tex_dim(pCreateInfo->imageType),
997ec681f3Smrg                         pCreateInfo->extent.width, pCreateInfo->extent.height,
1007ec681f3Smrg                         pCreateInfo->extent.depth, pCreateInfo->arrayLayers,
1017ec681f3Smrg                         pCreateInfo->samples, pCreateInfo->mipLevels,
1027ec681f3Smrg                         PAN_IMAGE_CRC_NONE, NULL);
1037ec681f3Smrg
1047ec681f3Smrg   image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE;
1057ec681f3Smrg   if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) {
1067ec681f3Smrg      for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) {
1077ec681f3Smrg         if (pCreateInfo->pQueueFamilyIndices[i] == VK_QUEUE_FAMILY_EXTERNAL)
1087ec681f3Smrg            image->queue_family_mask |= (1u << PANVK_MAX_QUEUE_FAMILIES) - 1u;
1097ec681f3Smrg         else
1107ec681f3Smrg            image->queue_family_mask |= 1u << pCreateInfo->pQueueFamilyIndices[i];
1117ec681f3Smrg       }
1127ec681f3Smrg   }
1137ec681f3Smrg
1147ec681f3Smrg   if (vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO))
1157ec681f3Smrg      image->shareable = true;
1167ec681f3Smrg
1177ec681f3Smrg   *pImage = panvk_image_to_handle(image);
1187ec681f3Smrg   return VK_SUCCESS;
1197ec681f3Smrg}
1207ec681f3Smrg
1217ec681f3Smrgstatic uint64_t
1227ec681f3Smrgpanvk_image_select_mod(VkDevice _device,
1237ec681f3Smrg                       const VkImageCreateInfo *pCreateInfo,
1247ec681f3Smrg                       const VkSubresourceLayout **plane_layouts)
1257ec681f3Smrg{
1267ec681f3Smrg   VK_FROM_HANDLE(panvk_device, device, _device);
1277ec681f3Smrg   const struct panfrost_device *pdev = &device->physical_device->pdev;
1287ec681f3Smrg   enum pipe_format fmt = vk_format_to_pipe_format(pCreateInfo->format);
1297ec681f3Smrg   bool noafbc = !(device->physical_device->instance->debug_flags & PANVK_DEBUG_AFBC);
1307ec681f3Smrg   bool linear = device->physical_device->instance->debug_flags & PANVK_DEBUG_LINEAR;
1317ec681f3Smrg
1327ec681f3Smrg   *plane_layouts = NULL;
1337ec681f3Smrg
1347ec681f3Smrg   if (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR)
1357ec681f3Smrg      return DRM_FORMAT_MOD_LINEAR;
1367ec681f3Smrg
1377ec681f3Smrg   if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
1387ec681f3Smrg      const VkImageDrmFormatModifierListCreateInfoEXT *mod_info =
1397ec681f3Smrg         vk_find_struct_const(pCreateInfo->pNext,
1407ec681f3Smrg                              IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
1417ec681f3Smrg      const VkImageDrmFormatModifierExplicitCreateInfoEXT *drm_explicit_info =
1427ec681f3Smrg         vk_find_struct_const(pCreateInfo->pNext,
1437ec681f3Smrg                              IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
1447ec681f3Smrg
1457ec681f3Smrg      assert(mod_info || drm_explicit_info);
1467ec681f3Smrg
1477ec681f3Smrg      uint64_t modifier;
1487ec681f3Smrg
1497ec681f3Smrg      if (mod_info) {
1507ec681f3Smrg         modifier = DRM_FORMAT_MOD_LINEAR;
1517ec681f3Smrg         for (unsigned i = 0; i < mod_info->drmFormatModifierCount; i++) {
1527ec681f3Smrg            if (drm_is_afbc(mod_info->pDrmFormatModifiers[i]) && !noafbc) {
1537ec681f3Smrg               modifier = mod_info->pDrmFormatModifiers[i];
1547ec681f3Smrg               break;
1557ec681f3Smrg            }
1567ec681f3Smrg         }
1577ec681f3Smrg      } else {
1587ec681f3Smrg         modifier = drm_explicit_info->drmFormatModifier;
1597ec681f3Smrg         assert(modifier == DRM_FORMAT_MOD_LINEAR ||
1607ec681f3Smrg                modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
1617ec681f3Smrg                (drm_is_afbc(modifier) && !noafbc));
1627ec681f3Smrg         *plane_layouts = drm_explicit_info->pPlaneLayouts;
1637ec681f3Smrg      }
1647ec681f3Smrg
1657ec681f3Smrg      return modifier;
1667ec681f3Smrg   }
1677ec681f3Smrg
1687ec681f3Smrg   const struct wsi_image_create_info *wsi_info =
1697ec681f3Smrg      vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA);
1707ec681f3Smrg   if (wsi_info && wsi_info->scanout)
1717ec681f3Smrg      return DRM_FORMAT_MOD_LINEAR;
1727ec681f3Smrg
1737ec681f3Smrg   assert(pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL);
1747ec681f3Smrg
1757ec681f3Smrg   if (linear)
1767ec681f3Smrg      return DRM_FORMAT_MOD_LINEAR;
1777ec681f3Smrg
1787ec681f3Smrg   /* Image store don't work on AFBC images */
1797ec681f3Smrg   if (pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT)
1807ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
1817ec681f3Smrg
1827ec681f3Smrg   /* AFBC does not support layered multisampling */
1837ec681f3Smrg   if (pCreateInfo->samples > 1)
1847ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
1857ec681f3Smrg
1867ec681f3Smrg   if (!pdev->has_afbc)
1877ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
1887ec681f3Smrg
1897ec681f3Smrg   /* Only a small selection of formats are AFBC'able */
1907ec681f3Smrg   if (!panfrost_format_supports_afbc(pdev, fmt))
1917ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
1927ec681f3Smrg
1937ec681f3Smrg   /* 3D AFBC is only supported on Bifrost v7+. It's supposed to
1947ec681f3Smrg    * be supported on Midgard but it doesn't seem to work.
1957ec681f3Smrg    */
1967ec681f3Smrg   if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D && pdev->arch < 7)
1977ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
1987ec681f3Smrg
1997ec681f3Smrg   /* For one tile, AFBC is a loss compared to u-interleaved */
2007ec681f3Smrg   if (pCreateInfo->extent.width <= 16 && pCreateInfo->extent.height <= 16)
2017ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
2027ec681f3Smrg
2037ec681f3Smrg   if (noafbc)
2047ec681f3Smrg      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
2057ec681f3Smrg
2067ec681f3Smrg   uint64_t afbc_type = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
2077ec681f3Smrg                        AFBC_FORMAT_MOD_SPARSE;
2087ec681f3Smrg
2097ec681f3Smrg   if (panfrost_afbc_can_ytr(fmt))
2107ec681f3Smrg      afbc_type |= AFBC_FORMAT_MOD_YTR;
2117ec681f3Smrg
2127ec681f3Smrg   return DRM_FORMAT_MOD_ARM_AFBC(afbc_type);
2137ec681f3Smrg}
2147ec681f3Smrg
2157ec681f3SmrgVkResult
2167ec681f3Smrgpanvk_CreateImage(VkDevice device,
2177ec681f3Smrg                  const VkImageCreateInfo *pCreateInfo,
2187ec681f3Smrg                  const VkAllocationCallbacks *pAllocator,
2197ec681f3Smrg                  VkImage *pImage)
2207ec681f3Smrg{
2217ec681f3Smrg   const VkSubresourceLayout *plane_layouts;
2227ec681f3Smrg   uint64_t modifier = panvk_image_select_mod(device, pCreateInfo, &plane_layouts);
2237ec681f3Smrg
2247ec681f3Smrg   return panvk_image_create(device, pCreateInfo, pAllocator, pImage, modifier, plane_layouts);
2257ec681f3Smrg}
2267ec681f3Smrg
2277ec681f3Smrgvoid
2287ec681f3Smrgpanvk_DestroyImage(VkDevice _device,
2297ec681f3Smrg                   VkImage _image,
2307ec681f3Smrg                   const VkAllocationCallbacks *pAllocator)
2317ec681f3Smrg{
2327ec681f3Smrg   VK_FROM_HANDLE(panvk_device, device, _device);
2337ec681f3Smrg   VK_FROM_HANDLE(panvk_image, image, _image);
2347ec681f3Smrg
2357ec681f3Smrg   if (!image)
2367ec681f3Smrg      return;
2377ec681f3Smrg
2387ec681f3Smrg   vk_object_free(&device->vk, pAllocator, image);
2397ec681f3Smrg}
2407ec681f3Smrg
2417ec681f3Smrgstatic unsigned
2427ec681f3Smrgpanvk_plane_index(VkFormat format, VkImageAspectFlags aspect_mask)
2437ec681f3Smrg{
2447ec681f3Smrg   switch (aspect_mask) {
2457ec681f3Smrg   default:
2467ec681f3Smrg      return 0;
2477ec681f3Smrg   case VK_IMAGE_ASPECT_PLANE_1_BIT:
2487ec681f3Smrg      return 1;
2497ec681f3Smrg   case VK_IMAGE_ASPECT_PLANE_2_BIT:
2507ec681f3Smrg      return 2;
2517ec681f3Smrg   case VK_IMAGE_ASPECT_STENCIL_BIT:
2527ec681f3Smrg      return format == VK_FORMAT_D32_SFLOAT_S8_UINT;
2537ec681f3Smrg   }
2547ec681f3Smrg}
2557ec681f3Smrg
2567ec681f3Smrgvoid
2577ec681f3Smrgpanvk_GetImageSubresourceLayout(VkDevice _device,
2587ec681f3Smrg                                VkImage _image,
2597ec681f3Smrg                                const VkImageSubresource *pSubresource,
2607ec681f3Smrg                                VkSubresourceLayout *pLayout)
2617ec681f3Smrg{
2627ec681f3Smrg   VK_FROM_HANDLE(panvk_image, image, _image);
2637ec681f3Smrg
2647ec681f3Smrg   unsigned plane = panvk_plane_index(image->vk_format, pSubresource->aspectMask);
2657ec681f3Smrg   assert(plane < PANVK_MAX_PLANES);
2667ec681f3Smrg
2677ec681f3Smrg   const struct pan_image_slice_layout *slice_layout =
2687ec681f3Smrg      &image->pimage.layout.slices[pSubresource->mipLevel];
2697ec681f3Smrg
2707ec681f3Smrg   pLayout->offset = slice_layout->offset +
2717ec681f3Smrg                     (pSubresource->arrayLayer *
2727ec681f3Smrg                      image->pimage.layout.array_stride);
2737ec681f3Smrg   pLayout->size = slice_layout->size;
2747ec681f3Smrg   pLayout->rowPitch = slice_layout->line_stride;
2757ec681f3Smrg   pLayout->arrayPitch = image->pimage.layout.array_stride;
2767ec681f3Smrg   pLayout->depthPitch = slice_layout->surface_stride;
2777ec681f3Smrg}
2787ec681f3Smrg
2797ec681f3Smrgvoid
2807ec681f3Smrgpanvk_DestroyImageView(VkDevice _device,
2817ec681f3Smrg                       VkImageView _view,
2827ec681f3Smrg                       const VkAllocationCallbacks *pAllocator)
2837ec681f3Smrg{
2847ec681f3Smrg   VK_FROM_HANDLE(panvk_device, device, _device);
2857ec681f3Smrg   VK_FROM_HANDLE(panvk_image_view, view, _view);
2867ec681f3Smrg
2877ec681f3Smrg   if (!view)
2887ec681f3Smrg      return;
2897ec681f3Smrg
2907ec681f3Smrg   panfrost_bo_unreference(view->bo);
2917ec681f3Smrg   vk_object_free(&device->vk, pAllocator, view);
2927ec681f3Smrg}
2937ec681f3Smrg
2947ec681f3SmrgVkResult
2957ec681f3Smrgpanvk_CreateBufferView(VkDevice _device,
2967ec681f3Smrg                       const VkBufferViewCreateInfo *pCreateInfo,
2977ec681f3Smrg                       const VkAllocationCallbacks *pAllocator,
2987ec681f3Smrg                       VkBufferView *pView)
2997ec681f3Smrg{
3007ec681f3Smrg   panvk_stub();
3017ec681f3Smrg   return VK_SUCCESS;
3027ec681f3Smrg}
3037ec681f3Smrg
3047ec681f3Smrgvoid
3057ec681f3Smrgpanvk_DestroyBufferView(VkDevice _device,
3067ec681f3Smrg                        VkBufferView bufferView,
3077ec681f3Smrg                        const VkAllocationCallbacks *pAllocator)
3087ec681f3Smrg{
3097ec681f3Smrg   panvk_stub();
3107ec681f3Smrg}
3117ec681f3Smrg
3127ec681f3SmrgVkResult
3137ec681f3Smrgpanvk_GetImageDrmFormatModifierPropertiesEXT(VkDevice device,
3147ec681f3Smrg                                             VkImage _image,
3157ec681f3Smrg                                             VkImageDrmFormatModifierPropertiesEXT *pProperties)
3167ec681f3Smrg{
3177ec681f3Smrg   VK_FROM_HANDLE(panvk_image, image, _image);
3187ec681f3Smrg
3197ec681f3Smrg   assert(pProperties->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT);
3207ec681f3Smrg
3217ec681f3Smrg   pProperties->drmFormatModifier = image->pimage.layout.modifier;
3227ec681f3Smrg   return VK_SUCCESS;
3237ec681f3Smrg}
324