1 /*
2 * Copyright © 2016 Red Hat.
3 * Copyright © 2016 Bas Nieuwenhuizen
4 *
5 * based in part on anv driver which is:
6 * Copyright © 2015 Intel Corporation
7 *
8 * SPDX-License-Identifier: MIT
9 */
10
11 #include "vk_log.h"
12
13 #include "radv_image_view.h"
14 #include "radv_buffer_view.h"
15 #include "radv_entrypoints.h"
16 #include "radv_formats.h"
17 #include "radv_image.h"
18
19 #include "ac_descriptors.h"
20 #include "ac_formats.h"
21 #include "gfx10_format_table.h"
22
23 static unsigned
radv_tex_dim(VkImageType image_type,VkImageViewType view_type,unsigned nr_layers,unsigned nr_samples,bool is_storage_image,bool gfx9)24 radv_tex_dim(VkImageType image_type, VkImageViewType view_type, unsigned nr_layers, unsigned nr_samples,
25 bool is_storage_image, bool gfx9)
26 {
27 if (view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
28 return is_storage_image ? V_008F1C_SQ_RSRC_IMG_2D_ARRAY : V_008F1C_SQ_RSRC_IMG_CUBE;
29
30 /* GFX9 allocates 1D textures as 2D. */
31 if (gfx9 && image_type == VK_IMAGE_TYPE_1D)
32 image_type = VK_IMAGE_TYPE_2D;
33 switch (image_type) {
34 case VK_IMAGE_TYPE_1D:
35 return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_1D_ARRAY : V_008F1C_SQ_RSRC_IMG_1D;
36 case VK_IMAGE_TYPE_2D:
37 if (nr_samples > 1)
38 return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY : V_008F1C_SQ_RSRC_IMG_2D_MSAA;
39 else
40 return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_2D_ARRAY : V_008F1C_SQ_RSRC_IMG_2D;
41 case VK_IMAGE_TYPE_3D:
42 if (view_type == VK_IMAGE_VIEW_TYPE_3D)
43 return V_008F1C_SQ_RSRC_IMG_3D;
44 else
45 return V_008F1C_SQ_RSRC_IMG_2D_ARRAY;
46 default:
47 unreachable("illegal image type");
48 }
49 }
50
51 void
radv_set_mutable_tex_desc_fields(struct radv_device * device,struct radv_image * image,const struct legacy_surf_level * base_level_info,unsigned plane_id,unsigned base_level,unsigned first_level,unsigned block_width,bool is_stencil,bool is_storage_image,bool disable_compression,bool enable_write_compression,uint32_t * state,const struct ac_surf_nbc_view * nbc_view)52 radv_set_mutable_tex_desc_fields(struct radv_device *device, struct radv_image *image,
53 const struct legacy_surf_level *base_level_info, unsigned plane_id,
54 unsigned base_level, unsigned first_level, unsigned block_width, bool is_stencil,
55 bool is_storage_image, bool disable_compression, bool enable_write_compression,
56 uint32_t *state, const struct ac_surf_nbc_view *nbc_view)
57 {
58 struct radv_image_plane *plane = &image->planes[plane_id];
59 const uint32_t bind_idx = image->disjoint ? plane_id : 0;
60 struct radv_image_binding *binding = &image->bindings[bind_idx];
61 uint64_t gpu_address = binding->bo ? radv_image_get_va(image, bind_idx) : 0;
62 const struct radv_physical_device *pdev = radv_device_physical(device);
63
64 const struct ac_mutable_tex_state ac_state = {
65 .surf = &plane->surface,
66 .va = gpu_address,
67 .gfx10 =
68 {
69 .write_compress_enable =
70 radv_dcc_enabled(image, first_level) && is_storage_image && enable_write_compression,
71 .iterate_256 = radv_image_get_iterate256(device, image),
72 },
73 .gfx9 =
74 {
75 .nbc_view = nbc_view,
76 },
77 .gfx6 =
78 {
79 .base_level_info = base_level_info,
80 .base_level = base_level,
81 .block_width = block_width,
82 },
83 .is_stencil = is_stencil,
84 .dcc_enabled = !disable_compression && radv_dcc_enabled(image, first_level),
85 .tc_compat_htile_enabled = !disable_compression && radv_image_is_tc_compat_htile(image),
86 };
87
88 ac_set_mutable_tex_desc_fields(&pdev->info, &ac_state, state);
89 }
90
91 /**
92 * Build the sampler view descriptor for a texture (GFX10).
93 */
94 static void
gfx10_make_texture_descriptor(struct radv_device * device,struct radv_image * image,bool is_storage_image,VkImageViewType view_type,VkFormat vk_format,const VkComponentMapping * mapping,unsigned first_level,unsigned last_level,unsigned first_layer,unsigned last_layer,unsigned width,unsigned height,unsigned depth,float min_lod,uint32_t * state,uint32_t * fmask_state,VkImageCreateFlags img_create_flags,const struct ac_surf_nbc_view * nbc_view,const VkImageViewSlicedCreateInfoEXT * sliced_3d)95 gfx10_make_texture_descriptor(struct radv_device *device, struct radv_image *image, bool is_storage_image,
96 VkImageViewType view_type, VkFormat vk_format, const VkComponentMapping *mapping,
97 unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer,
98 unsigned width, unsigned height, unsigned depth, float min_lod, uint32_t *state,
99 uint32_t *fmask_state, VkImageCreateFlags img_create_flags,
100 const struct ac_surf_nbc_view *nbc_view, const VkImageViewSlicedCreateInfoEXT *sliced_3d)
101 {
102 const struct radv_physical_device *pdev = radv_device_physical(device);
103 const bool create_2d_view_of_3d =
104 (img_create_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT) && view_type == VK_IMAGE_VIEW_TYPE_2D;
105 enum pipe_format format = vk_format_to_pipe_format(vk_format);
106 const struct util_format_description *desc;
107 enum pipe_swizzle swizzle[4];
108 unsigned array_pitch = 0;
109 unsigned type;
110
111 /* For emulated ETC2 without alpha we need to override the format to a 3-componenent format, so
112 * that border colors work correctly (alpha forced to 1). Since Vulkan has no such format,
113 * this uses the Gallium formats to set the description. */
114 if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK && format == PIPE_FORMAT_R8G8B8A8_UNORM) {
115 format = PIPE_FORMAT_R8G8B8X8_UNORM;
116 } else if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK && format == PIPE_FORMAT_R8G8B8A8_SRGB) {
117 format = PIPE_FORMAT_R8G8B8X8_SRGB;
118 }
119
120 desc = util_format_description(format);
121
122 radv_compose_swizzle(desc, mapping, swizzle);
123
124 if (create_2d_view_of_3d) {
125 assert(image->vk.image_type == VK_IMAGE_TYPE_3D);
126 type = V_008F1C_SQ_RSRC_IMG_3D;
127 } else {
128 type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, image->vk.samples, is_storage_image,
129 pdev->info.gfx_level == GFX9);
130 }
131
132 if (type == V_008F1C_SQ_RSRC_IMG_1D_ARRAY) {
133 height = 1;
134 depth = image->vk.array_layers;
135 } else if (type == V_008F1C_SQ_RSRC_IMG_2D_ARRAY || type == V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY) {
136 if (view_type != VK_IMAGE_VIEW_TYPE_3D)
137 depth = image->vk.array_layers;
138 } else if (type == V_008F1C_SQ_RSRC_IMG_CUBE)
139 depth = image->vk.array_layers / 6;
140
141 if (create_2d_view_of_3d) {
142 assert(type == V_008F1C_SQ_RSRC_IMG_3D);
143
144 depth = !is_storage_image ? depth : u_minify(depth, first_level);
145 array_pitch = is_storage_image;
146 } else if (sliced_3d) {
147 assert(type == V_008F1C_SQ_RSRC_IMG_3D && is_storage_image);
148
149 const unsigned total = u_minify(depth, first_level);
150 const unsigned slice_count = sliced_3d->sliceCount == VK_REMAINING_3D_SLICES_EXT
151 ? MAX2(1, total - sliced_3d->sliceOffset)
152 : sliced_3d->sliceCount;
153
154 first_layer = sliced_3d->sliceOffset;
155 depth = sliced_3d->sliceOffset + slice_count;
156 array_pitch = 1;
157 }
158
159 const struct ac_texture_state tex_state = {
160 .surf = &image->planes[0].surface,
161 .format = format,
162 .img_format = vk_format_to_pipe_format(image->vk.format),
163 .width = width,
164 .height = height,
165 .depth = type == V_008F1C_SQ_RSRC_IMG_3D ? depth - 1 : last_layer,
166 .type = type,
167 .swizzle =
168 {
169 swizzle[0],
170 swizzle[1],
171 swizzle[2],
172 swizzle[3],
173 },
174 .num_samples = image->vk.samples,
175 .num_storage_samples = image->vk.samples,
176 .first_level = first_level,
177 .last_level = last_level,
178 .num_levels = image->vk.mip_levels,
179 .first_layer = first_layer,
180 .last_layer = last_layer,
181 .min_lod = min_lod,
182 .gfx10 =
183 {
184 .uav3d = array_pitch,
185 },
186 .gfx9 =
187 {
188 .nbc_view = nbc_view,
189 },
190 .dcc_enabled = radv_dcc_enabled(image, first_level),
191 .tc_compat_htile_enabled = radv_image_is_tc_compat_htile(image),
192 };
193
194 ac_build_texture_descriptor(&pdev->info, &tex_state, &state[0]);
195
196 /* Initialize the sampler view for FMASK. */
197 if (fmask_state) {
198 if (radv_image_has_fmask(image)) {
199 assert(image->plane_count == 1);
200
201 const struct ac_fmask_state ac_state = {
202 .surf = &image->planes[0].surface,
203 .va = radv_image_get_va(image, 0),
204 .width = width,
205 .height = height,
206 .depth = depth,
207 .type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, 0, false, false),
208 .first_layer = first_layer,
209 .last_layer = last_layer,
210 .num_samples = image->vk.samples,
211 .num_storage_samples = image->vk.samples,
212 .tc_compat_cmask = radv_image_is_tc_compat_cmask(image),
213 };
214
215 ac_build_fmask_descriptor(pdev->info.gfx_level, &ac_state, &fmask_state[0]);
216 } else
217 memset(fmask_state, 0, 8 * 4);
218 }
219 }
220
221 /**
222 * Build the sampler view descriptor for a texture (SI-GFX9)
223 */
224 static void
gfx6_make_texture_descriptor(struct radv_device * device,struct radv_image * image,bool is_storage_image,VkImageViewType view_type,VkFormat vk_format,const VkComponentMapping * mapping,unsigned first_level,unsigned last_level,unsigned first_layer,unsigned last_layer,unsigned width,unsigned height,unsigned depth,float min_lod,uint32_t * state,uint32_t * fmask_state,VkImageCreateFlags img_create_flags)225 gfx6_make_texture_descriptor(struct radv_device *device, struct radv_image *image, bool is_storage_image,
226 VkImageViewType view_type, VkFormat vk_format, const VkComponentMapping *mapping,
227 unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer,
228 unsigned width, unsigned height, unsigned depth, float min_lod, uint32_t *state,
229 uint32_t *fmask_state, VkImageCreateFlags img_create_flags)
230 {
231 const struct radv_physical_device *pdev = radv_device_physical(device);
232 const struct radv_instance *instance = radv_physical_device_instance(pdev);
233 const bool create_2d_view_of_3d =
234 (img_create_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT) && view_type == VK_IMAGE_VIEW_TYPE_2D;
235 enum pipe_format format = vk_format_to_pipe_format(vk_format);
236 const struct util_format_description *desc;
237 enum pipe_swizzle swizzle[4];
238 unsigned type;
239
240 /* For emulated ETC2 without alpha we need to override the format to a 3-componenent format, so
241 * that border colors work correctly (alpha forced to 1). Since Vulkan has no such format,
242 * this uses the Gallium formats to set the description. */
243 if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK && format == PIPE_FORMAT_R8G8B8A8_UNORM) {
244 format = PIPE_FORMAT_R8G8B8X8_UNORM;
245 } else if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK && format == PIPE_FORMAT_R8G8B8A8_SRGB) {
246 format = PIPE_FORMAT_R8G8B8X8_SRGB;
247 }
248
249 desc = util_format_description(format);
250
251 radv_compose_swizzle(desc, mapping, swizzle);
252
253 if (pdev->info.gfx_level == GFX9 && create_2d_view_of_3d) {
254 assert(image->vk.image_type == VK_IMAGE_TYPE_3D);
255 type = V_008F1C_SQ_RSRC_IMG_3D;
256 } else {
257 type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, image->vk.samples, is_storage_image,
258 pdev->info.gfx_level == GFX9);
259 }
260
261 if (type == V_008F1C_SQ_RSRC_IMG_1D_ARRAY) {
262 height = 1;
263 depth = image->vk.array_layers;
264 } else if (type == V_008F1C_SQ_RSRC_IMG_2D_ARRAY || type == V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY) {
265 if (view_type != VK_IMAGE_VIEW_TYPE_3D)
266 depth = image->vk.array_layers;
267 } else if (type == V_008F1C_SQ_RSRC_IMG_CUBE)
268 depth = image->vk.array_layers / 6;
269
270 const struct ac_texture_state tex_state = {
271 .surf = &image->planes[0].surface,
272 .format = format,
273 .img_format = vk_format_to_pipe_format(image->vk.format),
274 .width = width,
275 .height = height,
276 .depth = depth,
277 .type = type,
278 .swizzle =
279 {
280 swizzle[0],
281 swizzle[1],
282 swizzle[2],
283 swizzle[3],
284 },
285 .num_samples = image->vk.samples,
286 .num_storage_samples = image->vk.samples,
287 .first_level = first_level,
288 .last_level = last_level,
289 .num_levels = image->vk.mip_levels,
290 .first_layer = first_layer,
291 .last_layer = last_layer,
292 .min_lod = min_lod,
293 .dcc_enabled = radv_dcc_enabled(image, first_level),
294 .tc_compat_htile_enabled = radv_image_is_tc_compat_htile(image),
295 .aniso_single_level = !instance->drirc.disable_aniso_single_level,
296 };
297
298 ac_build_texture_descriptor(&pdev->info, &tex_state, &state[0]);
299
300 /* Initialize the sampler view for FMASK. */
301 if (fmask_state) {
302 if (radv_image_has_fmask(image)) {
303 assert(image->plane_count == 1);
304
305 const struct ac_fmask_state ac_fmask_state = {
306 .surf = &image->planes[0].surface,
307 .va = radv_image_get_va(image, 0),
308 .width = width,
309 .height = height,
310 .depth = depth,
311 .type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, 0, false, false),
312 .first_layer = first_layer,
313 .last_layer = last_layer,
314 .num_samples = image->vk.samples,
315 .num_storage_samples = image->vk.samples,
316 .tc_compat_cmask = radv_image_is_tc_compat_cmask(image),
317 };
318
319 ac_build_fmask_descriptor(pdev->info.gfx_level, &ac_fmask_state, &fmask_state[0]);
320 } else
321 memset(fmask_state, 0, 8 * 4);
322 }
323 }
324
325 void
radv_make_texture_descriptor(struct radv_device * device,struct radv_image * image,bool is_storage_image,VkImageViewType view_type,VkFormat vk_format,const VkComponentMapping * mapping,unsigned first_level,unsigned last_level,unsigned first_layer,unsigned last_layer,unsigned width,unsigned height,unsigned depth,float min_lod,uint32_t * state,uint32_t * fmask_state,VkImageCreateFlags img_create_flags,const struct ac_surf_nbc_view * nbc_view,const VkImageViewSlicedCreateInfoEXT * sliced_3d)326 radv_make_texture_descriptor(struct radv_device *device, struct radv_image *image, bool is_storage_image,
327 VkImageViewType view_type, VkFormat vk_format, const VkComponentMapping *mapping,
328 unsigned first_level, unsigned last_level, unsigned first_layer, unsigned last_layer,
329 unsigned width, unsigned height, unsigned depth, float min_lod, uint32_t *state,
330 uint32_t *fmask_state, VkImageCreateFlags img_create_flags,
331 const struct ac_surf_nbc_view *nbc_view, const VkImageViewSlicedCreateInfoEXT *sliced_3d)
332 {
333 const struct radv_physical_device *pdev = radv_device_physical(device);
334
335 if (pdev->info.gfx_level >= GFX10) {
336 gfx10_make_texture_descriptor(device, image, is_storage_image, view_type, vk_format, mapping, first_level,
337 last_level, first_layer, last_layer, width, height, depth, min_lod, state,
338 fmask_state, img_create_flags, nbc_view, sliced_3d);
339 } else {
340 gfx6_make_texture_descriptor(device, image, is_storage_image, view_type, vk_format, mapping, first_level,
341 last_level, first_layer, last_layer, width, height, depth, min_lod, state,
342 fmask_state, img_create_flags);
343 }
344 }
345
346 static inline void
compute_non_block_compressed_view(struct radv_device * device,const struct radv_image_view * iview,struct ac_surf_nbc_view * nbc_view)347 compute_non_block_compressed_view(struct radv_device *device, const struct radv_image_view *iview,
348 struct ac_surf_nbc_view *nbc_view)
349 {
350 const struct radv_physical_device *pdev = radv_device_physical(device);
351 const struct radv_image *image = iview->image;
352 const struct radeon_surf *surf = &image->planes[0].surface;
353 struct ac_addrlib *addrlib = device->ws->get_addrlib(device->ws);
354 struct ac_surf_info surf_info = radv_get_ac_surf_info(device, image);
355
356 ac_surface_compute_nbc_view(addrlib, &pdev->info, surf, &surf_info, iview->vk.base_mip_level,
357 iview->vk.base_array_layer, nbc_view);
358 }
359
360 static void
radv_image_view_make_descriptor(struct radv_image_view * iview,struct radv_device * device,VkFormat vk_format,const VkComponentMapping * components,float min_lod,bool is_storage_image,bool disable_compression,bool enable_compression,unsigned plane_id,unsigned descriptor_plane_id,VkImageCreateFlags img_create_flags,const struct ac_surf_nbc_view * nbc_view,const VkImageViewSlicedCreateInfoEXT * sliced_3d,bool force_zero_base_mip)361 radv_image_view_make_descriptor(struct radv_image_view *iview, struct radv_device *device, VkFormat vk_format,
362 const VkComponentMapping *components, float min_lod, bool is_storage_image,
363 bool disable_compression, bool enable_compression, unsigned plane_id,
364 unsigned descriptor_plane_id, VkImageCreateFlags img_create_flags,
365 const struct ac_surf_nbc_view *nbc_view,
366 const VkImageViewSlicedCreateInfoEXT *sliced_3d, bool force_zero_base_mip)
367 {
368 const struct radv_physical_device *pdev = radv_device_physical(device);
369 struct radv_image *image = iview->image;
370 struct radv_image_plane *plane = &image->planes[plane_id];
371 bool is_stencil = iview->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT;
372 unsigned first_layer = iview->vk.base_array_layer;
373 uint32_t blk_w;
374 union radv_descriptor *descriptor;
375 uint32_t hw_level = iview->vk.base_mip_level;
376
377 if (is_storage_image) {
378 descriptor = &iview->storage_descriptor;
379 } else {
380 descriptor = &iview->descriptor;
381 }
382
383 assert(vk_format_get_plane_count(vk_format) == 1);
384 assert(plane->surface.blk_w % vk_format_get_blockwidth(plane->format) == 0);
385 blk_w = plane->surface.blk_w / vk_format_get_blockwidth(plane->format) * vk_format_get_blockwidth(vk_format);
386
387 if (pdev->info.gfx_level >= GFX9) {
388 if (nbc_view->valid) {
389 hw_level = nbc_view->level;
390 iview->extent.width = nbc_view->width;
391 iview->extent.height = nbc_view->height;
392
393 /* Clear the base array layer because addrlib adds it as part of the base addr offset. */
394 first_layer = 0;
395 }
396 } else {
397 if (force_zero_base_mip)
398 hw_level = 0;
399 }
400
401 radv_make_texture_descriptor(device, image, is_storage_image, iview->vk.view_type, vk_format, components, hw_level,
402 hw_level + iview->vk.level_count - 1, first_layer,
403 iview->vk.base_array_layer + iview->vk.layer_count - 1,
404 vk_format_get_plane_width(image->vk.format, plane_id, iview->extent.width),
405 vk_format_get_plane_height(image->vk.format, plane_id, iview->extent.height),
406 iview->extent.depth, min_lod, descriptor->plane_descriptors[descriptor_plane_id],
407 descriptor_plane_id || is_storage_image ? NULL : descriptor->fmask_descriptor,
408 img_create_flags, nbc_view, sliced_3d);
409
410 const struct legacy_surf_level *base_level_info = NULL;
411 if (pdev->info.gfx_level <= GFX8) {
412 if (is_stencil)
413 base_level_info = &plane->surface.u.legacy.zs.stencil_level[iview->vk.base_mip_level];
414 else
415 base_level_info = &plane->surface.u.legacy.level[force_zero_base_mip ? iview->vk.base_mip_level : 0];
416 }
417
418 bool enable_write_compression = radv_image_use_dcc_image_stores(device, image);
419 if (is_storage_image && !(enable_write_compression || enable_compression))
420 disable_compression = true;
421 radv_set_mutable_tex_desc_fields(device, image, base_level_info, plane_id, iview->vk.base_mip_level,
422 iview->vk.base_mip_level, blk_w, is_stencil, is_storage_image, disable_compression,
423 enable_write_compression, descriptor->plane_descriptors[descriptor_plane_id],
424 nbc_view);
425 }
426
427 /**
428 * Determine if the given image view can be fast cleared.
429 */
430 static bool
radv_image_view_can_fast_clear(const struct radv_device * device,const struct radv_image_view * iview)431 radv_image_view_can_fast_clear(const struct radv_device *device, const struct radv_image_view *iview)
432 {
433 struct radv_image *image;
434
435 if (!iview)
436 return false;
437 image = iview->image;
438
439 /* Only fast clear if the image itself can be fast cleared. */
440 if (!radv_image_can_fast_clear(device, image))
441 return false;
442
443 /* Only fast clear if all layers are bound. */
444 if (iview->vk.base_array_layer > 0 || iview->vk.layer_count != image->vk.array_layers)
445 return false;
446
447 /* Only fast clear if the view covers the whole image. */
448 if (!radv_image_extent_compare(image, &iview->extent))
449 return false;
450
451 return true;
452 }
453
454 void
radv_image_view_init(struct radv_image_view * iview,struct radv_device * device,const VkImageViewCreateInfo * pCreateInfo,VkImageCreateFlags img_create_flags,const struct radv_image_view_extra_create_info * extra_create_info)455 radv_image_view_init(struct radv_image_view *iview, struct radv_device *device,
456 const VkImageViewCreateInfo *pCreateInfo, VkImageCreateFlags img_create_flags,
457 const struct radv_image_view_extra_create_info *extra_create_info)
458 {
459 VK_FROM_HANDLE(radv_image, image, pCreateInfo->image);
460 const struct radv_physical_device *pdev = radv_device_physical(device);
461 const VkImageSubresourceRange *range = &pCreateInfo->subresourceRange;
462 uint32_t plane_count = 1;
463 float min_lod = 0.0f;
464
465 const struct VkImageViewMinLodCreateInfoEXT *min_lod_info =
466 vk_find_struct_const(pCreateInfo->pNext, IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT);
467
468 if (min_lod_info)
469 min_lod = min_lod_info->minLod;
470
471 const struct VkImageViewSlicedCreateInfoEXT *sliced_3d =
472 vk_find_struct_const(pCreateInfo->pNext, IMAGE_VIEW_SLICED_CREATE_INFO_EXT);
473
474 bool from_client = extra_create_info && extra_create_info->from_client;
475 vk_image_view_init(&device->vk, &iview->vk, !from_client, pCreateInfo);
476
477 bool force_zero_base_mip = true;
478 if (pdev->info.gfx_level <= GFX8 && min_lod) {
479 /* Do not force the base level to zero to workaround a spurious bug with mipmaps and min LOD. */
480 force_zero_base_mip = false;
481 }
482
483 switch (image->vk.image_type) {
484 case VK_IMAGE_TYPE_1D:
485 case VK_IMAGE_TYPE_2D:
486 assert(range->baseArrayLayer + vk_image_subresource_layer_count(&image->vk, range) - 1 <= image->vk.array_layers);
487 break;
488 case VK_IMAGE_TYPE_3D:
489 assert(range->baseArrayLayer + vk_image_subresource_layer_count(&image->vk, range) - 1 <=
490 u_minify(image->vk.extent.depth, range->baseMipLevel));
491 break;
492 default:
493 unreachable("bad VkImageType");
494 }
495 iview->image = image;
496 iview->plane_id = radv_plane_from_aspect(pCreateInfo->subresourceRange.aspectMask);
497 iview->nbc_view.valid = false;
498
499 /* If the image has an Android external format, pCreateInfo->format will be
500 * VK_FORMAT_UNDEFINED. */
501 if (iview->vk.format == VK_FORMAT_UNDEFINED) {
502 iview->vk.format = image->vk.format;
503 iview->vk.view_format = image->vk.format;
504 }
505
506 /* Split out the right aspect. Note that for internal meta code we sometimes
507 * use an equivalent color format for the aspect so we first have to check
508 * if we actually got depth/stencil formats. */
509 if (iview->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT) {
510 if (vk_format_has_stencil(iview->vk.view_format))
511 iview->vk.view_format = vk_format_stencil_only(iview->vk.view_format);
512 } else if (iview->vk.aspects == VK_IMAGE_ASPECT_DEPTH_BIT) {
513 if (vk_format_has_depth(iview->vk.view_format))
514 iview->vk.view_format = vk_format_depth_only(iview->vk.view_format);
515 }
516
517 if (vk_format_get_plane_count(image->vk.format) > 1 &&
518 pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
519 plane_count = vk_format_get_plane_count(iview->vk.format);
520 }
521
522 /* when the view format is emulated, redirect the view to the hidden plane 1 */
523 if (radv_is_format_emulated(pdev, iview->vk.format)) {
524 assert(radv_is_format_emulated(pdev, image->vk.format));
525 iview->plane_id = 1;
526 iview->vk.view_format = image->planes[iview->plane_id].format;
527 iview->vk.format = image->planes[iview->plane_id].format;
528 plane_count = 1;
529 }
530
531 if (!force_zero_base_mip || pdev->info.gfx_level >= GFX9) {
532 iview->extent = (VkExtent3D){
533 .width = image->vk.extent.width,
534 .height = image->vk.extent.height,
535 .depth = image->vk.extent.depth,
536 };
537 } else {
538 iview->extent = iview->vk.extent;
539 }
540
541 if (iview->vk.format != image->planes[iview->plane_id].format) {
542 const struct radv_image_plane *plane = &image->planes[iview->plane_id];
543 unsigned view_bw = vk_format_get_blockwidth(iview->vk.format);
544 unsigned view_bh = vk_format_get_blockheight(iview->vk.format);
545 unsigned plane_bw = vk_format_get_blockwidth(plane->format);
546 unsigned plane_bh = vk_format_get_blockheight(plane->format);
547
548 iview->extent.width = DIV_ROUND_UP(iview->extent.width * view_bw, plane_bw);
549 iview->extent.height = DIV_ROUND_UP(iview->extent.height * view_bh, plane_bh);
550
551 /* Comment ported from amdvlk -
552 * If we have the following image:
553 * Uncompressed pixels Compressed block sizes (4x4)
554 * mip0: 22 x 22 6 x 6
555 * mip1: 11 x 11 3 x 3
556 * mip2: 5 x 5 2 x 2
557 * mip3: 2 x 2 1 x 1
558 * mip4: 1 x 1 1 x 1
559 *
560 * On GFX9 the descriptor is always programmed with the WIDTH and HEIGHT of the base level and
561 * the HW is calculating the degradation of the block sizes down the mip-chain as follows
562 * (straight-up divide-by-two integer math): mip0: 6x6 mip1: 3x3 mip2: 1x1 mip3: 1x1
563 *
564 * This means that mip2 will be missing texels.
565 *
566 * Fix this by calculating the base mip's width and height, then convert
567 * that, and round it back up to get the level 0 size. Clamp the
568 * converted size between the original values, and the physical extent
569 * of the base mipmap.
570 *
571 * On GFX10 we have to take care to not go over the physical extent
572 * of the base mipmap as otherwise the GPU computes a different layout.
573 * Note that the GPU does use the same base-mip dimensions for both a
574 * block compatible format and the compressed format, so even if we take
575 * the plain converted dimensions the physical layout is correct.
576 */
577 if (pdev->info.gfx_level >= GFX9 && vk_format_is_block_compressed(plane->format) &&
578 !vk_format_is_block_compressed(iview->vk.format)) {
579 /* If we have multiple levels in the view we should ideally take the last level,
580 * but the mip calculation has a max(..., 1) so walking back to the base mip in an
581 * useful way is hard. */
582 if (iview->vk.level_count > 1) {
583 iview->extent.width = plane->surface.u.gfx9.base_mip_width;
584 iview->extent.height = plane->surface.u.gfx9.base_mip_height;
585 } else {
586 unsigned lvl_width = u_minify(image->vk.extent.width, range->baseMipLevel);
587 unsigned lvl_height = u_minify(image->vk.extent.height, range->baseMipLevel);
588
589 lvl_width = DIV_ROUND_UP(lvl_width * view_bw, plane_bw);
590 lvl_height = DIV_ROUND_UP(lvl_height * view_bh, plane_bh);
591
592 iview->extent.width =
593 CLAMP(lvl_width << range->baseMipLevel, iview->extent.width, plane->surface.u.gfx9.base_mip_width);
594 iview->extent.height =
595 CLAMP(lvl_height << range->baseMipLevel, iview->extent.height, plane->surface.u.gfx9.base_mip_height);
596
597 /* If the hardware-computed extent is still be too small, on GFX10
598 * we can attempt another workaround provided by addrlib that
599 * changes the descriptor's base level, and adjusts the address and
600 * extents accordingly.
601 */
602 if (pdev->info.gfx_level >= GFX10 &&
603 (u_minify(iview->extent.width, range->baseMipLevel) < lvl_width ||
604 u_minify(iview->extent.height, range->baseMipLevel) < lvl_height) &&
605 iview->vk.layer_count == 1) {
606 compute_non_block_compressed_view(device, iview, &iview->nbc_view);
607 }
608 }
609 }
610 }
611
612 iview->support_fast_clear = radv_image_view_can_fast_clear(device, iview);
613 iview->disable_dcc_mrt = extra_create_info ? extra_create_info->disable_dcc_mrt : false;
614
615 bool disable_compression = extra_create_info ? extra_create_info->disable_compression : false;
616 bool enable_compression = extra_create_info ? extra_create_info->enable_compression : false;
617 for (unsigned i = 0; i < plane_count; ++i) {
618 VkFormat format = vk_format_get_plane_format(iview->vk.view_format, i);
619 radv_image_view_make_descriptor(iview, device, format, &pCreateInfo->components, min_lod, false,
620 disable_compression, enable_compression, iview->plane_id + i, i, img_create_flags,
621 &iview->nbc_view, NULL, force_zero_base_mip);
622 radv_image_view_make_descriptor(iview, device, format, &pCreateInfo->components, min_lod, true,
623 disable_compression, enable_compression, iview->plane_id + i, i, img_create_flags,
624 &iview->nbc_view, sliced_3d, force_zero_base_mip);
625 }
626 }
627
628 void
radv_image_view_finish(struct radv_image_view * iview)629 radv_image_view_finish(struct radv_image_view *iview)
630 {
631 vk_image_view_finish(&iview->vk);
632 }
633
634 VKAPI_ATTR VkResult VKAPI_CALL
radv_CreateImageView(VkDevice _device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView)635 radv_CreateImageView(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo,
636 const VkAllocationCallbacks *pAllocator, VkImageView *pView)
637 {
638 VK_FROM_HANDLE(radv_image, image, pCreateInfo->image);
639 VK_FROM_HANDLE(radv_device, device, _device);
640 struct radv_image_view *view;
641
642 view = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*view), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
643 if (view == NULL)
644 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
645
646 radv_image_view_init(view, device, pCreateInfo, image->vk.create_flags,
647 &(struct radv_image_view_extra_create_info){.from_client = true});
648
649 *pView = radv_image_view_to_handle(view);
650
651 return VK_SUCCESS;
652 }
653
654 VKAPI_ATTR void VKAPI_CALL
radv_DestroyImageView(VkDevice _device,VkImageView _iview,const VkAllocationCallbacks * pAllocator)655 radv_DestroyImageView(VkDevice _device, VkImageView _iview, const VkAllocationCallbacks *pAllocator)
656 {
657 VK_FROM_HANDLE(radv_device, device, _device);
658 VK_FROM_HANDLE(radv_image_view, iview, _iview);
659
660 if (!iview)
661 return;
662
663 radv_image_view_finish(iview);
664 vk_free2(&device->vk.alloc, pAllocator, iview);
665 }
666