mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-18 18:08:15 +02:00
Preserves the previous behavior while handling the new formats. Reviewed-by: Faith Ekstrand <faith.ekstrand@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30821>
657 lines
28 KiB
C
657 lines
28 KiB
C
/*
|
|
* Copyright © 2016 Red Hat.
|
|
* Copyright © 2016 Bas Nieuwenhuizen
|
|
*
|
|
* based in part on anv driver which is:
|
|
* Copyright © 2015 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include "vk_log.h"
|
|
|
|
#include "radv_image_view.h"
|
|
#include "radv_buffer_view.h"
|
|
#include "radv_entrypoints.h"
|
|
#include "radv_formats.h"
|
|
#include "radv_image.h"
|
|
|
|
#include "ac_descriptors.h"
|
|
#include "ac_formats.h"
|
|
#include "gfx10_format_table.h"
|
|
|
|
static unsigned
|
|
radv_tex_dim(VkImageType image_type, VkImageViewType view_type, unsigned nr_layers, unsigned nr_samples,
|
|
bool is_storage_image, bool gfx9)
|
|
{
|
|
if (view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
|
|
return is_storage_image ? V_008F1C_SQ_RSRC_IMG_2D_ARRAY : V_008F1C_SQ_RSRC_IMG_CUBE;
|
|
|
|
/* GFX9 allocates 1D textures as 2D. */
|
|
if (gfx9 && image_type == VK_IMAGE_TYPE_1D)
|
|
image_type = VK_IMAGE_TYPE_2D;
|
|
switch (image_type) {
|
|
case VK_IMAGE_TYPE_1D:
|
|
return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_1D_ARRAY : V_008F1C_SQ_RSRC_IMG_1D;
|
|
case VK_IMAGE_TYPE_2D:
|
|
if (nr_samples > 1)
|
|
return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY : V_008F1C_SQ_RSRC_IMG_2D_MSAA;
|
|
else
|
|
return nr_layers > 1 ? V_008F1C_SQ_RSRC_IMG_2D_ARRAY : V_008F1C_SQ_RSRC_IMG_2D;
|
|
case VK_IMAGE_TYPE_3D:
|
|
if (view_type == VK_IMAGE_VIEW_TYPE_3D)
|
|
return V_008F1C_SQ_RSRC_IMG_3D;
|
|
else
|
|
return V_008F1C_SQ_RSRC_IMG_2D_ARRAY;
|
|
default:
|
|
unreachable("illegal image type");
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct radv_image_plane *plane = &image->planes[plane_id];
|
|
const uint32_t bind_idx = image->disjoint ? plane_id : 0;
|
|
struct radv_image_binding *binding = &image->bindings[bind_idx];
|
|
uint64_t gpu_address = binding->bo ? radv_image_get_va(image, bind_idx) : 0;
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
|
|
const struct ac_mutable_tex_state ac_state = {
|
|
.surf = &plane->surface,
|
|
.va = gpu_address,
|
|
.gfx10 =
|
|
{
|
|
.write_compress_enable =
|
|
radv_dcc_enabled(image, first_level) && is_storage_image && enable_write_compression,
|
|
.iterate_256 = radv_image_get_iterate256(device, image),
|
|
},
|
|
.gfx9 =
|
|
{
|
|
.nbc_view = nbc_view,
|
|
},
|
|
.gfx6 =
|
|
{
|
|
.base_level_info = base_level_info,
|
|
.base_level = base_level,
|
|
.block_width = block_width,
|
|
},
|
|
.is_stencil = is_stencil,
|
|
.dcc_enabled = !disable_compression && radv_dcc_enabled(image, first_level),
|
|
.tc_compat_htile_enabled = !disable_compression && radv_image_is_tc_compat_htile(image),
|
|
};
|
|
|
|
ac_set_mutable_tex_desc_fields(&pdev->info, &ac_state, state);
|
|
}
|
|
|
|
/**
|
|
* Build the sampler view descriptor for a texture (GFX10).
|
|
*/
|
|
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, const struct ac_surf_nbc_view *nbc_view,
|
|
const VkImageViewSlicedCreateInfoEXT *sliced_3d)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
const bool create_2d_view_of_3d =
|
|
(image->vk.create_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT) && view_type == VK_IMAGE_VIEW_TYPE_2D;
|
|
enum pipe_format format = radv_format_to_pipe_format(vk_format);
|
|
const struct util_format_description *desc;
|
|
enum pipe_swizzle swizzle[4];
|
|
unsigned array_pitch = 0;
|
|
unsigned type;
|
|
|
|
/* For emulated ETC2 without alpha we need to override the format to a 3-componenent format, so
|
|
* that border colors work correctly (alpha forced to 1). Since Vulkan has no such format,
|
|
* this uses the Gallium formats to set the description. */
|
|
if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK && format == PIPE_FORMAT_R8G8B8A8_UNORM) {
|
|
format = PIPE_FORMAT_R8G8B8X8_UNORM;
|
|
} else if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK && format == PIPE_FORMAT_R8G8B8A8_SRGB) {
|
|
format = PIPE_FORMAT_R8G8B8X8_SRGB;
|
|
}
|
|
|
|
desc = util_format_description(format);
|
|
|
|
radv_compose_swizzle(desc, mapping, swizzle);
|
|
|
|
type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, image->vk.samples, is_storage_image,
|
|
pdev->info.gfx_level == GFX9);
|
|
|
|
if (type == V_008F1C_SQ_RSRC_IMG_1D_ARRAY) {
|
|
height = 1;
|
|
depth = image->vk.array_layers;
|
|
} else if (type == V_008F1C_SQ_RSRC_IMG_2D_ARRAY || type == V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY) {
|
|
if (view_type != VK_IMAGE_VIEW_TYPE_3D)
|
|
depth = image->vk.array_layers;
|
|
} else if (type == V_008F1C_SQ_RSRC_IMG_CUBE)
|
|
depth = image->vk.array_layers / 6;
|
|
|
|
if (create_2d_view_of_3d) {
|
|
assert(image->vk.image_type == VK_IMAGE_TYPE_3D && type == V_008F1C_SQ_RSRC_IMG_2D_ARRAY);
|
|
|
|
array_pitch = is_storage_image;
|
|
} else if (sliced_3d) {
|
|
assert(type == V_008F1C_SQ_RSRC_IMG_3D && is_storage_image);
|
|
|
|
const unsigned total = u_minify(depth, first_level);
|
|
const unsigned slice_count = sliced_3d->sliceCount == VK_REMAINING_3D_SLICES_EXT
|
|
? MAX2(1, total - sliced_3d->sliceOffset)
|
|
: sliced_3d->sliceCount;
|
|
|
|
first_layer = sliced_3d->sliceOffset;
|
|
depth = sliced_3d->sliceOffset + slice_count;
|
|
array_pitch = 1;
|
|
}
|
|
|
|
const struct ac_texture_state tex_state = {
|
|
.surf = &image->planes[0].surface,
|
|
.format = format,
|
|
.img_format = radv_format_to_pipe_format(image->vk.format),
|
|
.width = width,
|
|
.height = height,
|
|
.depth = type == V_008F1C_SQ_RSRC_IMG_3D ? depth - 1 : last_layer,
|
|
.type = type,
|
|
.swizzle =
|
|
{
|
|
swizzle[0],
|
|
swizzle[1],
|
|
swizzle[2],
|
|
swizzle[3],
|
|
},
|
|
.num_samples = image->vk.samples,
|
|
.num_storage_samples = image->vk.samples,
|
|
.first_level = first_level,
|
|
.last_level = last_level,
|
|
.num_levels = image->vk.mip_levels,
|
|
.first_layer = first_layer,
|
|
.last_layer = last_layer,
|
|
.min_lod = min_lod,
|
|
.gfx10 =
|
|
{
|
|
.uav3d = array_pitch,
|
|
},
|
|
.gfx9 =
|
|
{
|
|
.nbc_view = nbc_view,
|
|
},
|
|
.dcc_enabled = radv_dcc_enabled(image, first_level),
|
|
.tc_compat_htile_enabled = radv_image_is_tc_compat_htile(image),
|
|
};
|
|
|
|
ac_build_texture_descriptor(&pdev->info, &tex_state, &state[0]);
|
|
|
|
/* Initialize the sampler view for FMASK. */
|
|
if (fmask_state) {
|
|
if (radv_image_has_fmask(image)) {
|
|
assert(image->plane_count == 1);
|
|
|
|
const struct ac_fmask_state ac_state = {
|
|
.surf = &image->planes[0].surface,
|
|
.va = radv_image_get_va(image, 0),
|
|
.width = width,
|
|
.height = height,
|
|
.depth = depth,
|
|
.type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, 0, false, false),
|
|
.first_layer = first_layer,
|
|
.last_layer = last_layer,
|
|
.num_samples = image->vk.samples,
|
|
.num_storage_samples = image->vk.samples,
|
|
.tc_compat_cmask = radv_image_is_tc_compat_cmask(image),
|
|
};
|
|
|
|
ac_build_fmask_descriptor(pdev->info.gfx_level, &ac_state, &fmask_state[0]);
|
|
} else
|
|
memset(fmask_state, 0, 8 * 4);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build the sampler view descriptor for a texture (SI-GFX9)
|
|
*/
|
|
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)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
const struct radv_instance *instance = radv_physical_device_instance(pdev);
|
|
enum pipe_format format = radv_format_to_pipe_format(vk_format);
|
|
const struct util_format_description *desc;
|
|
enum pipe_swizzle swizzle[4];
|
|
unsigned type;
|
|
|
|
/* For emulated ETC2 without alpha we need to override the format to a 3-componenent format, so
|
|
* that border colors work correctly (alpha forced to 1). Since Vulkan has no such format,
|
|
* this uses the Gallium formats to set the description. */
|
|
if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK && format == PIPE_FORMAT_R8G8B8A8_UNORM) {
|
|
format = PIPE_FORMAT_R8G8B8X8_UNORM;
|
|
} else if (image->vk.format == VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK && format == PIPE_FORMAT_R8G8B8A8_SRGB) {
|
|
format = PIPE_FORMAT_R8G8B8X8_SRGB;
|
|
}
|
|
|
|
desc = util_format_description(format);
|
|
|
|
radv_compose_swizzle(desc, mapping, swizzle);
|
|
|
|
type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, image->vk.samples, is_storage_image,
|
|
pdev->info.gfx_level == GFX9);
|
|
|
|
if (type == V_008F1C_SQ_RSRC_IMG_1D_ARRAY) {
|
|
height = 1;
|
|
depth = image->vk.array_layers;
|
|
} else if (type == V_008F1C_SQ_RSRC_IMG_2D_ARRAY || type == V_008F1C_SQ_RSRC_IMG_2D_MSAA_ARRAY) {
|
|
if (view_type != VK_IMAGE_VIEW_TYPE_3D)
|
|
depth = image->vk.array_layers;
|
|
} else if (type == V_008F1C_SQ_RSRC_IMG_CUBE)
|
|
depth = image->vk.array_layers / 6;
|
|
|
|
const struct ac_texture_state tex_state = {
|
|
.surf = &image->planes[0].surface,
|
|
.format = format,
|
|
.img_format = radv_format_to_pipe_format(image->vk.format),
|
|
.width = width,
|
|
.height = height,
|
|
.depth = depth,
|
|
.type = type,
|
|
.swizzle =
|
|
{
|
|
swizzle[0],
|
|
swizzle[1],
|
|
swizzle[2],
|
|
swizzle[3],
|
|
},
|
|
.num_samples = image->vk.samples,
|
|
.num_storage_samples = image->vk.samples,
|
|
.first_level = first_level,
|
|
.last_level = last_level,
|
|
.num_levels = image->vk.mip_levels,
|
|
.first_layer = first_layer,
|
|
.last_layer = last_layer,
|
|
.min_lod = min_lod,
|
|
.dcc_enabled = radv_dcc_enabled(image, first_level),
|
|
.tc_compat_htile_enabled = radv_image_is_tc_compat_htile(image),
|
|
.aniso_single_level = !instance->drirc.disable_aniso_single_level,
|
|
};
|
|
|
|
ac_build_texture_descriptor(&pdev->info, &tex_state, &state[0]);
|
|
|
|
/* Initialize the sampler view for FMASK. */
|
|
if (fmask_state) {
|
|
if (radv_image_has_fmask(image)) {
|
|
assert(image->plane_count == 1);
|
|
|
|
const struct ac_fmask_state ac_fmask_state = {
|
|
.surf = &image->planes[0].surface,
|
|
.va = radv_image_get_va(image, 0),
|
|
.width = width,
|
|
.height = height,
|
|
.depth = depth,
|
|
.type = radv_tex_dim(image->vk.image_type, view_type, image->vk.array_layers, 0, false, false),
|
|
.first_layer = first_layer,
|
|
.last_layer = last_layer,
|
|
.num_samples = image->vk.samples,
|
|
.num_storage_samples = image->vk.samples,
|
|
.tc_compat_cmask = radv_image_is_tc_compat_cmask(image),
|
|
};
|
|
|
|
ac_build_fmask_descriptor(pdev->info.gfx_level, &ac_fmask_state, &fmask_state[0]);
|
|
} else
|
|
memset(fmask_state, 0, 8 * 4);
|
|
}
|
|
}
|
|
|
|
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, const struct ac_surf_nbc_view *nbc_view,
|
|
const VkImageViewSlicedCreateInfoEXT *sliced_3d)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
|
|
if (pdev->info.gfx_level >= GFX10) {
|
|
gfx10_make_texture_descriptor(device, image, is_storage_image, view_type, vk_format, mapping, first_level,
|
|
last_level, first_layer, last_layer, width, height, depth, min_lod, state,
|
|
fmask_state, nbc_view, sliced_3d);
|
|
} else {
|
|
gfx6_make_texture_descriptor(device, image, is_storage_image, view_type, vk_format, mapping, first_level,
|
|
last_level, first_layer, last_layer, width, height, depth, min_lod, state,
|
|
fmask_state);
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
const struct radv_image *image = iview->image;
|
|
const struct radeon_surf *surf = &image->planes[0].surface;
|
|
struct ac_addrlib *addrlib = device->ws->get_addrlib(device->ws);
|
|
struct ac_surf_info surf_info = radv_get_ac_surf_info(device, image);
|
|
|
|
ac_surface_compute_nbc_view(addrlib, &pdev->info, surf, &surf_info, iview->vk.base_mip_level,
|
|
iview->vk.base_array_layer, nbc_view);
|
|
}
|
|
|
|
static void
|
|
radv_image_view_make_descriptor(struct radv_image_view *iview, struct radv_device *device, VkFormat vk_format,
|
|
const VkComponentMapping *components, bool is_storage_image, bool disable_compression,
|
|
bool enable_compression, unsigned plane_id, unsigned descriptor_plane_id,
|
|
const VkImageViewSlicedCreateInfoEXT *sliced_3d)
|
|
{
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
struct radv_image *image = iview->image;
|
|
struct radv_image_plane *plane = &image->planes[plane_id];
|
|
bool is_stencil = iview->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT;
|
|
unsigned first_layer = iview->vk.base_array_layer;
|
|
uint32_t blk_w;
|
|
union radv_descriptor *descriptor;
|
|
uint32_t hw_level = iview->vk.base_mip_level;
|
|
bool force_zero_base_mip = false;
|
|
|
|
if (is_storage_image) {
|
|
descriptor = &iview->storage_descriptor;
|
|
} else {
|
|
descriptor = &iview->descriptor;
|
|
}
|
|
|
|
assert(vk_format_get_plane_count(vk_format) == 1);
|
|
assert(plane->surface.blk_w % vk_format_get_blockwidth(plane->format) == 0);
|
|
blk_w = plane->surface.blk_w / vk_format_get_blockwidth(plane->format) * vk_format_get_blockwidth(vk_format);
|
|
|
|
VkExtent3D extent = {
|
|
.width = iview->extent.width,
|
|
.height = iview->extent.height,
|
|
.depth = iview->extent.depth,
|
|
};
|
|
|
|
if (pdev->info.gfx_level >= GFX9) {
|
|
if (iview->nbc_view.valid) {
|
|
hw_level = iview->nbc_view.level;
|
|
|
|
/* Clear the base array layer because addrlib adds it as part of the base addr offset. */
|
|
first_layer = 0;
|
|
}
|
|
} else {
|
|
/* On GFX6-8, there are some cases where the view must use mip0 and minified image sizes:
|
|
* - storage descriptors
|
|
* - block compressed images
|
|
* - depth view of a depth/stencil image (ie. depth/stencil pitch adjustments)
|
|
* - 2d view of a 3d image
|
|
*/
|
|
if (is_storage_image) {
|
|
force_zero_base_mip = true;
|
|
} else if (vk_format_is_block_compressed(image->planes[plane_id].format)) {
|
|
force_zero_base_mip = true;
|
|
} else if (iview->vk.aspects == VK_IMAGE_ASPECT_DEPTH_BIT &&
|
|
(iview->image->vk.aspects == (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
|
|
force_zero_base_mip = true;
|
|
} else if (iview->image->vk.create_flags & VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT &&
|
|
iview->vk.view_type == VK_IMAGE_VIEW_TYPE_2D) {
|
|
force_zero_base_mip = true;
|
|
}
|
|
|
|
if (force_zero_base_mip) {
|
|
hw_level = 0;
|
|
} else {
|
|
extent.width = image->vk.extent.width;
|
|
extent.height = image->vk.extent.height;
|
|
extent.depth = image->vk.extent.depth;
|
|
}
|
|
}
|
|
|
|
radv_make_texture_descriptor(
|
|
device, image, is_storage_image, iview->vk.view_type, vk_format, components, hw_level,
|
|
hw_level + iview->vk.level_count - 1, first_layer, iview->vk.base_array_layer + iview->vk.layer_count - 1,
|
|
vk_format_get_plane_width(image->vk.format, plane_id, extent.width),
|
|
vk_format_get_plane_height(image->vk.format, plane_id, extent.height), extent.depth, iview->vk.min_lod,
|
|
descriptor->plane_descriptors[descriptor_plane_id],
|
|
descriptor_plane_id || is_storage_image ? NULL : descriptor->fmask_descriptor, &iview->nbc_view, sliced_3d);
|
|
|
|
const struct legacy_surf_level *base_level_info = NULL;
|
|
if (pdev->info.gfx_level <= GFX8) {
|
|
if (is_stencil)
|
|
base_level_info =
|
|
&plane->surface.u.legacy.zs.stencil_level[force_zero_base_mip ? iview->vk.base_mip_level : 0];
|
|
else
|
|
base_level_info = &plane->surface.u.legacy.level[force_zero_base_mip ? iview->vk.base_mip_level : 0];
|
|
}
|
|
|
|
bool enable_write_compression = radv_image_use_dcc_image_stores(device, image);
|
|
if (is_storage_image && !(enable_write_compression || enable_compression))
|
|
disable_compression = true;
|
|
|
|
radv_set_mutable_tex_desc_fields(device, image, base_level_info, plane_id,
|
|
force_zero_base_mip ? iview->vk.base_mip_level : 0, iview->vk.base_mip_level, blk_w,
|
|
is_stencil, is_storage_image, disable_compression, enable_write_compression,
|
|
descriptor->plane_descriptors[descriptor_plane_id], &iview->nbc_view);
|
|
}
|
|
|
|
/**
|
|
* Determine if the given image view can be fast cleared.
|
|
*/
|
|
static bool
|
|
radv_image_view_can_fast_clear(const struct radv_device *device, const struct radv_image_view *iview)
|
|
{
|
|
struct radv_image *image;
|
|
|
|
if (!iview)
|
|
return false;
|
|
image = iview->image;
|
|
|
|
/* Only fast clear if the image itself can be fast cleared. */
|
|
if (!radv_image_can_fast_clear(device, image))
|
|
return false;
|
|
|
|
/* Only fast clear if all layers are bound. */
|
|
if (iview->vk.base_array_layer > 0 || iview->vk.layer_count != image->vk.array_layers)
|
|
return false;
|
|
|
|
/* Only fast clear if the view covers the whole image. */
|
|
if (!radv_image_extent_compare(image, &iview->extent))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
radv_image_view_init(struct radv_image_view *iview, struct radv_device *device,
|
|
const VkImageViewCreateInfo *pCreateInfo,
|
|
const struct radv_image_view_extra_create_info *extra_create_info)
|
|
{
|
|
VK_FROM_HANDLE(radv_image, image, pCreateInfo->image);
|
|
const struct radv_physical_device *pdev = radv_device_physical(device);
|
|
uint32_t plane_count = 1;
|
|
|
|
const struct VkImageViewSlicedCreateInfoEXT *sliced_3d =
|
|
vk_find_struct_const(pCreateInfo->pNext, IMAGE_VIEW_SLICED_CREATE_INFO_EXT);
|
|
|
|
bool from_client = extra_create_info && extra_create_info->from_client;
|
|
vk_image_view_init(&device->vk, &iview->vk, !from_client, pCreateInfo);
|
|
|
|
iview->image = image;
|
|
iview->plane_id = radv_plane_from_aspect(pCreateInfo->subresourceRange.aspectMask);
|
|
iview->nbc_view.valid = false;
|
|
|
|
/* If the image has an Android external format, pCreateInfo->format will be
|
|
* VK_FORMAT_UNDEFINED. */
|
|
if (iview->vk.format == VK_FORMAT_UNDEFINED) {
|
|
iview->vk.format = image->vk.format;
|
|
iview->vk.view_format = image->vk.format;
|
|
}
|
|
|
|
/* Split out the right aspect. Note that for internal meta code we sometimes
|
|
* use an equivalent color format for the aspect so we first have to check
|
|
* if we actually got depth/stencil formats. */
|
|
if (iview->vk.aspects == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
|
if (vk_format_has_stencil(iview->vk.view_format))
|
|
iview->vk.view_format = vk_format_stencil_only(iview->vk.view_format);
|
|
} else if (iview->vk.aspects == VK_IMAGE_ASPECT_DEPTH_BIT) {
|
|
if (vk_format_has_depth(iview->vk.view_format))
|
|
iview->vk.view_format = vk_format_depth_only(iview->vk.view_format);
|
|
}
|
|
|
|
if (vk_format_get_plane_count(image->vk.format) > 1 &&
|
|
pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) {
|
|
plane_count = vk_format_get_plane_count(iview->vk.format);
|
|
}
|
|
|
|
/* when the view format is emulated, redirect the view to the hidden plane 1 */
|
|
if (radv_is_format_emulated(pdev, iview->vk.format)) {
|
|
assert(radv_is_format_emulated(pdev, image->vk.format));
|
|
iview->plane_id = 1;
|
|
iview->vk.view_format = image->planes[iview->plane_id].format;
|
|
iview->vk.format = image->planes[iview->plane_id].format;
|
|
plane_count = 1;
|
|
}
|
|
|
|
if (pdev->info.gfx_level >= GFX9) {
|
|
iview->extent = (VkExtent3D){
|
|
.width = image->vk.extent.width,
|
|
.height = image->vk.extent.height,
|
|
.depth = image->vk.extent.depth,
|
|
};
|
|
} else {
|
|
/* On GFX6-8, CB/DS surfaces use minified images sizes because the mip level can't be
|
|
* specified in registers.
|
|
*/
|
|
iview->extent = vk_image_mip_level_extent(&image->vk, iview->vk.base_mip_level);
|
|
}
|
|
|
|
if (iview->vk.format != image->planes[iview->plane_id].format) {
|
|
const struct radv_image_plane *plane = &image->planes[iview->plane_id];
|
|
unsigned view_bw = vk_format_get_blockwidth(iview->vk.format);
|
|
unsigned view_bh = vk_format_get_blockheight(iview->vk.format);
|
|
unsigned plane_bw = vk_format_get_blockwidth(plane->format);
|
|
unsigned plane_bh = vk_format_get_blockheight(plane->format);
|
|
|
|
iview->extent.width = DIV_ROUND_UP(iview->extent.width * view_bw, plane_bw);
|
|
iview->extent.height = DIV_ROUND_UP(iview->extent.height * view_bh, plane_bh);
|
|
|
|
/* Comment ported from amdvlk -
|
|
* If we have the following image:
|
|
* Uncompressed pixels Compressed block sizes (4x4)
|
|
* mip0: 22 x 22 6 x 6
|
|
* mip1: 11 x 11 3 x 3
|
|
* mip2: 5 x 5 2 x 2
|
|
* mip3: 2 x 2 1 x 1
|
|
* mip4: 1 x 1 1 x 1
|
|
*
|
|
* On GFX9 the descriptor is always programmed with the WIDTH and HEIGHT of the base level and
|
|
* the HW is calculating the degradation of the block sizes down the mip-chain as follows
|
|
* (straight-up divide-by-two integer math): mip0: 6x6 mip1: 3x3 mip2: 1x1 mip3: 1x1
|
|
*
|
|
* This means that mip2 will be missing texels.
|
|
*
|
|
* Fix this by calculating the base mip's width and height, then convert
|
|
* that, and round it back up to get the level 0 size. Clamp the
|
|
* converted size between the original values, and the physical extent
|
|
* of the base mipmap.
|
|
*
|
|
* On GFX10 we have to take care to not go over the physical extent
|
|
* of the base mipmap as otherwise the GPU computes a different layout.
|
|
* Note that the GPU does use the same base-mip dimensions for both a
|
|
* block compatible format and the compressed format, so even if we take
|
|
* the plain converted dimensions the physical layout is correct.
|
|
*/
|
|
if (pdev->info.gfx_level >= GFX9 && vk_format_is_block_compressed(plane->format) &&
|
|
!vk_format_is_block_compressed(iview->vk.format)) {
|
|
/* If we have multiple levels in the view we should ideally take the last level,
|
|
* but the mip calculation has a max(..., 1) so walking back to the base mip in an
|
|
* useful way is hard. */
|
|
if (iview->vk.level_count > 1) {
|
|
iview->extent.width = plane->surface.u.gfx9.base_mip_width;
|
|
iview->extent.height = plane->surface.u.gfx9.base_mip_height;
|
|
} else {
|
|
unsigned lvl_width = u_minify(image->vk.extent.width, iview->vk.base_mip_level);
|
|
unsigned lvl_height = u_minify(image->vk.extent.height, iview->vk.base_mip_level);
|
|
|
|
lvl_width = DIV_ROUND_UP(lvl_width * view_bw, plane_bw);
|
|
lvl_height = DIV_ROUND_UP(lvl_height * view_bh, plane_bh);
|
|
|
|
iview->extent.width =
|
|
CLAMP(lvl_width << iview->vk.base_mip_level, iview->extent.width, plane->surface.u.gfx9.base_mip_width);
|
|
iview->extent.height = CLAMP(lvl_height << iview->vk.base_mip_level, iview->extent.height,
|
|
plane->surface.u.gfx9.base_mip_height);
|
|
|
|
/* If the hardware-computed extent is still be too small, on GFX10
|
|
* we can attempt another workaround provided by addrlib that
|
|
* changes the descriptor's base level, and adjusts the address and
|
|
* extents accordingly.
|
|
*/
|
|
if (pdev->info.gfx_level >= GFX10 &&
|
|
(u_minify(iview->extent.width, iview->vk.base_mip_level) < lvl_width ||
|
|
u_minify(iview->extent.height, iview->vk.base_mip_level) < lvl_height) &&
|
|
iview->vk.layer_count == 1) {
|
|
compute_non_block_compressed_view(device, iview, &iview->nbc_view);
|
|
|
|
if (iview->nbc_view.valid) {
|
|
iview->extent.width = iview->nbc_view.width;
|
|
iview->extent.height = iview->nbc_view.height;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
iview->support_fast_clear = radv_image_view_can_fast_clear(device, iview);
|
|
iview->disable_dcc_mrt = extra_create_info ? extra_create_info->disable_dcc_mrt : false;
|
|
|
|
bool disable_compression = extra_create_info ? extra_create_info->disable_compression : false;
|
|
bool enable_compression = extra_create_info ? extra_create_info->enable_compression : false;
|
|
for (unsigned i = 0; i < plane_count; ++i) {
|
|
VkFormat format = vk_format_get_plane_format(iview->vk.view_format, i);
|
|
radv_image_view_make_descriptor(iview, device, format, &pCreateInfo->components, false, disable_compression,
|
|
enable_compression, iview->plane_id + i, i, NULL);
|
|
radv_image_view_make_descriptor(iview, device, format, &pCreateInfo->components, true, disable_compression,
|
|
enable_compression, iview->plane_id + i, i, sliced_3d);
|
|
}
|
|
}
|
|
|
|
void
|
|
radv_image_view_finish(struct radv_image_view *iview)
|
|
{
|
|
vk_image_view_finish(&iview->vk);
|
|
}
|
|
|
|
VKAPI_ATTR VkResult VKAPI_CALL
|
|
radv_CreateImageView(VkDevice _device, const VkImageViewCreateInfo *pCreateInfo,
|
|
const VkAllocationCallbacks *pAllocator, VkImageView *pView)
|
|
{
|
|
VK_FROM_HANDLE(radv_device, device, _device);
|
|
struct radv_image_view *view;
|
|
|
|
view = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*view), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
|
|
if (view == NULL)
|
|
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
|
|
|
radv_image_view_init(view, device, pCreateInfo, &(struct radv_image_view_extra_create_info){.from_client = true});
|
|
|
|
*pView = radv_image_view_to_handle(view);
|
|
|
|
return VK_SUCCESS;
|
|
}
|
|
|
|
VKAPI_ATTR void VKAPI_CALL
|
|
radv_DestroyImageView(VkDevice _device, VkImageView _iview, const VkAllocationCallbacks *pAllocator)
|
|
{
|
|
VK_FROM_HANDLE(radv_device, device, _device);
|
|
VK_FROM_HANDLE(radv_image_view, iview, _iview);
|
|
|
|
if (!iview)
|
|
return;
|
|
|
|
radv_image_view_finish(iview);
|
|
vk_free2(&device->vk.alloc, pAllocator, iview);
|
|
}
|