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 "panfrost/lib/pan_texture.h"
31 #include "util/format_r11g11b10f.h"
32 #include "util/format_srgb.h"
33 #include "util/half_float.h"
34 #include "vulkan/util/vk_format.h"
35 #include "vk_format.h"
36 #include "vk_util.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, VkFormatProperties *out_properties)
41 {
42 VkFormatFeatureFlags tex = 0, buffer = 0;
43 enum pipe_format pfmt = vk_format_to_pipe_format(format);
44 const struct panfrost_format fmt = physical_device->formats.all[pfmt];
45
46 if (!pfmt || !fmt.hw)
47 goto end;
48
49 /* 3byte formats are not supported by the buffer <-> image copy helpers. */
50 if (util_format_get_blocksize(pfmt) == 3)
51 goto end;
52
53 /* We don't support compressed formats yet: this is causing trouble when
54 * doing a vkCmdCopyImage() between a compressed and a non-compressed format
55 * on a tiled/AFBC resource.
56 */
57 if (util_format_is_compressed(pfmt))
58 goto end;
59
60 buffer |=
61 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT;
62
63 if (fmt.bind & PAN_BIND_VERTEX_BUFFER)
64 buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT;
65
66 if (fmt.bind & PAN_BIND_SAMPLER_VIEW) {
67 tex |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
68 VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
69 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
70 VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
71 VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
72
73 /* Integer formats only support nearest filtering */
74 if (!util_format_is_scaled(pfmt) && !util_format_is_pure_integer(pfmt))
75 tex |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
76
77 buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
78
79 tex |= VK_FORMAT_FEATURE_BLIT_SRC_BIT;
80 }
81
82 /* SNORM rendering isn't working yet, disable */
83 if (fmt.bind & PAN_BIND_RENDER_TARGET && !util_format_is_snorm(pfmt)) {
84 tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
85 VK_FORMAT_FEATURE_BLIT_DST_BIT;
86
87 tex |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT;
88 buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT;
89
90 /* Can always blend via blend shaders */
91 tex |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT;
92 }
93
94 if (fmt.bind & PAN_BIND_DEPTH_STENCIL)
95 tex |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
96
97 end:
98 out_properties->linearTilingFeatures = tex;
99 out_properties->optimalTilingFeatures = tex;
100 out_properties->bufferFeatures = buffer;
101 }
102
103 void
panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties * pFormatProperties)104 panvk_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice,
105 VkFormat format,
106 VkFormatProperties *pFormatProperties)
107 {
108 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
109
110 get_format_properties(physical_device, format, pFormatProperties);
111 }
112
113 void
panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,VkFormat format,VkFormatProperties2 * pFormatProperties)114 panvk_GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice,
115 VkFormat format,
116 VkFormatProperties2 *pFormatProperties)
117 {
118 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
119
120 get_format_properties(physical_device, format,
121 &pFormatProperties->formatProperties);
122
123 VkDrmFormatModifierPropertiesListEXT *list = vk_find_struct(
124 pFormatProperties->pNext, DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT);
125 if (list) {
126 VK_OUTARRAY_MAKE_TYPED(VkDrmFormatModifierPropertiesEXT, out,
127 list->pDrmFormatModifierProperties,
128 &list->drmFormatModifierCount);
129
130 vk_outarray_append_typed(VkDrmFormatModifierProperties2EXT, &out,
131 mod_props)
132 {
133 mod_props->drmFormatModifier = DRM_FORMAT_MOD_LINEAR;
134 mod_props->drmFormatModifierPlaneCount = 1;
135 }
136 }
137 }
138
139 static VkResult
get_image_format_properties(struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * info,VkImageFormatProperties * pImageFormatProperties,VkFormatFeatureFlags * p_feature_flags)140 get_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 ==
173 format_props.linearTilingFeatures);
174 FALLTHROUGH;
175 case VK_IMAGE_TILING_OPTIMAL:
176 format_feature_flags = format_props.optimalTilingFeatures;
177 break;
178 default:
179 unreachable("bad VkPhysicalDeviceImageFormatInfo2");
180 }
181
182 if (format_feature_flags == 0)
183 goto unsupported;
184
185 if (info->type != VK_IMAGE_TYPE_2D &&
186 util_format_is_depth_or_stencil(format))
187 goto unsupported;
188
189 switch (info->type) {
190 default:
191 unreachable("bad vkimage type");
192 case VK_IMAGE_TYPE_1D:
193 maxExtent.width = 16384;
194 maxExtent.height = 1;
195 maxExtent.depth = 1;
196 maxMipLevels = 15; /* log2(maxWidth) + 1 */
197 maxArraySize = 2048;
198 break;
199 case VK_IMAGE_TYPE_2D:
200 maxExtent.width = 16384;
201 maxExtent.height = 16384;
202 maxExtent.depth = 1;
203 maxMipLevels = 15; /* log2(maxWidth) + 1 */
204 maxArraySize = 2048;
205 break;
206 case VK_IMAGE_TYPE_3D:
207 maxExtent.width = 2048;
208 maxExtent.height = 2048;
209 maxExtent.depth = 2048;
210 maxMipLevels = 12; /* log2(maxWidth) + 1 */
211 maxArraySize = 1;
212 break;
213 }
214
215 if (info->tiling == VK_IMAGE_TILING_OPTIMAL &&
216 info->type == VK_IMAGE_TYPE_2D &&
217 (format_feature_flags &
218 (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
219 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
220 !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) &&
221 !(info->usage & VK_IMAGE_USAGE_STORAGE_BIT)) {
222 sampleCounts |= VK_SAMPLE_COUNT_4_BIT;
223 }
224
225 if (info->usage & VK_IMAGE_USAGE_SAMPLED_BIT) {
226 if (!(format_feature_flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
227 goto unsupported;
228 }
229 }
230
231 if (info->usage & VK_IMAGE_USAGE_STORAGE_BIT) {
232 if (!(format_feature_flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
233 goto unsupported;
234 }
235 }
236
237 if (info->usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
238 if (!(format_feature_flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
239 goto unsupported;
240 }
241 }
242
243 if (info->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
244 if (!(format_feature_flags &
245 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
246 goto unsupported;
247 }
248 }
249
250 *pImageFormatProperties = (VkImageFormatProperties){
251 .maxExtent = maxExtent,
252 .maxMipLevels = maxMipLevels,
253 .maxArrayLayers = maxArraySize,
254 .sampleCounts = sampleCounts,
255
256 /* FINISHME: Accurately calculate
257 * VkImageFormatProperties::maxResourceSize.
258 */
259 .maxResourceSize = UINT32_MAX,
260 };
261
262 if (p_feature_flags)
263 *p_feature_flags = format_feature_flags;
264
265 return VK_SUCCESS;
266 unsupported:
267 *pImageFormatProperties = (VkImageFormatProperties){
268 .maxExtent = {0, 0, 0},
269 .maxMipLevels = 0,
270 .maxArrayLayers = 0,
271 .sampleCounts = 0,
272 .maxResourceSize = 0,
273 };
274
275 return VK_ERROR_FORMAT_NOT_SUPPORTED;
276 }
277
278 VkResult
panvk_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkImageTiling tiling,VkImageUsageFlags usage,VkImageCreateFlags createFlags,VkImageFormatProperties * pImageFormatProperties)279 panvk_GetPhysicalDeviceImageFormatProperties(
280 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
281 VkImageTiling tiling, VkImageUsageFlags usage,
282 VkImageCreateFlags createFlags,
283 VkImageFormatProperties *pImageFormatProperties)
284 {
285 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
286
287 const VkPhysicalDeviceImageFormatInfo2 info = {
288 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
289 .pNext = NULL,
290 .format = format,
291 .type = type,
292 .tiling = tiling,
293 .usage = usage,
294 .flags = createFlags,
295 };
296
297 return get_image_format_properties(physical_device, &info,
298 pImageFormatProperties, NULL);
299 }
300
301 static VkResult
panvk_get_external_image_format_properties(const struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkExternalMemoryHandleTypeFlagBits handleType,VkExternalMemoryProperties * external_properties)302 panvk_get_external_image_format_properties(
303 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(
333 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
357 VkResult
panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * base_info,VkImageFormatProperties2 * base_props)358 panvk_GetPhysicalDeviceImageFormatProperties2(
359 VkPhysicalDevice physicalDevice,
360 const VkPhysicalDeviceImageFormatInfo2 *base_info,
361 VkImageFormatProperties2 *base_props)
362 {
363 VK_FROM_HANDLE(panvk_physical_device, physical_device, physicalDevice);
364 const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
365 const VkPhysicalDeviceImageViewImageFormatInfoEXT *image_view_info = NULL;
366 VkExternalImageFormatProperties *external_props = NULL;
367 VkFilterCubicImageViewImageFormatPropertiesEXT *cubic_props = NULL;
368 VkFormatFeatureFlags format_feature_flags;
369 VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL;
370 VkResult result;
371
372 result = get_image_format_properties(physical_device, base_info,
373 &base_props->imageFormatProperties,
374 &format_feature_flags);
375 if (result != VK_SUCCESS)
376 return result;
377
378 /* Extract input structs */
379 vk_foreach_struct_const(s, base_info->pNext) {
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 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(
417 physical_device, base_info, external_info->handleType,
418 &external_props->externalMemoryProperties);
419 if (result != VK_SUCCESS)
420 goto fail;
421 }
422
423 if (cubic_props) {
424 /* note: blob only allows cubic filtering for 2D and 2D array views
425 * its likely we can enable it for 1D and CUBE, needs testing however
426 */
427 if ((image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D ||
428 image_view_info->imageViewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY) &&
429 (format_feature_flags &
430 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,VkSampleCountFlagBits samples,VkImageUsageFlags usage,VkImageTiling tiling,uint32_t * pNumProperties,VkSparseImageFormatProperties * pProperties)460 panvk_GetPhysicalDeviceSparseImageFormatProperties(
461 VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type,
462 VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling,
463 uint32_t *pNumProperties, VkSparseImageFormatProperties *pProperties)
464 {
465 /* Sparse images are not yet supported. */
466 *pNumProperties = 0;
467 }
468
469 void
panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)470 panvk_GetPhysicalDeviceSparseImageFormatProperties2(
471 VkPhysicalDevice physicalDevice,
472 const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
473 uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
474 {
475 /* Sparse images are not yet supported. */
476 *pPropertyCount = 0;
477 }
478
479 void
panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo,VkExternalBufferProperties * pExternalBufferProperties)480 panvk_GetPhysicalDeviceExternalBufferProperties(
481 VkPhysicalDevice physicalDevice,
482 const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
483 VkExternalBufferProperties *pExternalBufferProperties)
484 {
485 panvk_stub();
486 }
487