• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_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 
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 == 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;
265 unsupported:
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 
278 VkResult
panvk_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,VkImageTiling tiling,VkImageUsageFlags usage,VkImageCreateFlags createFlags,VkImageFormatProperties * pImageFormatProperties)279 panvk_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 
303 static VkResult
panvk_get_external_image_format_properties(const struct panvk_physical_device * physical_device,const VkPhysicalDeviceImageFormatInfo2 * pImageFormatInfo,VkExternalMemoryHandleTypeFlagBits handleType,VkExternalMemoryProperties * external_properties)304 panvk_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 
357 VkResult
panvk_GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceImageFormatInfo2 * base_info,VkImageFormatProperties2 * base_props)358 panvk_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 
445 fail:
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 
460 void
panvk_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice,VkFormat format,VkImageType type,uint32_t samples,VkImageUsageFlags usage,VkImageTiling tiling,uint32_t * pNumProperties,VkSparseImageFormatProperties * pProperties)461 panvk_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 
474 void
panvk_GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceSparseImageFormatInfo2 * pFormatInfo,uint32_t * pPropertyCount,VkSparseImageFormatProperties2 * pProperties)475 panvk_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 
484 void
panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalBufferInfo * pExternalBufferInfo,VkExternalBufferProperties * pExternalBufferProperties)485 panvk_GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice,
486                                                 const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
487                                                 VkExternalBufferProperties *pExternalBufferProperties)
488 {
489    panvk_stub();
490 }
491