• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <assert.h>
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <string.h>
28 
29 #include "pvr_csb.h"
30 #include "pvr_device_info.h"
31 #include "pvr_formats.h"
32 #include "pvr_private.h"
33 #include "pvr_tex_state.h"
34 #include "util/macros.h"
35 #include "util/u_math.h"
36 #include "vk_format.h"
37 #include "vk_image.h"
38 #include "vk_log.h"
39 #include "vk_object.h"
40 #include "vk_util.h"
41 #include "wsi_common.h"
42 
pvr_image_init_memlayout(struct pvr_image * image)43 static void pvr_image_init_memlayout(struct pvr_image *image)
44 {
45    switch (image->vk.tiling) {
46    default:
47       unreachable("bad VkImageTiling");
48    case VK_IMAGE_TILING_OPTIMAL:
49       if (image->vk.wsi_legacy_scanout)
50          image->memlayout = PVR_MEMLAYOUT_LINEAR;
51       else if (image->vk.image_type == VK_IMAGE_TYPE_3D)
52          image->memlayout = PVR_MEMLAYOUT_3DTWIDDLED;
53       else
54          image->memlayout = PVR_MEMLAYOUT_TWIDDLED;
55       break;
56    case VK_IMAGE_TILING_LINEAR:
57       image->memlayout = PVR_MEMLAYOUT_LINEAR;
58       break;
59    }
60 }
61 
pvr_image_init_physical_extent(struct pvr_image * image)62 static void pvr_image_init_physical_extent(struct pvr_image *image)
63 {
64    assert(image->memlayout != PVR_MEMLAYOUT_UNDEFINED);
65 
66    /* clang-format off */
67    if (image->vk.mip_levels > 1 ||
68       image->memlayout == PVR_MEMLAYOUT_TWIDDLED ||
69       image->memlayout == PVR_MEMLAYOUT_3DTWIDDLED) {
70       /* clang-format on */
71       image->physical_extent.width =
72          util_next_power_of_two(image->vk.extent.width);
73       image->physical_extent.height =
74          util_next_power_of_two(image->vk.extent.height);
75       image->physical_extent.depth =
76          util_next_power_of_two(image->vk.extent.depth);
77    } else {
78       assert(image->memlayout == PVR_MEMLAYOUT_LINEAR);
79       image->physical_extent = image->vk.extent;
80    }
81 }
82 
pvr_image_setup_mip_levels(struct pvr_image * image)83 static void pvr_image_setup_mip_levels(struct pvr_image *image)
84 {
85    const uint32_t extent_alignment =
86       image->vk.image_type == VK_IMAGE_TYPE_3D ? 4 : 1;
87    const unsigned int cpp = vk_format_get_blocksize(image->vk.format);
88    VkExtent3D extent =
89       vk_image_extent_to_elements(&image->vk, image->physical_extent);
90 
91    assert(image->vk.mip_levels <= ARRAY_SIZE(image->mip_levels));
92 
93    image->layer_size = 0;
94 
95    for (uint32_t i = 0; i < image->vk.mip_levels; i++) {
96       struct pvr_mip_level *mip_level = &image->mip_levels[i];
97 
98       mip_level->pitch = cpp * ALIGN(extent.width, extent_alignment);
99       mip_level->height_pitch = ALIGN(extent.height, extent_alignment);
100       mip_level->size = image->vk.samples * mip_level->pitch *
101                         mip_level->height_pitch *
102                         ALIGN(extent.depth, extent_alignment);
103       mip_level->offset = image->layer_size;
104 
105       image->layer_size += mip_level->size;
106 
107       extent.height = u_minify(extent.height, 1);
108       extent.width = u_minify(extent.width, 1);
109       extent.depth = u_minify(extent.depth, 1);
110    }
111 
112    if (image->vk.mip_levels > 1) {
113       /* The hw calculates layer strides as if a full mip chain up until 1x1x1
114        * were present so we need to account for that in the `layer_size`.
115        */
116       while (extent.height != 1 || extent.width != 1 || extent.depth != 1) {
117          const uint32_t height_pitch = ALIGN(extent.height, extent_alignment);
118          const uint32_t pitch = cpp * ALIGN(extent.width, extent_alignment);
119 
120          image->layer_size += image->vk.samples * pitch * height_pitch *
121                               ALIGN(extent.depth, extent_alignment);
122 
123          extent.height = u_minify(extent.height, 1);
124          extent.width = u_minify(extent.width, 1);
125          extent.depth = u_minify(extent.depth, 1);
126       }
127    }
128 
129    /* TODO: It might be useful to store the alignment in the image so it can be
130     * checked (via an assert?) when setting
131     * RGX_CR_TPU_TAG_CEM_4K_FACE_PACKING_EN, assuming this is where the
132     * requirement comes from.
133     */
134    if (image->vk.array_layers > 1)
135       image->layer_size = align64(image->layer_size, image->alignment);
136 
137    image->size = image->layer_size * image->vk.array_layers;
138 }
139 
pvr_CreateImage(VkDevice _device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage)140 VkResult pvr_CreateImage(VkDevice _device,
141                          const VkImageCreateInfo *pCreateInfo,
142                          const VkAllocationCallbacks *pAllocator,
143                          VkImage *pImage)
144 {
145    PVR_FROM_HANDLE(pvr_device, device, _device);
146    struct pvr_image *image;
147 
148    image =
149       vk_image_create(&device->vk, pCreateInfo, pAllocator, sizeof(*image));
150    if (!image)
151       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
152 
153    /* All images aligned to 4k, in case of arrays/CEM.
154     * Refer: pvr_GetImageMemoryRequirements for further details.
155     */
156    image->alignment = 4096U;
157 
158    /* Initialize the image using the saved information from pCreateInfo */
159    pvr_image_init_memlayout(image);
160    pvr_image_init_physical_extent(image);
161    pvr_image_setup_mip_levels(image);
162 
163    *pImage = pvr_image_to_handle(image);
164 
165    return VK_SUCCESS;
166 }
167 
pvr_DestroyImage(VkDevice _device,VkImage _image,const VkAllocationCallbacks * pAllocator)168 void pvr_DestroyImage(VkDevice _device,
169                       VkImage _image,
170                       const VkAllocationCallbacks *pAllocator)
171 {
172    PVR_FROM_HANDLE(pvr_device, device, _device);
173    PVR_FROM_HANDLE(pvr_image, image, _image);
174 
175    if (!image)
176       return;
177 
178    if (image->vma)
179       pvr_unbind_memory(device, image->vma);
180 
181    vk_image_destroy(&device->vk, pAllocator, &image->vk);
182 }
183 
184 /* clang-format off */
185 /* Consider a 4 page buffer object.
186  *   _________________________________________
187  *  |         |          |         |          |
188  *  |_________|__________|_________|__________|
189  *                  |
190  *                  \__ offset (0.5 page size)
191  *
192  *                  |___size(2 pages)____|
193  *
194  *            |__VMA size required (3 pages)__|
195  *
196  *                  |
197  *                  \__ returned dev_addr = vma + offset % page_size
198  *
199  *   VMA size = align(size + offset % page_size, page_size);
200  *
201  *   Note: the above handling is currently divided between generic
202  *   driver code and winsys layer. Given are the details of how this is
203  *   being handled.
204  *   * As winsys vma allocation interface does not have offset information,
205  *     it can not calculate the extra size needed to adjust for the unaligned
206  *     offset. So generic code is responsible for allocating a VMA that has
207  *     extra space to deal with the above scenario.
208  *   * Remaining work of mapping the vma to bo is done by vma_map interface,
209  *     as it contains offset information, we don't need to do any adjustments
210  *     in the generic code for this part.
211  *
212  *  TODO: Look into merging heap_alloc and vma_map into single interface.
213  */
214 /* clang-format on */
215 
pvr_BindImageMemory2(VkDevice _device,uint32_t bindInfoCount,const VkBindImageMemoryInfo * pBindInfos)216 VkResult pvr_BindImageMemory2(VkDevice _device,
217                               uint32_t bindInfoCount,
218                               const VkBindImageMemoryInfo *pBindInfos)
219 {
220    PVR_FROM_HANDLE(pvr_device, device, _device);
221    uint32_t i;
222 
223    for (i = 0; i < bindInfoCount; i++) {
224       PVR_FROM_HANDLE(pvr_device_memory, mem, pBindInfos[i].memory);
225       PVR_FROM_HANDLE(pvr_image, image, pBindInfos[i].image);
226 
227       VkResult result = pvr_bind_memory(device,
228                                         mem,
229                                         pBindInfos[i].memoryOffset,
230                                         image->size,
231                                         image->alignment,
232                                         &image->vma,
233                                         &image->dev_addr);
234       if (result != VK_SUCCESS) {
235          while (i--) {
236             PVR_FROM_HANDLE(pvr_image, image, pBindInfos[i].image);
237 
238             pvr_unbind_memory(device, image->vma);
239          }
240 
241          return result;
242       }
243    }
244 
245    return VK_SUCCESS;
246 }
247 
pvr_get_image_subresource_layout(const struct pvr_image * image,const VkImageSubresource * subresource,VkSubresourceLayout * layout)248 void pvr_get_image_subresource_layout(const struct pvr_image *image,
249                                       const VkImageSubresource *subresource,
250                                       VkSubresourceLayout *layout)
251 {
252    const struct pvr_mip_level *mip_level =
253       &image->mip_levels[subresource->mipLevel];
254 
255    pvr_assert(subresource->mipLevel < image->vk.mip_levels);
256    pvr_assert(subresource->arrayLayer < image->vk.array_layers);
257 
258    layout->offset =
259       subresource->arrayLayer * image->layer_size + mip_level->offset;
260    layout->rowPitch = mip_level->pitch;
261    layout->depthPitch = mip_level->pitch * mip_level->height_pitch;
262    layout->arrayPitch = image->layer_size;
263    layout->size = mip_level->size;
264 }
265 
pvr_GetImageSubresourceLayout(VkDevice device,VkImage _image,const VkImageSubresource * subresource,VkSubresourceLayout * layout)266 void pvr_GetImageSubresourceLayout(VkDevice device,
267                                    VkImage _image,
268                                    const VkImageSubresource *subresource,
269                                    VkSubresourceLayout *layout)
270 {
271    PVR_FROM_HANDLE(pvr_image, image, _image);
272 
273    pvr_get_image_subresource_layout(image, subresource, layout);
274 }
275 
pvr_adjust_non_compressed_view(const struct pvr_image * image,struct pvr_texture_state_info * info)276 static void pvr_adjust_non_compressed_view(const struct pvr_image *image,
277                                            struct pvr_texture_state_info *info)
278 {
279    const uint32_t base_level = info->base_level;
280 
281    if (!vk_format_is_compressed(image->vk.format) ||
282        vk_format_is_compressed(info->format)) {
283       return;
284    }
285 
286    /* Cannot use the image state, as the miplevel sizes for an
287     * uncompressed chain view may not decrease by 2 each time compared to the
288     * compressed one e.g. (22x22,11x11,5x5) -> (6x6,3x3,2x2)
289     * Instead manually apply an offset and patch the size
290     */
291    info->extent.width = u_minify(info->extent.width, base_level);
292    info->extent.height = u_minify(info->extent.height, base_level);
293    info->extent.depth = u_minify(info->extent.depth, base_level);
294    info->extent = vk_image_extent_to_elements(&image->vk, info->extent);
295    info->offset += image->mip_levels[base_level].offset;
296    info->base_level = 0;
297 }
298 
pvr_CreateImageView(VkDevice _device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView)299 VkResult pvr_CreateImageView(VkDevice _device,
300                              const VkImageViewCreateInfo *pCreateInfo,
301                              const VkAllocationCallbacks *pAllocator,
302                              VkImageView *pView)
303 {
304    PVR_FROM_HANDLE(pvr_device, device, _device);
305    struct pvr_texture_state_info info;
306    unsigned char input_swizzle[4];
307    const uint8_t *format_swizzle;
308    const struct pvr_image *image;
309    struct pvr_image_view *iview;
310    VkResult result;
311 
312    iview = vk_image_view_create(&device->vk,
313                                 false /* driver_internal */,
314                                 pCreateInfo,
315                                 pAllocator,
316                                 sizeof(*iview));
317    if (!iview)
318       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
319 
320    image = pvr_image_view_get_image(iview);
321 
322    info.type = iview->vk.view_type;
323    info.base_level = iview->vk.base_mip_level;
324    info.mip_levels = iview->vk.level_count;
325    info.extent = image->vk.extent;
326    info.aspect_mask = image->vk.aspects;
327    info.is_cube = (info.type == VK_IMAGE_VIEW_TYPE_CUBE ||
328                    info.type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
329    info.array_size = iview->vk.layer_count;
330    info.offset = iview->vk.base_array_layer * image->layer_size;
331    info.mipmaps_present = (image->vk.mip_levels > 1) ? true : false;
332    info.stride = image->physical_extent.width;
333    info.tex_state_type = PVR_TEXTURE_STATE_SAMPLE;
334    info.mem_layout = image->memlayout;
335    info.flags = 0;
336    info.sample_count = image->vk.samples;
337    info.addr = image->dev_addr;
338 
339    info.format = pCreateInfo->format;
340 
341    pvr_adjust_non_compressed_view(image, &info);
342 
343    vk_component_mapping_to_pipe_swizzle(iview->vk.swizzle, input_swizzle);
344    format_swizzle = pvr_get_format_swizzle(info.format);
345    util_format_compose_swizzles(format_swizzle, input_swizzle, info.swizzle);
346 
347    result = pvr_pack_tex_state(device,
348                                &info,
349                                iview->texture_state[info.tex_state_type]);
350    if (result != VK_SUCCESS)
351       goto err_vk_image_view_destroy;
352 
353    /* Create an additional texture state for cube type if storage
354     * usage flag is set.
355     */
356    if (info.is_cube && image->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) {
357       info.tex_state_type = PVR_TEXTURE_STATE_STORAGE;
358 
359       result = pvr_pack_tex_state(device,
360                                   &info,
361                                   iview->texture_state[info.tex_state_type]);
362       if (result != VK_SUCCESS)
363          goto err_vk_image_view_destroy;
364    }
365 
366    if (image->vk.usage & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
367       /* Attachment state is created as if the mipmaps are not supported, so the
368        * baselevel is set to zero and num_mip_levels is set to 1. Which gives an
369        * impression that this is the only level in the image. This also requires
370        * that width, height and depth be adjusted as well. Given
371        * iview->vk.extent is already adjusted for base mip map level we use it
372        * here.
373        */
374       /* TODO: Investigate and document the reason for above approach. */
375       info.extent = iview->vk.extent;
376 
377       info.mip_levels = 1;
378       info.mipmaps_present = false;
379       info.stride = u_minify(image->physical_extent.width, info.base_level);
380       info.base_level = 0;
381       info.tex_state_type = PVR_TEXTURE_STATE_ATTACHMENT;
382 
383       if (image->vk.image_type == VK_IMAGE_TYPE_3D &&
384           iview->vk.view_type == VK_IMAGE_VIEW_TYPE_2D) {
385          info.type = VK_IMAGE_VIEW_TYPE_3D;
386       } else {
387          info.type = iview->vk.view_type;
388       }
389 
390       result = pvr_pack_tex_state(device,
391                                   &info,
392                                   iview->texture_state[info.tex_state_type]);
393       if (result != VK_SUCCESS)
394          goto err_vk_image_view_destroy;
395    }
396 
397    *pView = pvr_image_view_to_handle(iview);
398 
399    return VK_SUCCESS;
400 
401 err_vk_image_view_destroy:
402    vk_image_view_destroy(&device->vk, pAllocator, &iview->vk);
403 
404    return result;
405 }
406 
pvr_DestroyImageView(VkDevice _device,VkImageView _iview,const VkAllocationCallbacks * pAllocator)407 void pvr_DestroyImageView(VkDevice _device,
408                           VkImageView _iview,
409                           const VkAllocationCallbacks *pAllocator)
410 {
411    PVR_FROM_HANDLE(pvr_device, device, _device);
412    PVR_FROM_HANDLE(pvr_image_view, iview, _iview);
413 
414    if (!iview)
415       return;
416 
417    vk_image_view_destroy(&device->vk, pAllocator, &iview->vk);
418 }
419 
pvr_CreateBufferView(VkDevice _device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pView)420 VkResult pvr_CreateBufferView(VkDevice _device,
421                               const VkBufferViewCreateInfo *pCreateInfo,
422                               const VkAllocationCallbacks *pAllocator,
423                               VkBufferView *pView)
424 {
425    PVR_FROM_HANDLE(pvr_buffer, buffer, pCreateInfo->buffer);
426    PVR_FROM_HANDLE(pvr_device, device, _device);
427    struct pvr_texture_state_info info;
428    const uint8_t *format_swizzle;
429    struct pvr_buffer_view *bview;
430    VkResult result;
431 
432    bview = vk_buffer_view_create(&device->vk,
433                                  pCreateInfo,
434                                  pAllocator,
435                                  sizeof(*bview));
436    if (!bview)
437       return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
438 
439    /* If the remaining size of the buffer is not a multiple of the element
440     * size of the format, the nearest smaller multiple is used.
441     */
442    bview->vk.range -=
443       bview->vk.range % vk_format_get_blocksize(bview->vk.format);
444 
445    /* The range of the buffer view shouldn't be smaller than one texel. */
446    assert(bview->vk.range >= vk_format_get_blocksize(bview->vk.format));
447 
448    info.base_level = 0U;
449    info.mip_levels = 1U;
450    info.mipmaps_present = false;
451    info.extent.width = 8192U;
452    info.extent.height = bview->vk.elements;
453    info.extent.height = DIV_ROUND_UP(info.extent.height, info.extent.width);
454    info.extent.depth = 0U;
455    info.sample_count = 1U;
456    info.stride = info.extent.width;
457    info.offset = 0U;
458    info.addr = PVR_DEV_ADDR_OFFSET(buffer->dev_addr, pCreateInfo->offset);
459    info.mem_layout = PVR_MEMLAYOUT_LINEAR;
460    info.is_cube = false;
461    info.type = VK_IMAGE_VIEW_TYPE_2D;
462    info.tex_state_type = PVR_TEXTURE_STATE_SAMPLE;
463    info.format = bview->vk.format;
464    info.flags = PVR_TEXFLAGS_INDEX_LOOKUP;
465    info.aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
466 
467    if (PVR_HAS_FEATURE(&device->pdevice->dev_info, tpu_array_textures))
468       info.array_size = 1U;
469 
470    format_swizzle = pvr_get_format_swizzle(info.format);
471    memcpy(info.swizzle, format_swizzle, sizeof(info.swizzle));
472 
473    result = pvr_pack_tex_state(device, &info, bview->texture_state);
474    if (result != VK_SUCCESS)
475       goto err_vk_buffer_view_destroy;
476 
477    *pView = pvr_buffer_view_to_handle(bview);
478 
479    return VK_SUCCESS;
480 
481 err_vk_buffer_view_destroy:
482    vk_object_free(&device->vk, pAllocator, bview);
483 
484    return result;
485 }
486 
pvr_DestroyBufferView(VkDevice _device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator)487 void pvr_DestroyBufferView(VkDevice _device,
488                            VkBufferView bufferView,
489                            const VkAllocationCallbacks *pAllocator)
490 {
491    PVR_FROM_HANDLE(pvr_buffer_view, bview, bufferView);
492    PVR_FROM_HANDLE(pvr_device, device, _device);
493 
494    if (!bview)
495       return;
496 
497    vk_buffer_view_destroy(&device->vk, pAllocator, &bview->vk);
498 }
499