mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-03 03:28:09 +02:00
nil: Add support for sparse resident images
These have to use one of the Vulkan specified sparse image block sizes for the tiling and have concept of a mip tail start LOD which we need to calculate as well. Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26719>
This commit is contained in:
parent
3700e58692
commit
23f2cfe8fb
2 changed files with 138 additions and 11 deletions
|
|
@ -277,6 +277,85 @@ choose_tiling(struct nil_extent4d extent_px,
|
|||
return nil_tiling_clamp(tiling, extent_B);
|
||||
}
|
||||
|
||||
static struct nil_extent4d
|
||||
nil_sparse_block_extent_el(enum pipe_format format,
|
||||
enum nil_image_dim dim)
|
||||
{
|
||||
/* Taken from Vulkan 1.3.279 spec section entitled "Standard Sparse Image
|
||||
* Block Shapes".
|
||||
*/
|
||||
switch (dim) {
|
||||
case NIL_IMAGE_DIM_2D:
|
||||
switch (util_format_get_blocksizebits(format)) {
|
||||
case 8: return nil_extent4d(256, 256, 1, 1);
|
||||
case 16: return nil_extent4d(256, 128, 1, 1);
|
||||
case 32: return nil_extent4d(128, 128, 1, 1);
|
||||
case 64: return nil_extent4d(128, 64, 1, 1);
|
||||
case 128: return nil_extent4d(64, 64, 1, 1);
|
||||
default: unreachable("Invalid texel size");
|
||||
}
|
||||
case NIL_IMAGE_DIM_3D:
|
||||
switch (util_format_get_blocksizebits(format)) {
|
||||
case 8: return nil_extent4d(64, 32, 32, 1);
|
||||
case 16: return nil_extent4d(32, 32, 32, 1);
|
||||
case 32: return nil_extent4d(32, 32, 16, 1);
|
||||
case 64: return nil_extent4d(32, 16, 16, 1);
|
||||
case 128: return nil_extent4d(16, 16, 16, 1);
|
||||
default: unreachable("Invalid texel size");
|
||||
}
|
||||
default:
|
||||
unreachable("Invalid dimension");
|
||||
}
|
||||
}
|
||||
|
||||
struct nil_extent4d
|
||||
nil_sparse_block_extent_px(enum pipe_format format,
|
||||
enum nil_image_dim dim,
|
||||
enum nil_sample_layout sample_layout)
|
||||
{
|
||||
struct nil_extent4d block_extent_el =
|
||||
nil_sparse_block_extent_el(format, dim);
|
||||
const struct nil_extent4d el_extent_sa = nil_el_extent_sa(format);
|
||||
struct nil_extent4d block_extent_sa =
|
||||
nil_extent4d_mul(block_extent_el, el_extent_sa);
|
||||
|
||||
return nil_extent4d_div_round_up(block_extent_sa,
|
||||
nil_px_extent_sa(sample_layout));
|
||||
}
|
||||
|
||||
static struct nil_extent4d
|
||||
nil_sparse_block_extent_B(enum pipe_format format,
|
||||
enum nil_image_dim dim)
|
||||
{
|
||||
const struct nil_extent4d block_extent_el =
|
||||
nil_sparse_block_extent_el(format, dim);
|
||||
const uint32_t B_per_el = util_format_get_blocksize(format);
|
||||
return nil_extent4d_el_to_B(block_extent_el, B_per_el);
|
||||
}
|
||||
|
||||
static struct nil_tiling
|
||||
sparse_tiling(enum pipe_format format, enum nil_image_dim dim)
|
||||
{
|
||||
const struct nil_extent4d sparse_block_extent_B =
|
||||
nil_sparse_block_extent_B(format, dim);
|
||||
|
||||
assert(util_is_power_of_two_or_zero(sparse_block_extent_B.w));
|
||||
assert(util_is_power_of_two_or_zero(sparse_block_extent_B.h));
|
||||
assert(util_is_power_of_two_or_zero(sparse_block_extent_B.d));
|
||||
|
||||
const bool gob_height_8 = true;
|
||||
const struct nil_extent4d sparse_block_extent_GOB =
|
||||
nil_extent4d_B_to_GOB(sparse_block_extent_B, gob_height_8);
|
||||
|
||||
return (struct nil_tiling) {
|
||||
.is_tiled = true,
|
||||
.gob_height_8 = gob_height_8,
|
||||
.x_log2 = util_logbase2(sparse_block_extent_GOB.w),
|
||||
.y_log2 = util_logbase2(sparse_block_extent_GOB.h),
|
||||
.z_log2 = util_logbase2(sparse_block_extent_GOB.d),
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t
|
||||
nil_tiling_size_B(struct nil_tiling tiling)
|
||||
{
|
||||
|
|
@ -523,8 +602,14 @@ nil_image_init(struct nv_device_info *dev,
|
|||
|
||||
const enum nil_sample_layout sample_layout =
|
||||
nil_choose_sample_layout(info->samples);
|
||||
const struct nil_tiling tiling =
|
||||
choose_tiling(info->extent_px, info->format, sample_layout, info->usage);
|
||||
|
||||
struct nil_tiling tiling;
|
||||
if (info->usage & NIL_IMAGE_USAGE_SPARSE_RESIDENCY_BIT) {
|
||||
tiling = sparse_tiling(info->format, info->dim);
|
||||
} else {
|
||||
tiling = choose_tiling(info->extent_px, info->format,
|
||||
sample_layout, info->usage);
|
||||
}
|
||||
|
||||
*image = (struct nil_image) {
|
||||
.dim = info->dim,
|
||||
|
|
@ -534,12 +619,20 @@ nil_image_init(struct nv_device_info *dev,
|
|||
.num_levels = info->levels,
|
||||
};
|
||||
|
||||
/* If the client requested sparse, default mip_tail_firs_lod to the number
|
||||
* of mip levels and we'll clamp it as needed in the loop below.
|
||||
*/
|
||||
if (info->usage & NIL_IMAGE_USAGE_SPARSE_RESIDENCY_BIT)
|
||||
image->mip_tail_first_lod = info->levels;
|
||||
|
||||
uint64_t layer_size_B = 0;
|
||||
for (uint32_t l = 0; l < info->levels; l++) {
|
||||
struct nil_extent4d lvl_ext_B = image_level_extent_B(image, l);
|
||||
if (tiling.is_tiled) {
|
||||
struct nil_tiling lvl_tiling = nil_tiling_clamp(tiling, lvl_ext_B);
|
||||
assert(l > 0 || nil_tiling_eq(tiling, lvl_tiling));
|
||||
|
||||
if (!nil_tiling_eq(tiling, lvl_tiling))
|
||||
image->mip_tail_first_lod = MIN2(image->mip_tail_first_lod, l);
|
||||
|
||||
/* Align the size to tiles */
|
||||
struct nil_extent4d lvl_tiling_ext_B = nil_tiling_extent_B(lvl_tiling);
|
||||
|
|
@ -568,6 +661,12 @@ nil_image_init(struct nv_device_info *dev,
|
|||
layer_size_B += nil_image_level_size_B(image, l);
|
||||
}
|
||||
|
||||
/* We use the tiling for level 0 instead of the tiling selected above
|
||||
* because, in the case of sparse residency with small images, level 0 may
|
||||
* have a smaller tiling than what we tried to use. However, the level 0
|
||||
* tiling is the one we program in the hardware so that's the one we need
|
||||
* to use for array stride calculations and the like.
|
||||
*/
|
||||
const uint32_t lvl0_tiling_size_B =
|
||||
nil_tiling_size_B(image->levels[0].tiling);
|
||||
|
||||
|
|
@ -577,6 +676,13 @@ nil_image_init(struct nv_device_info *dev,
|
|||
image->size_B = (uint64_t)image->array_stride_B * image->extent_px.a;
|
||||
image->align_B = lvl0_tiling_size_B;
|
||||
|
||||
/* If the client requested sparse residency, we need a 64K alignment or
|
||||
* else sparse binding may fail. This is true regardless of whether or
|
||||
* not we actually select a 64K tile format.
|
||||
*/
|
||||
if (info->usage & NIL_IMAGE_USAGE_SPARSE_RESIDENCY_BIT)
|
||||
image->align_B = MAX2(image->align_B, (1 << 16));
|
||||
|
||||
if (image->levels[0].tiling.is_tiled) {
|
||||
image->tile_mode = (uint16_t)image->levels[0].tiling.y_log2 << 4 |
|
||||
(uint16_t)image->levels[0].tiling.z_log2 << 8;
|
||||
|
|
@ -649,6 +755,7 @@ nil_image_for_level(const struct nil_image *image_in,
|
|||
.size_B = size_B,
|
||||
.tile_mode = image_in->tile_mode,
|
||||
.pte_kind = image_in->pte_kind,
|
||||
.mip_tail_first_lod = level < image_in->mip_tail_first_lod ? 1 : 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,14 +32,15 @@ enum ENUM_PACKED nil_sample_layout {
|
|||
enum nil_sample_layout nil_choose_sample_layout(uint32_t samples);
|
||||
|
||||
enum nil_image_usage_flags {
|
||||
NIL_IMAGE_USAGE_RENDER_TARGET_BIT = BITFIELD_BIT(0),
|
||||
NIL_IMAGE_USAGE_DEPTH_BIT = BITFIELD_BIT(1),
|
||||
NIL_IMAGE_USAGE_STENCIL_BIT = BITFIELD_BIT(2),
|
||||
NIL_IMAGE_USAGE_TEXTURE_BIT = BITFIELD_BIT(3),
|
||||
NIL_IMAGE_USAGE_STORAGE_BIT = BITFIELD_BIT(4),
|
||||
NIL_IMAGE_USAGE_CUBE_BIT = BITFIELD_BIT(5),
|
||||
NIL_IMAGE_USAGE_2D_VIEW_BIT = BITFIELD_BIT(6),
|
||||
NIL_IMAGE_USAGE_LINEAR_BIT = BITFIELD_BIT(7),
|
||||
NIL_IMAGE_USAGE_RENDER_TARGET_BIT = BITFIELD_BIT(0),
|
||||
NIL_IMAGE_USAGE_DEPTH_BIT = BITFIELD_BIT(1),
|
||||
NIL_IMAGE_USAGE_STENCIL_BIT = BITFIELD_BIT(2),
|
||||
NIL_IMAGE_USAGE_TEXTURE_BIT = BITFIELD_BIT(3),
|
||||
NIL_IMAGE_USAGE_STORAGE_BIT = BITFIELD_BIT(4),
|
||||
NIL_IMAGE_USAGE_CUBE_BIT = BITFIELD_BIT(5),
|
||||
NIL_IMAGE_USAGE_2D_VIEW_BIT = BITFIELD_BIT(6),
|
||||
NIL_IMAGE_USAGE_LINEAR_BIT = BITFIELD_BIT(7),
|
||||
NIL_IMAGE_USAGE_SPARSE_RESIDENCY_BIT = BITFIELD_BIT(8),
|
||||
};
|
||||
|
||||
enum ENUM_PACKED nil_view_type {
|
||||
|
|
@ -148,6 +149,7 @@ struct nil_image {
|
|||
struct nil_extent4d extent_px;
|
||||
enum nil_sample_layout sample_layout;
|
||||
uint8_t num_levels;
|
||||
uint8_t mip_tail_first_lod;
|
||||
|
||||
struct nil_image_level levels[NIL_MAX_LEVELS];
|
||||
|
||||
|
|
@ -218,6 +220,19 @@ nil_image_level_layer_offset_B(const struct nil_image *image,
|
|||
return image->levels[level].offset_B + (layer * image->array_stride_B);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nil_image_mip_tail_offset_B(const struct nil_image *image)
|
||||
{
|
||||
assert(image->mip_tail_first_lod > 0);
|
||||
return image->levels[image->mip_tail_first_lod].offset_B;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nil_image_mip_tail_size_B(const struct nil_image *image)
|
||||
{
|
||||
return image->array_stride_B - nil_image_mip_tail_offset_B(image);
|
||||
}
|
||||
|
||||
struct nil_extent4d
|
||||
nil_extent4d_px_to_tl(struct nil_extent4d extent_px,
|
||||
struct nil_tiling tiling, enum pipe_format format,
|
||||
|
|
@ -264,4 +279,9 @@ void nil_buffer_fill_tic(struct nv_device_info *dev,
|
|||
uint32_t num_elements,
|
||||
void *desc_out);
|
||||
|
||||
struct nil_extent4d
|
||||
nil_sparse_block_extent_px(enum pipe_format format,
|
||||
enum nil_image_dim dim,
|
||||
enum nil_sample_layout sample_layout);
|
||||
|
||||
#endif /* NIL_IMAGE_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue