• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2021 Collabora Ltd.
3  *
4  * Derived from tu_image.c which is:
5  * Copyright © 2016 Red Hat.
6  * Copyright © 2016 Bas Nieuwenhuizen
7  * Copyright © 2015 Intel Corporation
8  *
9  * SPDX-License-Identifier: MIT
10  */
11 
12 #include "vk_format.h"
13 #include "vk_log.h"
14 
15 #include "panvk_device.h"
16 #include "panvk_entrypoints.h"
17 #include "panvk_image.h"
18 #include "panvk_image_view.h"
19 #include "panvk_priv_bo.h"
20 
21 #include "genxml/gen_macros.h"
22 
23 static enum mali_texture_dimension
panvk_view_type_to_mali_tex_dim(VkImageViewType type)24 panvk_view_type_to_mali_tex_dim(VkImageViewType type)
25 {
26    switch (type) {
27    case VK_IMAGE_VIEW_TYPE_1D:
28    case VK_IMAGE_VIEW_TYPE_1D_ARRAY:
29       return MALI_TEXTURE_DIMENSION_1D;
30    case VK_IMAGE_VIEW_TYPE_2D:
31    case VK_IMAGE_VIEW_TYPE_2D_ARRAY:
32       return MALI_TEXTURE_DIMENSION_2D;
33    case VK_IMAGE_VIEW_TYPE_3D:
34       return MALI_TEXTURE_DIMENSION_3D;
35    case VK_IMAGE_VIEW_TYPE_CUBE:
36    case VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
37       return MALI_TEXTURE_DIMENSION_CUBE;
38    default:
39       unreachable("Invalid view type");
40    }
41 }
42 
43 static void
panvk_convert_swizzle(const VkComponentMapping * in,unsigned char * out)44 panvk_convert_swizzle(const VkComponentMapping *in, unsigned char *out)
45 {
46    const VkComponentSwizzle *comp = &in->r;
47    for (unsigned i = 0; i < 4; i++) {
48       switch (comp[i]) {
49       case VK_COMPONENT_SWIZZLE_ZERO:
50          out[i] = PIPE_SWIZZLE_0;
51          break;
52       case VK_COMPONENT_SWIZZLE_ONE:
53          out[i] = PIPE_SWIZZLE_1;
54          break;
55       case VK_COMPONENT_SWIZZLE_R:
56          out[i] = PIPE_SWIZZLE_X;
57          break;
58       case VK_COMPONENT_SWIZZLE_G:
59          out[i] = PIPE_SWIZZLE_Y;
60          break;
61       case VK_COMPONENT_SWIZZLE_B:
62          out[i] = PIPE_SWIZZLE_Z;
63          break;
64       case VK_COMPONENT_SWIZZLE_A:
65          out[i] = PIPE_SWIZZLE_W;
66          break;
67       default:
68          unreachable("Invalid swizzle");
69       }
70    }
71 }
72 
73 static VkResult
prepare_tex_descs(struct panvk_image_view * view)74 prepare_tex_descs(struct panvk_image_view *view)
75 {
76    /* Use a temporary pan_image_view so we can tweak it for texture
77     * descriptor emission without changing the original definition.
78     */
79    struct pan_image_view pview = view->pview;
80    struct panvk_image *image =
81       container_of(view->vk.image, struct panvk_image, vk);
82    struct panvk_device *dev = to_panvk_device(view->vk.base.device);
83    bool can_preload_other_aspect =
84       (view->vk.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
85       (image->vk.format == VK_FORMAT_D24_UNORM_S8_UINT ||
86        (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
87         view->vk.aspects ==
88            (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)));
89 
90    if (util_format_is_depth_or_stencil(view->pview.format)) {
91       /* Vulkan wants R001, where the depth/stencil is stored in the red
92        * component. Tweak the swizzle so we get what Vulkan wants.
93        */
94       static const unsigned char r001[4] = {
95          PIPE_SWIZZLE_X,
96          PIPE_SWIZZLE_0,
97          PIPE_SWIZZLE_0,
98          PIPE_SWIZZLE_1,
99       };
100 
101       util_format_compose_swizzles(r001, view->pview.swizzle, pview.swizzle);
102    }
103 #if PAN_ARCH == 7
104    /* v7 requires AFBC reswizzle. */
105    else if (!panfrost_format_is_yuv(view->pview.format) &&
106             panfrost_format_supports_afbc(PAN_ARCH, view->pview.format))
107       GENX(panfrost_texture_afbc_reswizzle)(&pview);
108 #endif
109 
110    /* If the view contains both stencil and depth, we need to keep only the
111     * depth. We'll create another texture with only the stencil.
112     */
113    if (pview.format == PIPE_FORMAT_Z32_FLOAT_S8X24_UINT)
114       pview.format = PIPE_FORMAT_Z32_FLOAT;
115 
116    struct panvk_pool_alloc_info alloc_info = {
117 #if PAN_ARCH == 6
118       .alignment = pan_alignment(SURFACE_WITH_STRIDE),
119 #elif PAN_ARCH == 7
120       .alignment = pan_alignment(MULTIPLANAR_SURFACE),
121 #else
122       .alignment = pan_alignment(PLANE),
123 #endif
124 
125       .size = GENX(panfrost_estimate_texture_payload_size)(&pview) *
126               (can_preload_other_aspect ? 2 : 1),
127    };
128 
129    view->mem = panvk_pool_alloc_mem(&dev->mempools.rw, alloc_info);
130    if (!panvk_priv_mem_host_addr(view->mem))
131       return panvk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
132 
133    struct panfrost_ptr ptr = {
134       .gpu = panvk_priv_mem_dev_addr(view->mem),
135       .cpu = panvk_priv_mem_host_addr(view->mem),
136    };
137 
138    GENX(panfrost_new_texture)(&pview, &view->descs.tex, &ptr);
139 
140    if (!can_preload_other_aspect)
141       return VK_SUCCESS;
142 
143    switch (pview.format) {
144    case PIPE_FORMAT_Z24X8_UNORM:
145    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
146       pview.format = PIPE_FORMAT_X24S8_UINT;
147       break;
148    case PIPE_FORMAT_X24S8_UINT:
149       pview.format = PIPE_FORMAT_Z24X8_UNORM;
150       break;
151    case PIPE_FORMAT_Z32_FLOAT:
152       pview.format = PIPE_FORMAT_S8_UINT;
153       break;
154    case PIPE_FORMAT_S8_UINT:
155       pview.format = PIPE_FORMAT_Z32_FLOAT;
156       break;
157    default:
158       assert(!"Invalid format");
159    }
160 
161    ptr.cpu += alloc_info.size / 2;
162    ptr.gpu += alloc_info.size / 2;
163 
164    GENX(panfrost_new_texture)(&pview, &view->descs.other_aspect_tex, &ptr);
165    return VK_SUCCESS;
166 }
167 
168 #if PAN_ARCH <= 7
169 static void
prepare_attr_buf_descs(struct panvk_image_view * view)170 prepare_attr_buf_descs(struct panvk_image_view *view)
171 {
172    struct panvk_image *image =
173       container_of(view->vk.image, struct panvk_image, vk);
174    unsigned plane_idx = 0;
175 
176    /* Stencil is on plane 1 in a D32_S8 image. The special color case is for
177     * vk_meta copies which create color views of depth/stencil images. In
178     * that case, we base the stencil vs depth detection on the format block
179     * size.
180     */
181    if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
182        (view->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT ||
183         (view->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT &&
184          vk_format_get_blocksize(view->vk.view_format) == 1)))
185       plane_idx = 1;
186 
187    bool is_3d =
188       image->planes[plane_idx].layout.dim == MALI_TEXTURE_DIMENSION_3D;
189    unsigned offset = image->planes[plane_idx].data.offset;
190    offset += panfrost_texture_offset(
191       &image->planes[plane_idx].layout, view->pview.first_level,
192       is_3d ? 0 : view->pview.first_layer, is_3d ? view->pview.first_layer : 0);
193 
194    pan_pack(&view->descs.img_attrib_buf[0], ATTRIBUTE_BUFFER, cfg) {
195       /* The format is the only thing we lack to emit attribute descriptors
196        * when copying from the set to the attribute tables. Instead of
197        * making the descriptor size to store an extra format, we pack
198        * the 22-bit format with the texel stride, which is expected to be
199        * fit in remaining 10 bits.
200        */
201       uint32_t fmt_blksize = util_format_get_blocksize(view->pview.format);
202       uint32_t hw_fmt =
203          GENX(panfrost_format_from_pipe_format)(view->pview.format)->hw;
204 
205       assert(fmt_blksize < BITFIELD_MASK(10));
206       assert(hw_fmt < BITFIELD_MASK(22));
207 
208       cfg.type = image->vk.drm_format_mod == DRM_FORMAT_MOD_LINEAR
209                     ? MALI_ATTRIBUTE_TYPE_3D_LINEAR
210                     : MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED;
211       cfg.pointer = image->planes[plane_idx].data.base + offset;
212       cfg.stride = fmt_blksize | (hw_fmt << 10);
213       cfg.size = pan_kmod_bo_size(image->bo) - offset;
214    }
215 
216    struct mali_attribute_buffer_packed *buf = &view->descs.img_attrib_buf[1];
217    pan_cast_and_pack(buf, ATTRIBUTE_BUFFER_CONTINUATION_3D, cfg) {
218       unsigned level = view->pview.first_level;
219       VkExtent3D extent = view->vk.extent;
220 
221       cfg.s_dimension = extent.width;
222       cfg.t_dimension = extent.height;
223       cfg.r_dimension =
224          view->pview.dim == MALI_TEXTURE_DIMENSION_3D
225             ? extent.depth
226             : (view->pview.last_layer - view->pview.first_layer + 1);
227       cfg.row_stride = image->planes[plane_idx].layout.slices[level].row_stride;
228       if (cfg.r_dimension > 1) {
229          cfg.slice_stride =
230             panfrost_get_layer_stride(&image->planes[plane_idx].layout, level);
231       }
232    }
233 }
234 #endif
235 
236 VKAPI_ATTR VkResult VKAPI_CALL
panvk_per_arch(CreateImageView)237 panvk_per_arch(CreateImageView)(VkDevice _device,
238                                 const VkImageViewCreateInfo *pCreateInfo,
239                                 const VkAllocationCallbacks *pAllocator,
240                                 VkImageView *pView)
241 {
242    VK_FROM_HANDLE(panvk_device, device, _device);
243    VK_FROM_HANDLE(panvk_image, image, pCreateInfo->image);
244    bool driver_internal =
245       (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA) != 0;
246    struct panvk_image_view *view;
247    VkResult result;
248 
249    view = vk_image_view_create(&device->vk, driver_internal, pCreateInfo,
250                                pAllocator, sizeof(*view));
251    if (view == NULL)
252       return panvk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
253 
254    view->pview = (struct pan_image_view){
255       .format = vk_format_to_pipe_format(view->vk.view_format),
256       .dim = panvk_view_type_to_mali_tex_dim(view->vk.view_type),
257       .nr_samples = image->vk.samples,
258       .first_level = view->vk.base_mip_level,
259       .last_level = view->vk.base_mip_level + view->vk.level_count - 1,
260       .first_layer = view->vk.base_array_layer,
261       .last_layer = view->vk.base_array_layer + view->vk.layer_count - 1,
262    };
263    panvk_convert_swizzle(&view->vk.swizzle, view->pview.swizzle);
264 
265    u_foreach_bit(aspect_bit, view->vk.aspects) {
266       uint8_t image_plane =
267          panvk_plane_index(image->vk.format, 1u << aspect_bit);
268       view->pview.planes[image_plane] = &image->planes[image_plane];
269    }
270 
271    /* Depth/stencil are viewed as color for copies. */
272    if (view->vk.aspects == VK_IMAGE_ASPECT_COLOR_BIT &&
273        image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
274        vk_format_get_blocksize(view->vk.view_format) == 1) {
275       view->pview.planes[0] = &image->planes[1];
276    }
277 
278    /* We need to patch the view format when the image contains both
279     * depth and stencil but the view only contains one of these components, so
280     * we can ignore the component we don't use.
281     */
282    if (view->vk.view_format == VK_FORMAT_S8_UINT &&
283        image->vk.format == VK_FORMAT_D24_UNORM_S8_UINT)
284       view->pview.format = PIPE_FORMAT_X24S8_UINT;
285 
286    /* Attachments need a texture for the FB preload logic. */
287    VkImageUsageFlags tex_usage_mask =
288       VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
289       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
290       VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
291 
292 #if PAN_ARCH >= 9
293    /* Valhall passes a texture descriptor to LEA_TEX. */
294    tex_usage_mask |= VK_IMAGE_USAGE_STORAGE_BIT;
295 #endif
296 
297    if (view->vk.usage & tex_usage_mask) {
298       result = prepare_tex_descs(view);
299       if (result != VK_SUCCESS)
300          goto err_destroy_iview;
301    }
302 
303 #if PAN_ARCH <= 7
304    if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT)
305       prepare_attr_buf_descs(view);
306 #endif
307 
308    *pView = panvk_image_view_to_handle(view);
309    return VK_SUCCESS;
310 
311 err_destroy_iview:
312    vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
313    return result;
314 }
315 
316 VKAPI_ATTR void VKAPI_CALL
panvk_per_arch(DestroyImageView)317 panvk_per_arch(DestroyImageView)(VkDevice _device, VkImageView _view,
318                                  const VkAllocationCallbacks *pAllocator)
319 {
320    VK_FROM_HANDLE(panvk_device, device, _device);
321    VK_FROM_HANDLE(panvk_image_view, view, _view);
322 
323    if (!view)
324       return;
325 
326    panvk_pool_free_mem(&view->mem);
327    vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
328 }
329