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