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(out, list->pDrmFormatModifierProperties, 129 &list->drmFormatModifierCount); 130 131 vk_outarray_append(&out, mod_props) { 132 mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR; 133 mod_props->drmFormatModifierPlaneCount = 1; 134 } 135 } 136} 137 138static VkResult 139get_image_format_properties(struct panvk_physical_device *physical_device, 140 const VkPhysicalDeviceImageFormatInfo2 *info, 141 VkImageFormatProperties *pImageFormatProperties, 142 VkFormatFeatureFlags *p_feature_flags) 143{ 144 VkFormatProperties format_props; 145 VkFormatFeatureFlags format_feature_flags; 146 VkExtent3D maxExtent; 147 uint32_t maxMipLevels; 148 uint32_t maxArraySize; 149 VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; 150 enum pipe_format format = vk_format_to_pipe_format(info->format); 151 152 get_format_properties(physical_device, info->format, &format_props); 153 154 switch (info->tiling) { 155 case VK_IMAGE_TILING_LINEAR: 156 format_feature_flags = format_props.linearTilingFeatures; 157 break; 158 159 case VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT: 160 /* The only difference between optimal and linear is currently whether 161 * depth/stencil attachments are allowed on depth/stencil formats. 162 * There's no reason to allow importing depth/stencil textures, so just 163 * disallow it and then this annoying edge case goes away. 164 * 165 * TODO: If anyone cares, we could enable this by looking at the 166 * modifier and checking if it's LINEAR or not. 167 */ 168 if (util_format_is_depth_or_stencil(format)) 169 goto unsupported; 170 171 assert(format_props.optimalTilingFeatures == format_props.linearTilingFeatures); 172 /* fallthrough */ 173 case VK_IMAGE_TILING_OPTIMAL: 174 format_feature_flags = format_props.optimalTilingFeatures; 175 break; 176 default: 177 unreachable("bad VkPhysicalDeviceImageFormatInfo2"); 178 } 179 180 if (format_feature_flags == 0) 181 goto unsupported; 182 183 if (info->type != VK_IMAGE_TYPE_2D && 184 util_format_is_depth_or_stencil(format)) 185 goto unsupported; 186 187 switch (info->type) { 188 default: 189 unreachable("bad vkimage type"); 190 case VK_IMAGE_TYPE_1D: 191 maxExtent.width = 16384; 192 maxExtent.height = 1; 193 maxExtent.depth = 1; 194 maxMipLevels = 15; /* log2(maxWidth) + 1 */ 195 maxArraySize = 2048; 196 break; 197 case VK_IMAGE_TYPE_2D: 198 maxExtent.width = 16384; 199 maxExtent.height = 16384; 200 maxExtent.depth = 1; 201 maxMipLevels = 15; /* log2(maxWidth) + 1 */ 202 maxArraySize = 2048; 203 break; 204 case VK_IMAGE_TYPE_3D: 205 maxExtent.width = 2048; 206 maxExtent.height = 2048; 207 maxExtent.depth = 2048; 208 maxMipLevels = 12; /* log2(maxWidth) + 1 */ 209 maxArraySize = 1; 210 break; 211 } 212 213 if (info->tiling == VK_IMAGE_TILING_OPTIMAL && 214 info->type == VK_IMAGE_TYPE_2D && 215 (format_feature_flags & 216 (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | 217 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && 218 !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && 219 !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) { 220 sampleCounts |= VK_SAMPLE_COUNT_4_BIT; 221 } 222 223 if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) { 224 if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) { 225 goto unsupported; 226 } 227 } 228 229 if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) { 230 if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) { 231 goto unsupported; 232 } 233 } 234 235 if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { 236 if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) { 237 goto unsupported; 238 } 239 } 240 241 if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { 242 if (!(format_feature_flags & 243 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) { 244 goto unsupported; 245 } 246 } 247 248 *pImageFormatProperties = (VkImageFormatProperties) { 249 .maxExtent = maxExtent, 250 .maxMipLevels = maxMipLevels, 251 .maxArrayLayers = maxArraySize, 252 .sampleCounts = sampleCounts, 253 254 /* FINISHME: Accurately calculate 255 * VkImageFormatProperties::maxResourceSize. 256 */ 257 .maxResourceSize = UINT32_MAX, 258 }; 259 260 if (p_feature_flags) 261 *p_feature_flags = format_feature_flags; 262 263 return VK_SUCCESS; 264unsupported: 265 *pImageFormatProperties = (VkImageFormatProperties) { 266 .maxExtent = { 0, 0, 0 }, 267 .maxMipLevels = 0, 268 .maxArrayLayers = 0, 269 .sampleCounts = 0, 270 .maxResourceSize = 0, 271 }; 272 273 return VK_ERROR_FORMAT_NOT_SUPPORTED; 274} 275 276 277VkResult 278panvk_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, 279 VkFormat format, 280 VkImageType type, 281 VkImageTiling tiling, 282 VkImageUsageFlags usage, 283 VkImageCreateFlags createFlags, 284 VkImageFormatProperties *pImageFormatProperties) 285{ 286 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 287 288 const VkPhysicalDeviceImageFormatInfo2 info = { 289 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, 290 .pNext = NULL, 291 .format = format, 292 .type = type, 293 .tiling = tiling, 294 .usage = usage, 295 .flags = createFlags, 296 }; 297 298 return get_image_format_properties(physical_device, &info, 299 pImageFormatProperties, NULL); 300} 301 302static VkResult 303panvk_get_external_image_format_properties(const struct panvk_physical_device *physical_device, 304 const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, 305 VkExternalMemoryHandleTypeFlagBits handleType, 306 VkExternalMemoryProperties *external_properties) 307{ 308 VkExternalMemoryFeatureFlagBits flags = 0; 309 VkExternalMemoryHandleTypeFlags export_flags = 0; 310 VkExternalMemoryHandleTypeFlags compat_flags = 0; 311 312 /* From the Vulkan 1.1.98 spec: 313 * 314 * If handleType is not compatible with the format, type, tiling, 315 * usage, and flags specified in VkPhysicalDeviceImageFormatInfo2, 316 * then vkGetPhysicalDeviceImageFormatProperties2 returns 317 * VK_ERROR_FORMAT_NOT_SUPPORTED. 318 */ 319 switch (handleType) { 320 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: 321 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: 322 switch (pImageFormatInfo->type) { 323 case VK_IMAGE_TYPE_2D: 324 flags = VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT | 325 VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | 326 VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; 327 compat_flags = export_flags = 328 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | 329 VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; 330 break; 331 default: 332 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, 333 "VkExternalMemoryTypeFlagBits(0x%x) unsupported for VkImageType(%d)", 334 handleType, pImageFormatInfo->type); 335 } 336 break; 337 case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: 338 flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; 339 compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; 340 break; 341 default: 342 return vk_errorf(physical_device, VK_ERROR_FORMAT_NOT_SUPPORTED, 343 "VkExternalMemoryTypeFlagBits(0x%x) unsupported", 344 handleType); 345 } 346 347 *external_properties = (VkExternalMemoryProperties) { 348 .externalMemoryFeatures = flags, 349 .exportFromImportedHandleTypes = export_flags, 350 .compatibleHandleTypes = compat_flags, 351 }; 352 353 return VK_SUCCESS; 354} 355 356VkResult 357panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, 358 const VkPhysicalDeviceImageFormatInfo2 *base_info, 359 VkImageFormatProperties2 *base_props) 360{ 361 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice); 362 const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL; 363 const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL; 364 VkExternalImageFormatProperties *external_props = NULL; 365 VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL; 366 VkFormatFeatureFlags format_feature_flags; 367 VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; 368 VkResult result; 369 370 result = get_image_format_properties(physical_device, base_info, 371 &base_props->imageFormatProperties, 372 &format_feature_flags); 373 if (result != VK_SUCCESS) 374 return result; 375 376 /* Extract input structs */ 377 vk_foreach_struct_const(s, base_info->pNext) 378 { 379 switch (s->sType) { 380 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: 381 external_info = (const void *) s; 382 break; 383 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT: 384 image_view_info = (const void *) s; 385 break; 386 default: 387 break; 388 } 389 } 390 391 /* Extract output structs */ 392 vk_foreach_struct(s, base_props->pNext) 393 { 394 switch (s->sType) { 395 case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: 396 external_props = (void *) s; 397 break; 398 case VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT: 399 cubic_props = (void *) s; 400 break; 401 case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: 402 ycbcr_props = (void *) s; 403 break; 404 default: 405 break; 406 } 407 } 408 409 /* From the Vulkan 1.0.42 spec: 410 * 411 * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will 412 * behave as if VkPhysicalDeviceExternalImageFormatInfo was not 413 * present and VkExternalImageFormatProperties will be ignored. 414 */ 415 if (external_info && external_info->handleType != 0) { 416 result = panvk_get_external_image_format_properties(physical_device, 417 base_info, 418 external_info->handleType, 419 &external_props->externalMemoryProperties); 420 if (result != VK_SUCCESS) 421 goto fail; 422 } 423 424 if (cubic_props) { 425 /* note: blob only allows cubic filtering for 2D and 2D array views 426 * its likely we can enable it for 1D and CUBE, needs testing however 427 */ 428 if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D || 429 image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) && 430 (format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT)) { 431 cubic_props->filterCubic = true; 432 cubic_props->filterCubicMinmax = true; 433 } else { 434 cubic_props->filterCubic = false; 435 cubic_props->filterCubicMinmax = false; 436 } 437 } 438 439 if (ycbcr_props) 440 ycbcr_props->combinedImageSamplerDescriptorCount = 1; 441 442 return VK_SUCCESS; 443 444fail: 445 if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { 446 /* From the Vulkan 1.0.42 spec: 447 * 448 * If the combination of parameters to 449 * vkGetPhysicalDeviceImageFormatProperties2 is not supported by 450 * the implementation for use in vkCreateImage, then all members of 451 * imageFormatProperties will be filled with zero. 452 */ 453 base_props->imageFormatProperties = (VkImageFormatProperties) {}; 454 } 455 456 return result; 457} 458 459void 460panvk_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, 461 VkFormat format, 462 VkImageType type, 463 uint32_t samples, 464 VkImageUsageFlags usage, 465 VkImageTiling tiling, 466 uint32_t *pNumProperties, 467 VkSparseImageFormatProperties *pProperties) 468{ 469 panvk_stub(); 470} 471 472void 473panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, 474 const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, 475 uint32_t *pPropertyCount, 476 VkSparseImageFormatProperties2 *pProperties) 477{ 478 panvk_stub(); 479} 480 481void 482panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, 483 const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, 484 VkExternalBufferProperties *pExternalBufferProperties) 485{ 486 panvk_stub(); 487} 488