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 VKAPI_ATTR VkResult VKAPI_CALL
panvk_per_arch(CreateImageView)74 panvk_per_arch(CreateImageView)(VkDevice _device,
75 const VkImageViewCreateInfo *pCreateInfo,
76 const VkAllocationCallbacks *pAllocator,
77 VkImageView *pView)
78 {
79 VK_FROM_HANDLE(panvk_device, device, _device);
80 VK_FROM_HANDLE(panvk_image, image, pCreateInfo->image);
81 bool driver_internal =
82 (pCreateInfo->flags & VK_IMAGE_VIEW_CREATE_DRIVER_INTERNAL_BIT_MESA) != 0;
83 struct panvk_image_view *view;
84
85 view = vk_image_view_create(&device->vk, driver_internal, pCreateInfo,
86 pAllocator, sizeof(*view));
87 if (view == NULL)
88 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
89
90 view->pview = (struct pan_image_view){
91 .planes[0] = &image->pimage,
92 .format = vk_format_to_pipe_format(view->vk.view_format),
93 .dim = panvk_view_type_to_mali_tex_dim(view->vk.view_type),
94 .nr_samples = image->pimage.layout.nr_samples,
95 .first_level = view->vk.base_mip_level,
96 .last_level = view->vk.base_mip_level + view->vk.level_count - 1,
97 .first_layer = view->vk.base_array_layer,
98 .last_layer = view->vk.base_array_layer + view->vk.layer_count - 1,
99 };
100 panvk_convert_swizzle(&view->vk.swizzle, view->pview.swizzle);
101
102 /* We need to patch the view format when the image contains both
103 * depth and stencil but the view only contains one of these components, so
104 * we can ignore the component we don't use.
105 */
106 if (vk_format_is_depth_or_stencil(view->vk.view_format)) {
107 if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
108 view->vk.view_format != VK_FORMAT_D32_SFLOAT_S8_UINT)
109 view->pview.format = view->vk.view_format == VK_FORMAT_D32_SFLOAT
110 ? PIPE_FORMAT_Z32_FLOAT_S8X24_UINT
111 : PIPE_FORMAT_X32_S8X24_UINT;
112
113 if (image->vk.format == VK_FORMAT_D24_UNORM_S8_UINT &&
114 view->vk.view_format == VK_FORMAT_S8_UINT)
115 view->pview.format = PIPE_FORMAT_X24S8_UINT;
116
117 if (image->vk.format == VK_FORMAT_D32_SFLOAT_S8_UINT &&
118 view->vk.view_format == VK_FORMAT_S8_UINT)
119 view->pview.format = PIPE_FORMAT_X32_S8X24_UINT;
120 }
121
122 VkImageUsageFlags tex_usage_mask =
123 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
124
125 #if PAN_ARCH >= 9
126 /* Valhall passes a texture descriptor to LEA_TEX. */
127 tex_usage_mask |= VK_IMAGE_USAGE_STORAGE_BIT;
128 #endif
129
130 if (view->vk.usage & tex_usage_mask) {
131 /* Use a temporary pan_image_view so we can tweak it for texture
132 * descriptor emission without changing the original definition.
133 */
134 struct pan_image_view pview = view->pview;
135
136 if (util_format_is_depth_or_stencil(view->pview.format)) {
137 /* Vulkan wants R001, where the depth/stencil is stored in the red
138 * component, but the pan_format/texture logic gives us RRRR.
139 * Tweak the swizzle so we get what Vulkan wants.
140 */
141 static const unsigned char r001[4] = {
142 PIPE_SWIZZLE_X,
143 PIPE_SWIZZLE_0,
144 PIPE_SWIZZLE_0,
145 PIPE_SWIZZLE_1,
146 };
147
148 util_format_compose_swizzles(r001, view->pview.swizzle, pview.swizzle);
149 }
150
151 struct panvk_pool_alloc_info alloc_info = {
152 .alignment = pan_alignment(TEXTURE),
153 .size = GENX(panfrost_estimate_texture_payload_size)(&pview),
154 };
155
156 view->mem = panvk_pool_alloc_mem(&device->mempools.rw, alloc_info);
157
158 struct panfrost_ptr ptr = {
159 .gpu = panvk_priv_mem_dev_addr(view->mem),
160 .cpu = panvk_priv_mem_host_addr(view->mem),
161 };
162
163 GENX(panfrost_new_texture)(&pview, view->descs.tex.opaque, &ptr);
164 }
165
166 #if PAN_ARCH <= 7
167 if (view->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) {
168 bool is_3d = image->pimage.layout.dim == MALI_TEXTURE_DIMENSION_3D;
169 unsigned offset = image->pimage.data.offset;
170 offset +=
171 panfrost_texture_offset(&image->pimage.layout, view->pview.first_level,
172 is_3d ? 0 : view->pview.first_layer,
173 is_3d ? view->pview.first_layer : 0);
174
175 pan_pack(view->descs.img_attrib_buf[0].opaque, ATTRIBUTE_BUFFER, cfg) {
176 /* The format is the only thing we lack to emit attribute descriptors
177 * when copying from the set to the attribute tables. Instead of
178 * making the descriptor size to store an extra format, we pack
179 * the 22-bit format with the texel stride, which is expected to be
180 * fit in remaining 10 bits.
181 */
182 uint32_t fmt_blksize = util_format_get_blocksize(view->pview.format);
183 uint32_t hw_fmt =
184 GENX(panfrost_format_from_pipe_format)(view->pview.format)->hw;
185
186 assert(fmt_blksize < BITFIELD_MASK(10));
187 assert(hw_fmt < BITFIELD_MASK(22));
188
189 cfg.type = image->pimage.layout.modifier == DRM_FORMAT_MOD_LINEAR
190 ? MALI_ATTRIBUTE_TYPE_3D_LINEAR
191 : MALI_ATTRIBUTE_TYPE_3D_INTERLEAVED;
192 cfg.pointer = image->pimage.data.base + offset;
193 cfg.stride = fmt_blksize | (hw_fmt << 10);
194 cfg.size = pan_kmod_bo_size(image->bo) - offset;
195 }
196
197 pan_pack(view->descs.img_attrib_buf[1].opaque,
198 ATTRIBUTE_BUFFER_CONTINUATION_3D, cfg) {
199 unsigned level = view->pview.first_level;
200 VkExtent3D extent = view->vk.extent;
201
202 cfg.s_dimension = extent.width;
203 cfg.t_dimension = extent.height;
204 cfg.r_dimension =
205 view->pview.dim == MALI_TEXTURE_DIMENSION_3D
206 ? extent.depth
207 : (view->pview.last_layer - view->pview.first_layer + 1);
208 cfg.row_stride = image->pimage.layout.slices[level].row_stride;
209 if (cfg.r_dimension > 1) {
210 cfg.slice_stride =
211 panfrost_get_layer_stride(&image->pimage.layout, level);
212 }
213 }
214 }
215 #endif
216
217 *pView = panvk_image_view_to_handle(view);
218 return VK_SUCCESS;
219 }
220
221 VKAPI_ATTR void VKAPI_CALL
panvk_per_arch(DestroyImageView)222 panvk_per_arch(DestroyImageView)(VkDevice _device, VkImageView _view,
223 const VkAllocationCallbacks *pAllocator)
224 {
225 VK_FROM_HANDLE(panvk_device, device, _device);
226 VK_FROM_HANDLE(panvk_image_view, view, _view);
227
228 if (!view)
229 return;
230
231 panvk_pool_free_mem(&device->mempools.rw, view->mem);
232 vk_image_view_destroy(&device->vk, pAllocator, &view->vk);
233 }
234