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 39 unsigned 40 panvk_image_get_plane_size(const struct panvk_image *image, unsigned plane) 41 { 42 assert(!plane); 43 return image->pimage.layout.data_size; 44 } 45 46 unsigned 47 panvk_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 53 static enum mali_texture_dimension 54 panvk_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 64 static VkResult 65 panvk_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 121 static uint64_t 122 panvk_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 215 VkResult 216 panvk_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 227 void 228 panvk_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 241 static unsigned 242 panvk_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 256 void 257 panvk_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 279 void 280 panvk_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 294 VkResult 295 panvk_CreateBufferView(VkDevice _device, 296 const VkBufferViewCreateInfo *pCreateInfo, 297 const VkAllocationCallbacks *pAllocator, 298 VkBufferView *pView) 299 { 300 panvk_stub(); 301 return VK_SUCCESS; 302 } 303 304 void 305 panvk_DestroyBufferView(VkDevice _device, 306 VkBufferView bufferView, 307 const VkAllocationCallbacks *pAllocator) 308 { 309 panvk_stub(); 310 } 311 312 VkResult 313 panvk_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