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
38 static void
get_format_properties(struct panvk_physical_device * physical_device,VkFormat format,VkFormatProperties * out_properties)39 get_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
99 end:
100 out_properties->linearTilingFeatures = tex;
101 out_properties->optimalTilingFeatures = tex;
102 out_properties->bufferFeatures = buffer;
103 }
104
105 void
panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties * pFormatProperties)106 panvk_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
115 void
panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties2 * pFormatProperties)116 panvk_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
138 static VkResult
get_image_format_properties(struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties * pImageFormatProperties,VkFormatFeatureFlags * p_feature_flags)139 get_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;
264 unsupported:
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
277 VkResult
panvk_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkImageTiling tiling,VkImageUsageFlags usage,VkImageCreateFlags createFlags,VkImageFormatProperties * pImageFormatProperties)278 panvk_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
302 static VkResult
panvk_get_external_image_format_properties(const struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkExternalMemoryHandleTypeFlagBits handleType,VkExternalMemoryProperties * external_properties)303 panvk_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
356 VkResult
panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * base_info,VkImageFormatProperties2 * base_props)357 panvk_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
444 fail:
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
459 void
panvk_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,uint32_t samples,VkImageUsageFlags usage,VkImageTiling tiling,uint32_t * pNumProperties,VkSparseImageFormatProperties * pProperties)460 panvk_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
472 void
panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)473 panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,
474 const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
475 uint32_t *pPropertyCount,
476 VkSparseImageFormatProperties2 *pProperties)
477 {
478 panvk_stub();
479 }
480
481 void
panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo,VkExternalBufferProperties * pExternalBufferProperties)482 panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
483 const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
484 VkExternalBufferProperties *pExternalBufferProperties)
485 {
486 panvk_stub();
487 }
488