1/*
2 * Copyright © 2022 Imagination Technologies Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include <stdbool.h>
25
26#include "pvr_formats.h"
27#include "pvr_private.h"
28#include "vk_enum_to_str.h"
29#include "vk_format.h"
30#include "vk_log.h"
31#include "vk_util.h"
32
33#define FORMAT(vk, tex_fmt, pack_mode)                     \
34   [VK_FORMAT_##vk] = {                                    \
35      .vk_format = VK_FORMAT_##vk,                         \
36      .tex_format = ROGUE_TEXSTATE_FORMAT_##tex_fmt,       \
37      .pbe_packmode = ROGUE_PBESTATE_PACKMODE_##pack_mode, \
38      .supported = true,                                   \
39   }
40
41struct pvr_format {
42   VkFormat vk_format;
43   uint32_t tex_format;
44   uint32_t pbe_packmode;
45   bool supported;
46};
47
48/* TODO: add all supported core formats */
49static const struct pvr_format pvr_format_table[] = {
50   /* VK_FORMAT_R8_UINT = 13. */
51   FORMAT(R8_UINT, U8, U8),
52   /* VK_FORMAT_B8G8R8A8_UNORM = 44. */
53   FORMAT(B8G8R8A8_UNORM, U8U8U8U8, U8U8U8U8),
54   /* VK_FORMAT_R32_UINT = 98. */
55   FORMAT(R32_UINT, U32, U32),
56   /* VK_FORMAT_R32G32B32A32_UINT = 107. */
57   FORMAT(R32G32B32A32_UINT, U32U32U32U32, U32U32U32U32),
58   /* VK_FORMAT_R32G32B32A32_SFLOAT = 109. */
59   FORMAT(R32G32B32A32_SFLOAT, F32F32F32F32, F32F32F32F32),
60   /* VK_FORMAT_D32_SFLOAT = 126. */
61   FORMAT(D32_SFLOAT, F32, F32),
62};
63
64#undef FORMAT
65
66static inline const struct pvr_format *pvr_get_format(VkFormat vk_format)
67{
68   if (vk_format < ARRAY_SIZE(pvr_format_table) &&
69       pvr_format_table[vk_format].supported) {
70      return &pvr_format_table[vk_format];
71   }
72
73   mesa_logd("Format %s(%d) not supported\n",
74             vk_Format_to_str(vk_format),
75             vk_format);
76
77   return NULL;
78}
79
80uint32_t pvr_get_tex_format(VkFormat vk_format)
81{
82   const struct pvr_format *pvr_format = pvr_get_format(vk_format);
83   if (pvr_format) {
84      return pvr_format->tex_format;
85   }
86
87   return ROGUE_TEXSTATE_FORMAT_INVALID;
88}
89
90uint32_t pvr_get_pbe_packmode(VkFormat vk_format)
91{
92   const struct pvr_format *pvr_format = pvr_get_format(vk_format);
93   if (pvr_format)
94      return pvr_format->pbe_packmode;
95
96   return ROGUE_PBESTATE_PACKMODE_INVALID;
97}
98
99static VkFormatFeatureFlags
100pvr_get_image_format_features(const struct pvr_format *pvr_format,
101                              VkImageTiling vk_tiling)
102{
103   VkFormatFeatureFlags flags = 0;
104   VkImageAspectFlags aspects;
105
106   if (!pvr_format)
107      return 0;
108
109   aspects = vk_format_aspects(pvr_format->vk_format);
110   if (aspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
111      flags |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT |
112               VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
113               VK_FORMAT_FEATURE_BLIT_SRC_BIT;
114   }
115
116   return flags;
117}
118
119const uint8_t *pvr_get_format_swizzle(VkFormat vk_format)
120{
121   const struct util_format_description *vf = vk_format_description(vk_format);
122
123   return vf->swizzle;
124}
125
126static VkFormatFeatureFlags
127pvr_get_buffer_format_features(const struct pvr_format *pvr_format)
128{
129   VkFormatFeatureFlags flags = 0;
130
131   if (!pvr_format)
132      return 0;
133
134   return flags;
135}
136
137void pvr_GetPhysicalDeviceFormatProperties2(
138   VkPhysicalDevice physicalDevice,
139   VkFormat format,
140   VkFormatProperties2 *pFormatProperties)
141{
142   const struct pvr_format *pvr_format = pvr_get_format(format);
143
144   pFormatProperties->formatProperties = (VkFormatProperties){
145      .linearTilingFeatures =
146         pvr_get_image_format_features(pvr_format, VK_IMAGE_TILING_LINEAR),
147      .optimalTilingFeatures =
148         pvr_get_image_format_features(pvr_format, VK_IMAGE_TILING_OPTIMAL),
149      .bufferFeatures = pvr_get_buffer_format_features(pvr_format),
150   };
151
152   vk_foreach_struct (ext, pFormatProperties->pNext) {
153      pvr_debug_ignored_stype(ext->sType);
154   }
155}
156
157static VkResult
158pvr_get_image_format_properties(struct pvr_physical_device *pdevice,
159                                const VkPhysicalDeviceImageFormatInfo2 *info,
160                                VkImageFormatProperties *pImageFormatProperties)
161{
162   assert(!"Unimplemented");
163   return VK_SUCCESS;
164}
165
166VkResult pvr_GetPhysicalDeviceImageFormatProperties2(
167   VkPhysicalDevice physicalDevice,
168   const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo,
169   VkImageFormatProperties2 *pImageFormatProperties)
170{
171   const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL;
172   PVR_FROM_HANDLE(pvr_physical_device, pdevice, physicalDevice);
173   VkExternalImageFormatProperties *external_props = NULL;
174   VkResult result;
175
176   result = pvr_get_image_format_properties(
177      pdevice,
178      pImageFormatInfo,
179      &pImageFormatProperties->imageFormatProperties);
180   if (result != VK_SUCCESS)
181      return result;
182
183   /* Extract input structs */
184   vk_foreach_struct_const (ext, pImageFormatInfo->pNext) {
185      switch (ext->sType) {
186      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO:
187         external_info = (const void *)ext;
188         break;
189      default:
190         pvr_debug_ignored_stype(ext->sType);
191         break;
192      }
193   }
194
195   /* Extract output structs */
196   vk_foreach_struct (ext, pImageFormatProperties->pNext) {
197      switch (ext->sType) {
198      case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES:
199         external_props = (void *)ext;
200         break;
201      default:
202         pvr_debug_ignored_stype(ext->sType);
203         break;
204      }
205   }
206
207   /* From the Vulkan 1.0.42 spec:
208    *
209    *    If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will
210    *    behave as if VkPhysicalDeviceExternalImageFormatInfo was not
211    *    present and VkExternalImageFormatProperties will be ignored.
212    */
213   if (external_info && external_info->handleType != 0) {
214      switch (external_info->handleType) {
215      case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
216      case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
217         if (!external_props)
218            break;
219
220         external_props->externalMemoryProperties.externalMemoryFeatures =
221            VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
222            VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
223         external_props->externalMemoryProperties.compatibleHandleTypes =
224            VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
225            VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
226         external_props->externalMemoryProperties.exportFromImportedHandleTypes =
227            VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
228            VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
229         break;
230      default:
231         return vk_error(pdevice, VK_ERROR_FORMAT_NOT_SUPPORTED);
232      }
233   }
234
235   return VK_SUCCESS;
236}
237
238void pvr_GetPhysicalDeviceSparseImageFormatProperties(
239   VkPhysicalDevice physicalDevice,
240   VkFormat format,
241   VkImageType type,
242   uint32_t samples,
243   VkImageUsageFlags usage,
244   VkImageTiling tiling,
245   uint32_t *pNumProperties,
246   VkSparseImageFormatProperties *pProperties)
247{
248   /* Sparse images are not yet supported. */
249   *pNumProperties = 0;
250}
251
252void pvr_GetPhysicalDeviceSparseImageFormatProperties2(
253   VkPhysicalDevice physicalDevice,
254   const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo,
255   uint32_t *pPropertyCount,
256   VkSparseImageFormatProperties2 *pProperties)
257{
258   /* Sparse images are not yet supported. */
259   *pPropertyCount = 0;
260}
261
262void pvr_GetPhysicalDeviceExternalBufferProperties(
263   VkPhysicalDevice physicalDevice,
264   const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo,
265   VkExternalBufferProperties *pExternalBufferProperties)
266{
267   /* The Vulkan 1.0.42 spec says "handleType must be a valid
268    * VkExternalMemoryHandleTypeFlagBits value" in
269    * VkPhysicalDeviceExternalBufferInfo. This differs from
270    * VkPhysicalDeviceExternalImageFormatInfo, which surprisingly permits
271    * handleType == 0.
272    */
273   assert(pExternalBufferInfo->handleType != 0);
274
275   /* All of the current flags are for sparse which we don't support. */
276   if (pExternalBufferInfo->flags)
277      goto unsupported;
278
279   switch (pExternalBufferInfo->handleType) {
280   case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT:
281   case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT:
282      /* clang-format off */
283      pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures =
284         VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT |
285         VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT;
286      pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes =
287         VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
288         VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
289      pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes =
290         VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT |
291         VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
292      /* clang-format on */
293      return;
294   default:
295      break;
296   }
297
298unsupported:
299   /* From the Vulkan 1.1.113 spec:
300    *
301    *    compatibleHandleTypes must include at least handleType.
302    */
303   pExternalBufferProperties->externalMemoryProperties =
304      (VkExternalMemoryProperties){
305         .compatibleHandleTypes = pExternalBufferInfo->handleType,
306      };
307}
308
309bool pvr_format_is_pbe_downscalable(VkFormat vk_format)
310{
311   if (vk_format_is_int(vk_format)) {
312      /* PBE downscale behavior for integer formats does not match Vulkan
313       * spec. Vulkan requires a single sample to be chosen instead of
314       * taking the average sample color.
315       */
316      return false;
317   }
318
319   switch (pvr_get_pbe_packmode(vk_format)) {
320   default:
321      return true;
322
323   case ROGUE_PBESTATE_PACKMODE_U16U16U16U16:
324   case ROGUE_PBESTATE_PACKMODE_S16S16S16S16:
325   case ROGUE_PBESTATE_PACKMODE_U32U32U32U32:
326   case ROGUE_PBESTATE_PACKMODE_S32S32S32S32:
327   case ROGUE_PBESTATE_PACKMODE_F32F32F32F32:
328   case ROGUE_PBESTATE_PACKMODE_U16U16U16:
329   case ROGUE_PBESTATE_PACKMODE_S16S16S16:
330   case ROGUE_PBESTATE_PACKMODE_U32U32U32:
331   case ROGUE_PBESTATE_PACKMODE_S32S32S32:
332   case ROGUE_PBESTATE_PACKMODE_F32F32F32:
333   case ROGUE_PBESTATE_PACKMODE_U16U16:
334   case ROGUE_PBESTATE_PACKMODE_S16S16:
335   case ROGUE_PBESTATE_PACKMODE_U32U32:
336   case ROGUE_PBESTATE_PACKMODE_S32S32:
337   case ROGUE_PBESTATE_PACKMODE_F32F32:
338   case ROGUE_PBESTATE_PACKMODE_U24ST8:
339   case ROGUE_PBESTATE_PACKMODE_ST8U24:
340   case ROGUE_PBESTATE_PACKMODE_U16:
341   case ROGUE_PBESTATE_PACKMODE_S16:
342   case ROGUE_PBESTATE_PACKMODE_U32:
343   case ROGUE_PBESTATE_PACKMODE_S32:
344   case ROGUE_PBESTATE_PACKMODE_F32:
345   case ROGUE_PBESTATE_PACKMODE_X24U8F32:
346   case ROGUE_PBESTATE_PACKMODE_X24X8F32:
347   case ROGUE_PBESTATE_PACKMODE_X24G8X32:
348   case ROGUE_PBESTATE_PACKMODE_X8U24:
349   case ROGUE_PBESTATE_PACKMODE_U8X24:
350   case ROGUE_PBESTATE_PACKMODE_PBYTE:
351   case ROGUE_PBESTATE_PACKMODE_PWORD:
352   case ROGUE_PBESTATE_PACKMODE_INVALID:
353      return false;
354   }
355}
356