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