1 /* Copyright © 2024 Intel Corporation
2 * SPDX-License-Identifier: MIT
3 */
4
5 #include "anv_private.h"
6
7 static enum isl_channel_select
remap_swizzle(VkComponentSwizzle swizzle,struct isl_swizzle format_swizzle)8 remap_swizzle(VkComponentSwizzle swizzle,
9 struct isl_swizzle format_swizzle)
10 {
11 switch (swizzle) {
12 case VK_COMPONENT_SWIZZLE_ZERO: return ISL_CHANNEL_SELECT_ZERO;
13 case VK_COMPONENT_SWIZZLE_ONE: return ISL_CHANNEL_SELECT_ONE;
14 case VK_COMPONENT_SWIZZLE_R: return format_swizzle.r;
15 case VK_COMPONENT_SWIZZLE_G: return format_swizzle.g;
16 case VK_COMPONENT_SWIZZLE_B: return format_swizzle.b;
17 case VK_COMPONENT_SWIZZLE_A: return format_swizzle.a;
18 default:
19 unreachable("Invalid swizzle");
20 }
21 }
22
23 void
anv_image_fill_surface_state(struct anv_device * device,const struct anv_image * image,VkImageAspectFlagBits aspect,const struct isl_view * view_in,isl_surf_usage_flags_t view_usage,enum isl_aux_usage aux_usage,const union isl_color_value * clear_color,enum anv_image_view_state_flags flags,struct anv_surface_state * state_inout)24 anv_image_fill_surface_state(struct anv_device *device,
25 const struct anv_image *image,
26 VkImageAspectFlagBits aspect,
27 const struct isl_view *view_in,
28 isl_surf_usage_flags_t view_usage,
29 enum isl_aux_usage aux_usage,
30 const union isl_color_value *clear_color,
31 enum anv_image_view_state_flags flags,
32 struct anv_surface_state *state_inout)
33 {
34 uint32_t plane = anv_image_aspect_to_plane(image, aspect);
35 if (image->emu_plane_format != VK_FORMAT_UNDEFINED) {
36 const uint16_t view_bpb = isl_format_get_layout(view_in->format)->bpb;
37 const uint16_t plane_bpb = isl_format_get_layout(
38 image->planes[plane].primary_surface.isl.format)->bpb;
39
40 /* We should redirect to the hidden plane when the original view format
41 * is compressed or when the view usage is storage. But we don't always
42 * have visibility to the original view format so we also check for size
43 * compatibility.
44 */
45 if (isl_format_is_compressed(view_in->format) ||
46 (view_usage & ISL_SURF_USAGE_STORAGE_BIT) ||
47 view_bpb != plane_bpb) {
48 plane = image->n_planes;
49 assert(isl_format_get_layout(
50 image->planes[plane].primary_surface.isl.format)->bpb ==
51 view_bpb);
52 }
53 }
54
55 const struct anv_surface *surface = &image->planes[plane].primary_surface,
56 *aux_surface = &image->planes[plane].aux_surface;
57
58 struct isl_view view = *view_in;
59 view.usage |= view_usage;
60
61 /* Propagate the protection flag of the image to the view. */
62 view_usage |= surface->isl.usage & ISL_SURF_USAGE_PROTECTED_BIT;
63
64 if (view_usage == ISL_SURF_USAGE_RENDER_TARGET_BIT)
65 view.swizzle = anv_swizzle_for_render(view.swizzle);
66
67 /* If this is a HiZ buffer we can sample from with a programmable clear
68 * value (SKL+), define the clear value to the optimal constant.
69 */
70 union isl_color_value default_clear_color = { .u32 = { 0, } };
71 if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT)
72 default_clear_color = anv_image_hiz_clear_value(image);
73
74 if (!clear_color)
75 clear_color = &default_clear_color;
76
77 const struct anv_address address =
78 anv_image_address(image, &surface->memory_range);
79
80 void *surface_state_map = state_inout->state_data.data;
81
82 const struct isl_surf *isl_surf = &surface->isl;
83
84 struct isl_surf tmp_surf;
85 uint64_t offset_B = 0;
86 uint32_t tile_x_sa = 0, tile_y_sa = 0;
87 if (isl_format_is_compressed(surface->isl.format) &&
88 !isl_format_is_compressed(view.format)) {
89 /* We're creating an uncompressed view of a compressed surface. This is
90 * allowed but only for a single level/layer.
91 */
92 assert(surface->isl.samples == 1);
93 assert(view.levels == 1);
94
95 ASSERTED bool ok =
96 isl_surf_get_uncompressed_surf(&device->isl_dev, isl_surf, &view,
97 &tmp_surf, &view,
98 &offset_B, &tile_x_sa, &tile_y_sa);
99 assert(ok);
100 isl_surf = &tmp_surf;
101 }
102
103 state_inout->address = anv_address_add(address, offset_B);
104
105 struct anv_address aux_address = ANV_NULL_ADDRESS;
106 if (aux_usage != ISL_AUX_USAGE_NONE)
107 aux_address = anv_image_address(image, &aux_surface->memory_range);
108 state_inout->aux_address = aux_address;
109
110 const struct anv_address clear_address =
111 anv_image_get_clear_color_addr(device, image, view.format, aspect,
112 view_usage & ISL_SURF_USAGE_TEXTURE_BIT);
113 state_inout->clear_address = clear_address;
114
115 if (image->vk.create_flags & VK_IMAGE_CREATE_PROTECTED_BIT)
116 view_usage |= ISL_SURF_USAGE_PROTECTED_BIT;
117
118 isl_surf_fill_state(&device->isl_dev, surface_state_map,
119 .surf = isl_surf,
120 .view = &view,
121 .address = anv_address_physical(state_inout->address),
122 .clear_color = *clear_color,
123 .aux_surf = &aux_surface->isl,
124 .aux_usage = aux_usage,
125 .aux_address = anv_address_physical(aux_address),
126 .clear_address = anv_address_physical(clear_address),
127 .use_clear_address =
128 device->isl_dev.ss.clear_color_state_size > 0,
129 .mocs = anv_mocs(device, state_inout->address.bo,
130 view_usage),
131 .x_offset_sa = tile_x_sa,
132 .y_offset_sa = tile_y_sa,
133 /* Assume robustness with EXT_pipeline_robustness
134 * because this can be turned on/off per pipeline and
135 * we have no visibility on this here.
136 */
137 .robust_image_access =
138 device->vk.enabled_features.robustImageAccess ||
139 device->vk.enabled_features.robustImageAccess2 ||
140 device->vk.enabled_extensions.EXT_pipeline_robustness);
141
142 /* With the exception of gfx8, the bottom 12 bits of the MCS base address
143 * are used to store other information. This should be ok, however, because
144 * the surface buffer addresses are always 4K page aligned.
145 */
146 if (!anv_address_is_null(aux_address)) {
147 uint32_t *aux_addr_dw = surface_state_map +
148 device->isl_dev.ss.aux_addr_offset;
149 assert((aux_address.offset & 0xfff) == 0);
150 state_inout->aux_address.offset |= *aux_addr_dw & 0xfff;
151 }
152
153 if (device->info->ver >= 10 && clear_address.bo) {
154 uint32_t *clear_addr_dw = surface_state_map +
155 device->isl_dev.ss.clear_color_state_offset;
156 assert((clear_address.offset & 0x3f) == 0);
157 state_inout->clear_address.offset |= *clear_addr_dw & 0x3f;
158 }
159
160 if (state_inout->state.map)
161 memcpy(state_inout->state.map, surface_state_map, ANV_SURFACE_STATE_SIZE);
162 }
163
164 static uint32_t
anv_image_aspect_get_planes(VkImageAspectFlags aspect_mask)165 anv_image_aspect_get_planes(VkImageAspectFlags aspect_mask)
166 {
167 anv_assert_valid_aspect_set(aspect_mask);
168 return util_bitcount(aspect_mask);
169 }
170
171 bool
anv_can_hiz_clear_ds_view(struct anv_device * device,const struct anv_image_view * iview,VkImageLayout layout,VkImageAspectFlags clear_aspects,float depth_clear_value,VkRect2D render_area,const VkQueueFlagBits queue_flags)172 anv_can_hiz_clear_ds_view(struct anv_device *device,
173 const struct anv_image_view *iview,
174 VkImageLayout layout,
175 VkImageAspectFlags clear_aspects,
176 float depth_clear_value,
177 VkRect2D render_area,
178 const VkQueueFlagBits queue_flags)
179 {
180 if (INTEL_DEBUG(DEBUG_NO_FAST_CLEAR))
181 return false;
182
183 /* If we're just clearing stencil, we can always HiZ clear */
184 if (!(clear_aspects & VK_IMAGE_ASPECT_DEPTH_BIT))
185 return true;
186
187 /* We must have depth in order to have HiZ */
188 if (!(iview->image->vk.aspects & VK_IMAGE_ASPECT_DEPTH_BIT))
189 return false;
190
191 const enum isl_aux_usage clear_aux_usage =
192 anv_layout_to_aux_usage(device->info, iview->image,
193 VK_IMAGE_ASPECT_DEPTH_BIT,
194 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
195 layout, queue_flags);
196
197 if (!isl_aux_usage_has_fast_clears(clear_aux_usage))
198 return false;
199
200 if (isl_aux_usage_has_ccs(clear_aux_usage)) {
201 /* From the TGL PRM, Vol 9, "Compressed Depth Buffers" (under the
202 * "Texture performant" and "ZCS" columns):
203 *
204 * Update with clear at either 16x8 or 8x4 granularity, based on
205 * fs_clr or otherwise.
206 *
207 * Although alignment requirements are only listed for the texture
208 * performant mode, test results indicate that requirements exist for
209 * the non-texture performant mode as well. Disable partial clears.
210 */
211 if (render_area.offset.x > 0 ||
212 render_area.offset.y > 0 ||
213 render_area.extent.width !=
214 u_minify(iview->vk.extent.width, iview->vk.base_mip_level) ||
215 render_area.extent.height !=
216 u_minify(iview->vk.extent.height, iview->vk.base_mip_level)) {
217 return false;
218 }
219
220 /* When fast-clearing, hardware behaves in unexpected ways if the clear
221 * rectangle, aligned to 16x8, could cover neighboring LODs.
222 * Fortunately, ISL guarantees that LOD0 will be 8-row aligned and
223 * LOD0's height seems to not matter. Also, few applications ever clear
224 * LOD1+. Only allow fast-clearing upper LODs if no overlap can occur.
225 */
226 const struct isl_surf *surf =
227 &iview->image->planes[0].primary_surface.isl;
228 assert(isl_surf_usage_is_depth(surf->usage));
229 assert(surf->dim_layout == ISL_DIM_LAYOUT_GFX4_2D);
230 assert(surf->array_pitch_el_rows % 8 == 0);
231 if (clear_aux_usage == ISL_AUX_USAGE_HIZ_CCS_WT &&
232 iview->vk.base_mip_level >= 1 &&
233 (iview->vk.extent.width % 32 != 0 ||
234 surf->image_alignment_el.h % 8 != 0)) {
235 return false;
236 }
237 }
238
239 if (device->info->ver <= 12 &&
240 depth_clear_value != anv_image_hiz_clear_value(iview->image).f32[0])
241 return false;
242
243 /* If we got here, then we can fast clear */
244 return true;
245 }
246
247 void
anv_image_view_init(struct anv_device * device,struct anv_image_view * iview,const VkImageViewCreateInfo * pCreateInfo,struct anv_state_stream * surface_state_stream)248 anv_image_view_init(struct anv_device *device,
249 struct anv_image_view *iview,
250 const VkImageViewCreateInfo *pCreateInfo,
251 struct anv_state_stream *surface_state_stream)
252 {
253 ANV_FROM_HANDLE(anv_image, image, pCreateInfo->image);
254
255 vk_image_view_init(&device->vk, &iview->vk, false, pCreateInfo);
256 iview->image = image;
257 iview->n_planes = anv_image_aspect_get_planes(iview->vk.aspects);
258 iview->use_surface_state_stream = surface_state_stream != NULL;
259
260 /* Now go through the underlying image selected planes and map them to
261 * planes in the image view.
262 */
263 anv_foreach_image_aspect_bit(iaspect_bit, image, iview->vk.aspects) {
264 const uint32_t vplane =
265 anv_aspect_to_plane(iview->vk.aspects, 1UL << iaspect_bit);
266
267 VkFormat view_format = iview->vk.view_format;
268 if (anv_is_format_emulated(device->physical, view_format)) {
269 assert(image->emu_plane_format != VK_FORMAT_UNDEFINED);
270 view_format =
271 anv_get_emulation_format(device->physical, view_format);
272 }
273 const struct anv_format_plane format = anv_get_format_plane(
274 device->info, view_format, vplane, image->vk.tiling);
275
276 iview->planes[vplane].isl = (struct isl_view) {
277 .format = format.isl_format,
278 .base_level = iview->vk.base_mip_level,
279 .levels = iview->vk.level_count,
280 .base_array_layer = iview->vk.base_array_layer,
281 .array_len = iview->vk.layer_count,
282 .min_lod_clamp = iview->vk.min_lod,
283 .swizzle = {
284 .r = remap_swizzle(iview->vk.swizzle.r, format.swizzle),
285 .g = remap_swizzle(iview->vk.swizzle.g, format.swizzle),
286 .b = remap_swizzle(iview->vk.swizzle.b, format.swizzle),
287 .a = remap_swizzle(iview->vk.swizzle.a, format.swizzle),
288 },
289 };
290
291 if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_3D) {
292 iview->planes[vplane].isl.base_array_layer = 0;
293 iview->planes[vplane].isl.array_len = iview->vk.extent.depth;
294 }
295
296 if (pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE ||
297 pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
298 iview->planes[vplane].isl.usage = ISL_SURF_USAGE_CUBE_BIT;
299 } else {
300 iview->planes[vplane].isl.usage = 0;
301 }
302
303 if (iview->vk.usage & (VK_IMAGE_USAGE_SAMPLED_BIT |
304 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) {
305 iview->planes[vplane].optimal_sampler.state =
306 anv_device_maybe_alloc_surface_state(device, surface_state_stream);
307 iview->planes[vplane].general_sampler.state =
308 anv_device_maybe_alloc_surface_state(device, surface_state_stream);
309
310 enum isl_aux_usage general_aux_usage =
311 anv_layout_to_aux_usage(device->info, image, 1UL << iaspect_bit,
312 VK_IMAGE_USAGE_SAMPLED_BIT,
313 VK_IMAGE_LAYOUT_GENERAL,
314 VK_QUEUE_GRAPHICS_BIT |
315 VK_QUEUE_COMPUTE_BIT |
316 VK_QUEUE_TRANSFER_BIT);
317 enum isl_aux_usage optimal_aux_usage =
318 anv_layout_to_aux_usage(device->info, image, 1UL << iaspect_bit,
319 VK_IMAGE_USAGE_SAMPLED_BIT,
320 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
321 VK_QUEUE_GRAPHICS_BIT |
322 VK_QUEUE_COMPUTE_BIT |
323 VK_QUEUE_TRANSFER_BIT);
324
325 anv_image_fill_surface_state(device, image, 1ULL << iaspect_bit,
326 &iview->planes[vplane].isl,
327 ISL_SURF_USAGE_TEXTURE_BIT,
328 optimal_aux_usage, NULL,
329 ANV_IMAGE_VIEW_STATE_TEXTURE_OPTIMAL,
330 &iview->planes[vplane].optimal_sampler);
331
332 anv_image_fill_surface_state(device, image, 1ULL << iaspect_bit,
333 &iview->planes[vplane].isl,
334 ISL_SURF_USAGE_TEXTURE_BIT,
335 general_aux_usage, NULL,
336 0,
337 &iview->planes[vplane].general_sampler);
338 }
339
340 /* NOTE: This one needs to go last since it may stomp isl_view.format */
341 if (iview->vk.usage & VK_IMAGE_USAGE_STORAGE_BIT) {
342 struct isl_view storage_view = iview->planes[vplane].isl;
343 if (iview->vk.view_type == VK_IMAGE_VIEW_TYPE_3D) {
344 storage_view.base_array_layer = iview->vk.storage.z_slice_offset;
345 storage_view.array_len = iview->vk.storage.z_slice_count;
346 }
347
348 enum isl_aux_usage general_aux_usage =
349 anv_layout_to_aux_usage(device->info, image, 1UL << iaspect_bit,
350 VK_IMAGE_USAGE_STORAGE_BIT,
351 VK_IMAGE_LAYOUT_GENERAL,
352 VK_QUEUE_GRAPHICS_BIT |
353 VK_QUEUE_COMPUTE_BIT |
354 VK_QUEUE_TRANSFER_BIT);
355 iview->planes[vplane].storage.state =
356 anv_device_maybe_alloc_surface_state(device, surface_state_stream);
357
358 anv_image_fill_surface_state(device, image, 1ULL << iaspect_bit,
359 &storage_view,
360 ISL_SURF_USAGE_STORAGE_BIT,
361 general_aux_usage, NULL,
362 0,
363 &iview->planes[vplane].storage);
364 }
365 }
366 }
367
368 void
anv_image_view_finish(struct anv_image_view * iview)369 anv_image_view_finish(struct anv_image_view *iview)
370 {
371 struct anv_device *device =
372 container_of(iview->vk.base.device, struct anv_device, vk);
373
374 if (!iview->use_surface_state_stream) {
375 for (uint32_t plane = 0; plane < iview->n_planes; plane++) {
376 if (iview->planes[plane].optimal_sampler.state.alloc_size) {
377 anv_state_pool_free(&device->bindless_surface_state_pool,
378 iview->planes[plane].optimal_sampler.state);
379 }
380
381 if (iview->planes[plane].general_sampler.state.alloc_size) {
382 anv_state_pool_free(&device->bindless_surface_state_pool,
383 iview->planes[plane].general_sampler.state);
384 }
385
386 if (iview->planes[plane].storage.state.alloc_size) {
387 anv_state_pool_free(&device->bindless_surface_state_pool,
388 iview->planes[plane].storage.state);
389 }
390 }
391 }
392
393 vk_image_view_finish(&iview->vk);
394 }
395
396 VkResult
anv_CreateImageView(VkDevice _device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView)397 anv_CreateImageView(VkDevice _device,
398 const VkImageViewCreateInfo *pCreateInfo,
399 const VkAllocationCallbacks *pAllocator,
400 VkImageView *pView)
401 {
402 ANV_FROM_HANDLE(anv_device, device, _device);
403 struct anv_image_view *iview;
404
405 iview = vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*iview), 8,
406 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
407 if (iview == NULL)
408 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
409
410 anv_image_view_init(device, iview, pCreateInfo, NULL);
411
412 *pView = anv_image_view_to_handle(iview);
413
414 return VK_SUCCESS;
415 }
416
417 void
anv_DestroyImageView(VkDevice _device,VkImageView _iview,const VkAllocationCallbacks * pAllocator)418 anv_DestroyImageView(VkDevice _device, VkImageView _iview,
419 const VkAllocationCallbacks *pAllocator)
420 {
421 ANV_FROM_HANDLE(anv_image_view, iview, _iview);
422
423 if (!iview)
424 return;
425
426 anv_image_view_finish(iview);
427 vk_free2(&iview->vk.base.device->alloc, pAllocator, iview);
428 }
429