• 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 "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