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