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#include "panfrost-quirks.h" 31 32#include "util/debug.h" 33#include "util/u_atomic.h" 34#include "vk_format.h" 35#include "vk_object.h" 36#include "vk_util.h" 37#include "drm-uapi/drm_fourcc.h" 38 39unsigned 40panvk_image_get_plane_size(const struct panvk_image *image, unsigned plane) 41{ 42 assert(!plane); 43 return image->pimage.layout.data_size; 44} 45 46unsigned 47panvk_image_get_total_size(const struct panvk_image *image) 48{ 49 assert(util_format_get_num_planes(image->pimage.layout.format) == 1); 50 return image->pimage.layout.data_size; 51} 52 53static enum mali_texture_dimension 54panvk_image_type_to_mali_tex_dim(VkImageType type) 55{ 56 switch (type) { 57 case VK_IMAGE_TYPE_1D: return MALI_TEXTURE_DIMENSION_1D; 58 case VK_IMAGE_TYPE_2D: return MALI_TEXTURE_DIMENSION_2D; 59 case VK_IMAGE_TYPE_3D: return MALI_TEXTURE_DIMENSION_3D; 60 default: unreachable("Invalid image type"); 61 } 62} 63 64static VkResult 65panvk_image_create(VkDevice _device, 66 const VkImageCreateInfo *pCreateInfo, 67 const VkAllocationCallbacks *alloc, 68 VkImage *pImage, 69 uint64_t modifier, 70 const VkSubresourceLayout *plane_layouts) 71{ 72 VK_FROM_HANDLE(panvk_device, device, _device); 73 const struct panfrost_device *pdev = &device->physical_device->pdev; 74 struct panvk_image *image = NULL; 75 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); 76 77 assert(pCreateInfo->mipLevels > 0); 78 assert(pCreateInfo->arrayLayers > 0); 79 assert(pCreateInfo->samples > 0); 80 assert(pCreateInfo->extent.width > 0); 81 assert(pCreateInfo->extent.height > 0); 82 assert(pCreateInfo->extent.depth > 0); 83 84 image = vk_object_zalloc(&device->vk, alloc, sizeof(*image), 85 VK_OBJECT_TYPE_IMAGE); 86 if (!image) 87 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 88 89 image->type = pCreateInfo->imageType; 90 91 image->vk_format = pCreateInfo->format; 92 image->tiling = pCreateInfo->tiling; 93 image->usage = pCreateInfo->usage; 94 image->flags = pCreateInfo->flags; 95 image->extent = pCreateInfo->extent; 96 pan_image_layout_init(pdev, &image->pimage.layout, modifier, 97 vk_format_to_pipe_format(pCreateInfo->format), 98 panvk_image_type_to_mali_tex_dim(pCreateInfo->imageType), 99 pCreateInfo->extent.width, pCreateInfo->extent.height, 100 pCreateInfo->extent.depth, pCreateInfo->arrayLayers, 101 pCreateInfo->samples, pCreateInfo->mipLevels, 102 PAN_IMAGE_CRC_NONE, NULL); 103 104 image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE; 105 if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { 106 for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) { 107 if (pCreateInfo->pQueueFamilyIndices[i] == VK_QUEUE_FAMILY_EXTERNAL) 108 image->queue_family_mask |= (1u << PANVK_MAX_QUEUE_FAMILIES) - 1u; 109 else 110 image->queue_family_mask |= 1u << pCreateInfo->pQueueFamilyIndices[i]; 111 } 112 } 113 114 if (vk_find_struct_const(pCreateInfo->pNext, EXTERNAL_MEMORY_IMAGE_CREATE_INFO)) 115 image->shareable = true; 116 117 *pImage = panvk_image_to_handle(image); 118 return VK_SUCCESS; 119} 120 121static uint64_t 122panvk_image_select_mod(VkDevice _device, 123 const VkImageCreateInfo *pCreateInfo, 124 const VkSubresourceLayout **plane_layouts) 125{ 126 VK_FROM_HANDLE(panvk_device, device, _device); 127 const struct panfrost_device *pdev = &device->physical_device->pdev; 128 enum pipe_format fmt = vk_format_to_pipe_format(pCreateInfo->format); 129 bool noafbc = !(device->physical_device->instance->debug_flags & PANVK_DEBUG_AFBC); 130 bool linear = device->physical_device->instance->debug_flags & PANVK_DEBUG_LINEAR; 131 132 *plane_layouts = NULL; 133 134 if (pCreateInfo->tiling == VK_IMAGE_TILING_LINEAR) 135 return DRM_FORMAT_MOD_LINEAR; 136 137 if (pCreateInfo->tiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT) { 138 const VkImageDrmFormatModifierListCreateInfoEXT *mod_info = 139 vk_find_struct_const(pCreateInfo->pNext, 140 IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT); 141 const VkImageDrmFormatModifierExplicitCreateInfoEXT *drm_explicit_info = 142 vk_find_struct_const(pCreateInfo->pNext, 143 IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT); 144 145 assert(mod_info || drm_explicit_info); 146 147 uint64_t modifier; 148 149 if (mod_info) { 150 modifier = DRM_FORMAT_MOD_LINEAR; 151 for (unsigned i = 0; i < mod_info->drmFormatModifierCount; i++) { 152 if (drm_is_afbc(mod_info->pDrmFormatModifiers[i]) && !noafbc) { 153 modifier = mod_info->pDrmFormatModifiers[i]; 154 break; 155 } 156 } 157 } else { 158 modifier = drm_explicit_info->drmFormatModifier; 159 assert(modifier == DRM_FORMAT_MOD_LINEAR || 160 modifier == DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED || 161 (drm_is_afbc(modifier) && !noafbc)); 162 *plane_layouts = drm_explicit_info->pPlaneLayouts; 163 } 164 165 return modifier; 166 } 167 168 const struct wsi_image_create_info *wsi_info = 169 vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA); 170 if (wsi_info && wsi_info->scanout) 171 return DRM_FORMAT_MOD_LINEAR; 172 173 assert(pCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL); 174 175 if (linear) 176 return DRM_FORMAT_MOD_LINEAR; 177 178 /* Image store don't work on AFBC images */ 179 if (pCreateInfo->usage & VK_IMAGE_USAGE_STORAGE_BIT) 180 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 181 182 /* AFBC does not support layered multisampling */ 183 if (pCreateInfo->samples > 1) 184 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 185 186 if (!pdev->has_afbc) 187 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 188 189 /* Only a small selection of formats are AFBC'able */ 190 if (!panfrost_format_supports_afbc(pdev, fmt)) 191 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 192 193 /* 3D AFBC is only supported on Bifrost v7+. It's supposed to 194 * be supported on Midgard but it doesn't seem to work. 195 */ 196 if (pCreateInfo->imageType == VK_IMAGE_TYPE_3D && pdev->arch < 7) 197 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 198 199 /* For one tile, AFBC is a loss compared to u-interleaved */ 200 if (pCreateInfo->extent.width <= 16 && pCreateInfo->extent.height <= 16) 201 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 202 203 if (noafbc) 204 return DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED; 205 206 uint64_t afbc_type = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 | 207 AFBC_FORMAT_MOD_SPARSE; 208 209 if (panfrost_afbc_can_ytr(fmt)) 210 afbc_type |= AFBC_FORMAT_MOD_YTR; 211 212 return DRM_FORMAT_MOD_ARM_AFBC(afbc_type); 213} 214 215VkResult 216panvk_CreateImage(VkDevice device, 217 const VkImageCreateInfo *pCreateInfo, 218 const VkAllocationCallbacks *pAllocator, 219 VkImage *pImage) 220{ 221 const VkSubresourceLayout *plane_layouts; 222 uint64_t modifier = panvk_image_select_mod(device, pCreateInfo, &plane_layouts); 223 224 return panvk_image_create(device, pCreateInfo, pAllocator, pImage, modifier, plane_layouts); 225} 226 227void 228panvk_DestroyImage(VkDevice _device, 229 VkImage _image, 230 const VkAllocationCallbacks *pAllocator) 231{ 232 VK_FROM_HANDLE(panvk_device, device, _device); 233 VK_FROM_HANDLE(panvk_image, image, _image); 234 235 if (!image) 236 return; 237 238 vk_object_free(&device->vk, pAllocator, image); 239} 240 241static unsigned 242panvk_plane_index(VkFormat format, VkImageAspectFlags aspect_mask) 243{ 244 switch (aspect_mask) { 245 default: 246 return 0; 247 case VK_IMAGE_ASPECT_PLANE_1_BIT: 248 return 1; 249 case VK_IMAGE_ASPECT_PLANE_2_BIT: 250 return 2; 251 case VK_IMAGE_ASPECT_STENCIL_BIT: 252 return format == VK_FORMAT_D32_SFLOAT_S8_UINT; 253 } 254} 255 256void 257panvk_GetImageSubresourceLayout(VkDevice _device, 258 VkImage _image, 259 const VkImageSubresource *pSubresource, 260 VkSubresourceLayout *pLayout) 261{ 262 VK_FROM_HANDLE(panvk_image, image, _image); 263 264 unsigned plane = panvk_plane_index(image->vk_format, pSubresource->aspectMask); 265 assert(plane < PANVK_MAX_PLANES); 266 267 const struct pan_image_slice_layout *slice_layout = 268 &image->pimage.layout.slices[pSubresource->mipLevel]; 269 270 pLayout->offset = slice_layout->offset + 271 (pSubresource->arrayLayer * 272 image->pimage.layout.array_stride); 273 pLayout->size = slice_layout->size; 274 pLayout->rowPitch = slice_layout->line_stride; 275 pLayout->arrayPitch = image->pimage.layout.array_stride; 276 pLayout->depthPitch = slice_layout->surface_stride; 277} 278 279void 280panvk_DestroyImageView(VkDevice _device, 281 VkImageView _view, 282 const VkAllocationCallbacks *pAllocator) 283{ 284 VK_FROM_HANDLE(panvk_device, device, _device); 285 VK_FROM_HANDLE(panvk_image_view, view, _view); 286 287 if (!view) 288 return; 289 290 panfrost_bo_unreference(view->bo); 291 vk_object_free(&device->vk, pAllocator, view); 292} 293 294VkResult 295panvk_CreateBufferView(VkDevice _device, 296 const VkBufferViewCreateInfo *pCreateInfo, 297 const VkAllocationCallbacks *pAllocator, 298 VkBufferView *pView) 299{ 300 panvk_stub(); 301 return VK_SUCCESS; 302} 303 304void 305panvk_DestroyBufferView(VkDevice _device, 306 VkBufferView bufferView, 307 const VkAllocationCallbacks *pAllocator) 308{ 309 panvk_stub(); 310} 311 312VkResult 313panvk_GetImageDrmFormatModifierPropertiesEXT(VkDevice device, 314 VkImage _image, 315 VkImageDrmFormatModifierPropertiesEXT *pProperties) 316{ 317 VK_FROM_HANDLE(panvk_image, image, _image); 318 319 assert(pProperties->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT); 320 321 pProperties->drmFormatModifier = image->pimage.layout.modifier; 322 return VK_SUCCESS; 323} 324