1/*
2 * Copyright © 2021 Collabora Ltd.
3 *
4 * Derived from tu_image.c which is:
5 * Copyright © 2016 Red Hat.
6 * Copyright © 2016 Bas Nieuwenhuizen
7 * Copyright © 2015 Intel Corporation
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice (including the next
17 * paragraph) shall be included in all copies or substantial portions of the
18 * Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 */
28
29#include "panvk_private.h"
30
31#include "util/debug.h"
32#include "util/u_atomic.h"
33#include "vk_format.h"
34#include "vk_object.h"
35#include "vk_util.h"
36#include "drm-uapi/drm_fourcc.h"
37
38unsigned
39panvk_image_get_plane_size(const struct panvk_image *image, unsigned plane)
40{
41   assert(!plane);
42   return image->pimage.layout.data_size;
43}
44
45unsigned
46panvk_image_get_total_size(const struct panvk_image *image)
47{
48   assert(util_format_get_num_planes(image->pimage.layout.format) == 1);
49   return image->pimage.layout.data_size;
50}
51
52static enum mali_texture_dimension
53panvk_image_type_to_mali_tex_dim(VkImageType type)
54{
55   switch (type) {
56   case VK_IMAGE_TYPE_1D: return MALI_TEXTURE_DIMENSION_1D;
57   case VK_IMAGE_TYPE_2D: return MALI_TEXTURE_DIMENSION_2D;
58   case VK_IMAGE_TYPE_3D: return MALI_TEXTURE_DIMENSION_3D;
59   default: unreachable("Invalid image type");
60   }
61}
62
63static VkResult
64panvk_image_create(VkDevice _device,
65                   const VkImageCreateInfo *pCreateInfo,
66                   const VkAllocationCallbacks *alloc,
67                   VkImage *pImage,
68                   uint64_t modifier,
69                   const VkSubresourceLayout *plane_layouts)
70{
71   VK_FROM_HANDLE(panvk_device, device, _device);
72   struct panvk_image *image = NULL;
73
74   image = vk_image_create(&device->vk, pCreateInfo, alloc, sizeof(*image));
75   if (!image)
76      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
77
78   image->pimage.layout = (struct pan_image_layout) {
79      .modifier = modifier,
80      .format = vk_format_to_pipe_format(image->vk.format),
81      .dim = panvk_image_type_to_mali_tex_dim(image->vk.image_type),
82      .width = image->vk.extent.width,
83      .height = image->vk.extent.height,
84      .depth = image->vk.extent.depth,
85      .array_size = image->vk.array_layers,
86      .nr_samples = image->vk.samples,
87      .nr_slices = image->vk.mip_levels,
88      .crc_mode = PAN_IMAGE_CRC_NONE
89   };
90
91   pan_image_layout_init(&image->pimage.layout, NULL);
92
93   *pImage = panvk_image_to_handle(image);
94   return VK_SUCCESS;
95}
96
97static uint64_t
98panvk_image_select_mod(VkDevice _device,
99                       const VkImageCreateInfo *pCreateInfo,
100                       const VkSubresourceLayout **plane_layouts)
101{
102   VK_FROM_HANDLE(panvk_device, device, _device);
103   const struct panfrost_device *pdev = &device->physical_device->pdev;
104   enum pipe_format fmt = vk_format_to_pipe_format(pCreateInfo->format);
105   bool noafbc = !(device->physical_device->instance->debug_flags & PANVK_DEBUG_AFBC);
106   bool linear = device->physical_device->instance->debug_flags & PANVK_DEBUG_LINEAR;
107
108   *plane_layouts = NULL;
109
110   if (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR)
111      return DRM_FORMAT_MOD_LINEAR;
112
113   if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) {
114      const VkImageDrmFormatModifierListCreateInfoEXT *mod_info =
115         vk_find_struct_const(pCreateInfo->pNext,
116                              IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT);
117      const VkImageDrmFormatModifierExplicitCreateInfoEXT *drm_explicit_info =
118         vk_find_struct_const(pCreateInfo->pNext,
119                              IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT);
120
121      assert(mod_info || drm_explicit_info);
122
123      uint64_t modifier;
124
125      if (mod_info) {
126         modifier = DRM_FORMAT_MOD_LINEAR;
127         for (unsigned i = 0; i < mod_info->drmFormatModifierCount; i++) {
128            if (drm_is_afbc(mod_info->pDrmFormatModifiers[i]) && !noafbc) {
129               modifier = mod_info->pDrmFormatModifiers[i];
130               break;
131            }
132         }
133      } else {
134         modifier = drm_explicit_info->drmFormatModifier;
135         assert(modifier == DRM_FORMAT_MOD_LINEAR ||
136                modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED ||
137                (drm_is_afbc(modifier) && !noafbc));
138         *plane_layouts = drm_explicit_info->pPlaneLayouts;
139      }
140
141      return modifier;
142   }
143
144   const struct wsi_image_create_info *wsi_info =
145      vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA);
146   if (wsi_info && wsi_info->scanout)
147      return DRM_FORMAT_MOD_LINEAR;
148
149   assert(pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL);
150
151   if (linear)
152      return DRM_FORMAT_MOD_LINEAR;
153
154   /* Image store don't work on AFBC images */
155   if (pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT)
156      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
157
158   /* AFBC does not support layered multisampling */
159   if (pCreateInfo->samples > 1)
160      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
161
162   if (!pdev->has_afbc)
163      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
164
165   /* Only a small selection of formats are AFBC'able */
166   if (!panfrost_format_supports_afbc(pdev, fmt))
167      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
168
169   /* 3D AFBC is only supported on Bifrost v7+. It's supposed to
170    * be supported on Midgard but it doesn't seem to work.
171    */
172   if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D && pdev->arch < 7)
173      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
174
175   /* For one tile, AFBC is a loss compared to u-interleaved */
176   if (pCreateInfo->extent.width <= 16 && pCreateInfo->extent.height <= 16)
177      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
178
179   if (noafbc)
180      return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
181
182   uint64_t afbc_type = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
183                        AFBC_FORMAT_MOD_SPARSE;
184
185   if (panfrost_afbc_can_ytr(fmt))
186      afbc_type |= AFBC_FORMAT_MOD_YTR;
187
188   return DRM_FORMAT_MOD_ARM_AFBC(afbc_type);
189}
190
191VkResult
192panvk_CreateImage(VkDevice device,
193                  const VkImageCreateInfo *pCreateInfo,
194                  const VkAllocationCallbacks *pAllocator,
195                  VkImage *pImage)
196{
197   const VkSubresourceLayout *plane_layouts;
198   uint64_t modifier = panvk_image_select_mod(device, pCreateInfo, &plane_layouts);
199
200   return panvk_image_create(device, pCreateInfo, pAllocator, pImage, modifier, plane_layouts);
201}
202
203void
204panvk_DestroyImage(VkDevice _device,
205                   VkImage _image,
206                   const VkAllocationCallbacks *pAllocator)
207{
208   VK_FROM_HANDLE(panvk_device, device, _device);
209   VK_FROM_HANDLE(panvk_image, image, _image);
210
211   if (!image)
212      return;
213
214   vk_image_destroy(&device->vk, pAllocator, &image->vk);
215}
216
217static unsigned
218panvk_plane_index(VkFormat format, VkImageAspectFlags aspect_mask)
219{
220   switch (aspect_mask) {
221   default:
222      return 0;
223   case VK_IMAGE_ASPECT_PLANE_1_BIT:
224      return 1;
225   case VK_IMAGE_ASPECT_PLANE_2_BIT:
226      return 2;
227   case VK_IMAGE_ASPECT_STENCIL_BIT:
228      return format == VK_FORMAT_D32_SFLOAT_S8_UINT;
229   }
230}
231
232void
233panvk_GetImageSubresourceLayout(VkDevice _device,
234                                VkImage _image,
235                                const VkImageSubresource *pSubresource,
236                                VkSubresourceLayout *pLayout)
237{
238   VK_FROM_HANDLE(panvk_image, image, _image);
239
240   unsigned plane = panvk_plane_index(image->vk.format, pSubresource->aspectMask);
241   assert(plane < PANVK_MAX_PLANES);
242
243   const struct pan_image_slice_layout *slice_layout =
244      &image->pimage.layout.slices[pSubresource->mipLevel];
245
246   pLayout->offset = slice_layout->offset +
247                     (pSubresource->arrayLayer *
248                      image->pimage.layout.array_stride);
249   pLayout->size = slice_layout->size;
250   pLayout->rowPitch = slice_layout->row_stride;
251   pLayout->arrayPitch = image->pimage.layout.array_stride;
252   pLayout->depthPitch = slice_layout->surface_stride;
253}
254
255void
256panvk_DestroyImageView(VkDevice _device,
257                       VkImageView _view,
258                       const VkAllocationCallbacks *pAllocator)
259{
260   VK_FROM_HANDLE(panvk_device, device, _device);
261   VK_FROM_HANDLE(panvk_image_view, view, _view);
262
263   if (!view)
264      return;
265
266   panfrost_bo_unreference(view->bo);
267   vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
268}
269
270void
271panvk_DestroyBufferView(VkDevice _device,
272                        VkBufferView bufferView,
273                        const VkAllocationCallbacks *pAllocator)
274{
275   VK_FROM_HANDLE(panvk_device, device, _device);
276   VK_FROM_HANDLE(panvk_buffer_view, view, bufferView);
277
278   if (!view)
279      return;
280
281   panfrost_bo_unreference(view->bo);
282   vk_object_free(&device->vk, pAllocator, view);
283}
284
285VkResult
286panvk_GetImageDrmFormatModifierPropertiesEXT(VkDevice device,
287                                             VkImage _image,
288                                             VkImageDrmFormatModifierPropertiesEXT *pProperties)
289{
290   VK_FROM_HANDLE(panvk_image, image, _image);
291
292   assert(pProperties->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT);
293
294   pProperties->drmFormatModifier = image->pimage.layout.modifier;
295   return VK_SUCCESS;
296}
297