1/* 2 * Copyright © 2021 Collabora Ltd. 3 * 4 * Derived from tu_formats.c which is: 5 * Copyright © 2016 Red Hat. 6 * Copyright © 2016 Bas Nieuwenhuizen 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the "Software"), 10 * to deal in the Software without restriction, including without limitation 11 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 * and/or sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the next 16 * paragraph) shall be included in all copies or substantial portions of the 17 * Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 */ 27 28#include "panvk_private.h" 29 30#include "util/format_r11g11b10f.h" 31#include "util/format_srgb.h" 32#include "util/half_float.h" 33#include "vulkan/util/vk_format.h" 34#include "vk_format.h" 35#include "vk_util.h" 36#include "panfrost/lib/pan_texture.h" 37 38static void 39get_format_properties(struct panvk_physical_device *physical_device, 40 VkFormat format, 41 VkFormatProperties *out_properties) 42{ 43 struct panfrost_device *pdev = &physical_device->pdev; 44 VkFormatFeatureFlags tex = 0, buffer = 0; 45 enum pipe_format pfmt = vk_format_to_pipe_format(format); 46 const struct panfrost_format fmt = pdev->formats[pfmt]; 47 48 if (!pfmt || !fmt.hw) 49 goto end; 50 51 /* 3byte formats are not supported by the buffer <-> image copy helpers. */ 52 if (util_format_get_blocksize(pfmt) == 3) 53 goto end; 54 55 /* We don't support compressed formats yet: this is causing trouble when 56 * doing a vkCmdCopyImage() between a compressed and a non-compressed format 57 * on a tiled/AFBC resource. 58 */ 59 if (util_format_is_compressed(pfmt)) 60 goto end; 61 62 buffer |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | 63 VK_FORMAT_FEATURE_TRANSFER_DST_BIT; 64 65 if (fmt.bind & PIPE_BIND_VERTEX_BUFFER) 66 buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; 67 68 if (fmt.bind & PIPE_BIND_SAMPLER_VIEW) { 69 tex |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | 70 VK_FORMAT_FEATURE_TRANSFER_DST_BIT | 71 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | 72 VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | 73 VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; 74 75 /* Integer formats only support nearest filtering */ 76 if (!util_format_is_scaled(pfmt) && 77 !util_format_is_pure_integer(pfmt)) 78 tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; 79 80 buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT; 81 82 tex |= VK_FORMAT_FEATURE_BLIT_SRC_BIT; 83 } 84 85 if (fmt.bind & PIPE_BIND_RENDER_TARGET) { 86 tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | 87 VK_FORMAT_FEATURE_BLIT_DST_BIT; 88 89 tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; 90 buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; 91 92 /* Can always blend via blend shaders */ 93 tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; 94 } 95 96 if (fmt.bind & PIPE_BIND_DEPTH_STENCIL) 97 tex |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; 98 99end: 100 out_properties->linearTilingFeatures = tex; 101 out_properties->optimalTilingFeatures = tex; 102 out_properties->bufferFeatures = buffer; 103} 104 105void 106panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, 107 VkFormat format, 108 VkFormatProperties *pFormatProperties) 109{ 110 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 111 112 get_format_properties(physical_device, format, pFormatProperties); 113} 114 115void 116panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, 117 VkFormat format, 118 VkFormatProperties2 *pFormatProperties) 119{ 120 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 121 122 get_format_properties(physical_device, format, 123 &pFormatProperties->formatProperties); 124 125 VkDrmFormatModifierPropertiesListEXT *list = 126 vk_find_struct(pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT); 127 if (list) { 128 VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out, 129 list->pDrmFormatModifierProperties, 130 &list->drmFormatModifierCount); 131 132 vk_outarray_append_typed(VkDrmFormatModifierProperties2EXT, &out, mod_props) { 133 mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; 134 mod_props->drmFormatModifierPlaneCount = 1; 135 } 136 } 137} 138 139static VkResult 140get_image_format_properties(struct panvk_physical_device *physical_device, 141 const VkPhysicalDeviceImageFormatInfo2 *info, 142 VkImageFormatProperties *pImageFormatProperties, 143 VkFormatFeatureFlags *p_feature_flags) 144{ 145 VkFormatProperties format_props; 146 VkFormatFeatureFlags format_feature_flags; 147 VkExtent3D maxExtent; 148 uint32_t maxMipLevels; 149 uint32_t maxArraySize; 150 VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; 151 enum pipe_format format = vk_format_to_pipe_format(info->format); 152 153 get_format_properties(physical_device, info->format, &format_props); 154 155 switch (info->tiling) { 156 case VK_IMAGE_TILING_LINEAR: 157 format_feature_flags = format_props.linearTilingFeatures; 158 break; 159 160 case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: 161 /* The only difference between optimal and linear is currently whether 162 * depth/stencil attachments are allowed on depth/stencil formats. 163 * There's no reason to allow importing depth/stencil textures, so just 164 * disallow it and then this annoying edge case goes away. 165 * 166 * TODO: If anyone cares, we could enable this by looking at the 167 * modifier and checking if it's LINEAR or not. 168 */ 169 if (util_format_is_depth_or_stencil(format)) 170 goto unsupported; 171 172 assert(format_props.optimalTilingFeatures == format_props.linearTilingFeatures); 173 FALLTHROUGH; 174 case VK_IMAGE_TILING_OPTIMAL: 175 format_feature_flags = format_props.optimalTilingFeatures; 176 break; 177 default: 178 unreachable("bad VkPhysicalDeviceImageFormatInfo2"); 179 } 180 181 if (format_feature_flags == 0) 182 goto unsupported; 183 184 if (info->type != VK_IMAGE_TYPE_2D && 185 util_format_is_depth_or_stencil(format)) 186 goto unsupported; 187 188 switch (info->type) { 189 default: 190 unreachable("bad vkimage type"); 191 case VK_IMAGE_TYPE_1D: 192 maxExtent.width = 16384; 193 maxExtent.height = 1; 194 maxExtent.depth = 1; 195 maxMipLevels = 15; /* log2(maxWidth) + 1 */ 196 maxArraySize = 2048; 197 break; 198 case VK_IMAGE_TYPE_2D: 199 maxExtent.width = 16384; 200 maxExtent.height = 16384; 201 maxExtent.depth = 1; 202 maxMipLevels = 15; /* log2(maxWidth) + 1 */ 203 maxArraySize = 2048; 204 break; 205 case VK_IMAGE_TYPE_3D: 206 maxExtent.width = 2048; 207 maxExtent.height = 2048; 208 maxExtent.depth = 2048; 209 maxMipLevels = 12; /* log2(maxWidth) + 1 */ 210 maxArraySize = 1; 211 break; 212 } 213 214 if (info->tiling == VK_IMAGE_TILING_OPTIMAL && 215 info->type == VK_IMAGE_TYPE_2D && 216 (format_feature_flags & 217 (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | 218 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && 219 !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && 220 !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) { 221 sampleCounts |= VK_SAMPLE_COUNT_4_BIT; 222 } 223 224 if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) { 225 if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { 226 goto unsupported; 227 } 228 } 229 230 if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) { 231 if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { 232 goto unsupported; 233 } 234 } 235 236 if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { 237 if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { 238 goto unsupported; 239 } 240 } 241 242 if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { 243 if (!(format_feature_flags & 244 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { 245 goto unsupported; 246 } 247 } 248 249 *pImageFormatProperties = (VkImageFormatProperties) { 250 .maxExtent = maxExtent, 251 .maxMipLevels = maxMipLevels, 252 .maxArrayLayers = maxArraySize, 253 .sampleCounts = sampleCounts, 254 255 /* FINISHME: Accurately calculate 256 * VkImageFormatProperties::maxResourceSize. 257 */ 258 .maxResourceSize = UINT32_MAX, 259 }; 260 261 if (p_feature_flags) 262 *p_feature_flags = format_feature_flags; 263 264 return VK_SUCCESS; 265unsupported: 266 *pImageFormatProperties = (VkImageFormatProperties) { 267 .maxExtent = { 0, 0, 0 }, 268 .maxMipLevels = 0, 269 .maxArrayLayers = 0, 270 .sampleCounts = 0, 271 .maxResourceSize = 0, 272 }; 273 274 return VK_ERROR_FORMAT_NOT_SUPPORTED; 275} 276 277 278VkResult 279panvk_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, 280 VkFormat format, 281 VkImageType type, 282 VkImageTiling tiling, 283 VkImageUsageFlags usage, 284 VkImageCreateFlags createFlags, 285 VkImageFormatProperties *pImageFormatProperties) 286{ 287 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 288 289 const VkPhysicalDeviceImageFormatInfo2 info = { 290 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, 291 .pNext = NULL, 292 .format = format, 293 .type = type, 294 .tiling = tiling, 295 .usage = usage, 296 .flags = createFlags, 297 }; 298 299 return get_image_format_properties(physical_device, &info, 300 pImageFormatProperties, NULL); 301} 302 303static VkResult 304panvk_get_external_image_format_properties(const struct panvk_physical_device *physical_device, 305 const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, 306 VkExternalMemoryHandleTypeFlagBits handleType, 307 VkExternalMemoryProperties *external_properties) 308{ 309 VkExternalMemoryFeatureFlagBits flags = 0; 310 VkExternalMemoryHandleTypeFlags export_flags = 0; 311 VkExternalMemoryHandleTypeFlags compat_flags = 0; 312 313 /* From the Vulkan 1.1.98 spec: 314 * 315 * If handleType is not compatible with the format, type, tiling, 316 * usage, and flags specified in VkPhysicalDeviceImageFormatInfo2, 317 * then vkGetPhysicalDeviceImageFormatProperties2 returns 318 * VK_ERROR_FORMAT_NOT_SUPPORTED. 319 */ 320 switch (handleType) { 321 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: 322 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: 323 switch (pImageFormatInfo->type) { 324 case VK_IMAGE_TYPE_2D: 325 flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | 326 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | 327 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; 328 compat_flags = export_flags = 329 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | 330 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; 331 break; 332 default: 333 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, 334 "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)", 335 handleType, pImageFormatInfo->type); 336 } 337 break; 338 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: 339 flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; 340 compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; 341 break; 342 default: 343 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, 344 "VkExternalMemoryTypeFlagBits(0x%x) unsupported", 345 handleType); 346 } 347 348 *external_properties = (VkExternalMemoryProperties) { 349 .externalMemoryFeatures = flags, 350 .exportFromImportedHandleTypes = export_flags, 351 .compatibleHandleTypes = compat_flags, 352 }; 353 354 return VK_SUCCESS; 355} 356 357VkResult 358panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, 359 const VkPhysicalDeviceImageFormatInfo2 *base_info, 360 VkImageFormatProperties2 *base_props) 361{ 362 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 363 const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL; 364 const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL; 365 VkExternalImageFormatProperties *external_props = NULL; 366 VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL; 367 VkFormatFeatureFlags format_feature_flags; 368 VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; 369 VkResult result; 370 371 result = get_image_format_properties(physical_device, base_info, 372 &base_props->imageFormatProperties, 373 &format_feature_flags); 374 if (result != VK_SUCCESS) 375 return result; 376 377 /* Extract input structs */ 378 vk_foreach_struct_const(s, base_info->pNext) 379 { 380 switch (s->sType) { 381 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: 382 external_info = (const void *) s; 383 break; 384 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: 385 image_view_info = (const void *) s; 386 break; 387 default: 388 break; 389 } 390 } 391 392 /* Extract output structs */ 393 vk_foreach_struct(s, base_props->pNext) 394 { 395 switch (s->sType) { 396 case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: 397 external_props = (void *) s; 398 break; 399 case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: 400 cubic_props = (void *) s; 401 break; 402 case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: 403 ycbcr_props = (void *) s; 404 break; 405 default: 406 break; 407 } 408 } 409 410 /* From the Vulkan 1.0.42 spec: 411 * 412 * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will 413 * behave as if VkPhysicalDeviceExternalImageFormatInfo was not 414 * present and VkExternalImageFormatProperties will be ignored. 415 */ 416 if (external_info && external_info->handleType != 0) { 417 result = panvk_get_external_image_format_properties(physical_device, 418 base_info, 419 external_info->handleType, 420 &external_props->externalMemoryProperties); 421 if (result != VK_SUCCESS) 422 goto fail; 423 } 424 425 if (cubic_props) { 426 /* note: blob only allows cubic filtering for 2D and 2D array views 427 * its likely we can enable it for 1D and CUBE, needs testing however 428 */ 429 if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D || 430 image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && 431 (format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) { 432 cubic_props->filterCubic = true; 433 cubic_props->filterCubicMinmax = true; 434 } else { 435 cubic_props->filterCubic = false; 436 cubic_props->filterCubicMinmax = false; 437 } 438 } 439 440 if (ycbcr_props) 441 ycbcr_props->combinedImageSamplerDescriptorCount = 1; 442 443 return VK_SUCCESS; 444 445fail: 446 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { 447 /* From the Vulkan 1.0.42 spec: 448 * 449 * If the combination of parameters to 450 * vkGetPhysicalDeviceImageFormatProperties2 is not supported by 451 * the implementation for use in vkCreateImage, then all members of 452 * imageFormatProperties will be filled with zero. 453 */ 454 base_props->imageFormatProperties = (VkImageFormatProperties) {}; 455 } 456 457 return result; 458} 459 460void 461panvk_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, 462 VkFormat format, 463 VkImageType type, 464 uint32_t samples, 465 VkImageUsageFlags usage, 466 VkImageTiling tiling, 467 uint32_t *pNumProperties, 468 VkSparseImageFormatProperties *pProperties) 469{ 470 /* Sparse images are not yet supported. */ 471 *pNumProperties = 0; 472} 473 474void 475panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, 476 const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, 477 uint32_t *pPropertyCount, 478 VkSparseImageFormatProperties2 *pProperties) 479{ 480 /* Sparse images are not yet supported. */ 481 *pPropertyCount = 0; 482} 483 484void 485panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, 486 const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, 487 VkExternalBufferProperties *pExternalBufferProperties) 488{ 489 panvk_stub(); 490} 491