diff options
Diffstat (limited to 'src/freedreno/fdl/fd6_layout.c')
-rw-r--r-- | src/freedreno/fdl/fd6_layout.c | 108 |
1 files changed, 89 insertions, 19 deletions
diff --git a/src/freedreno/fdl/fd6_layout.c b/src/freedreno/fdl/fd6_layout.c index 82b3a3e715c..966a3e4bbc4 100644 --- a/src/freedreno/fdl/fd6_layout.c +++ b/src/freedreno/fdl/fd6_layout.c @@ -29,28 +29,39 @@ #include "freedreno_layout.h" -/* indexed by cpp, including msaa 2x and 4x: */ +/* indexed by cpp, including msaa 2x and 4x: + * TODO: + * cpp=1 UBWC needs testing at larger texture sizes + * missing UBWC blockwidth/blockheight for npot+64 cpp + * missing 96/128 CPP for 8x MSAA with 32_32_32/32_32_32_32 + */ static const struct { unsigned pitchalign; unsigned heightalign; + uint8_t ubwc_blockwidth; + uint8_t ubwc_blockheight; } tile_alignment[] = { - [1] = { 128, 32 }, - [2] = { 128, 16 }, + [1] = { 128, 32, 16, 4 }, + [2] = { 128, 16, 16, 4 }, [3] = { 64, 32 }, - [4] = { 64, 16 }, + [4] = { 64, 16, 16, 4 }, [6] = { 64, 16 }, - [8] = { 64, 16 }, + [8] = { 64, 16, 8, 4, }, [12] = { 64, 16 }, - [16] = { 64, 16 }, + [16] = { 64, 16, 4, 4, }, [24] = { 64, 16 }, - [32] = { 64, 16 }, + [32] = { 64, 16, 4, 2 }, [48] = { 64, 16 }, [64] = { 64, 16 }, /* special cases for r8g8: */ - [0] = { 64, 32 }, + [0] = { 64, 32, 16, 4 }, }; +#define RGB_TILE_WIDTH_ALIGNMENT 64 +#define RGB_TILE_HEIGHT_ALIGNMENT 16 +#define UBWC_PLANE_SIZE_ALIGNMENT 4096 + /* NOTE: good way to test this is: (for example) * piglit/bin/texelFetch fs sampler3D 100x100x8 */ @@ -58,7 +69,7 @@ void fdl6_layout(struct fdl_layout *layout, enum pipe_format format, uint32_t nr_samples, uint32_t width0, uint32_t height0, uint32_t depth0, - uint32_t mip_levels, uint32_t array_size, bool is_3d) + uint32_t mip_levels, uint32_t array_size, bool is_3d, bool ubwc) { assert(nr_samples > 0); layout->width0 = width0; @@ -70,7 +81,6 @@ fdl6_layout(struct fdl_layout *layout, const struct util_format_description *format_desc = util_format_description(format); - uint32_t level; uint32_t depth = depth0; /* linear dimensions: */ uint32_t lwidth = width0; @@ -100,9 +110,11 @@ fdl6_layout(struct fdl_layout *layout, debug_assert(ta < ARRAY_SIZE(tile_alignment)); debug_assert(tile_alignment[ta].pitchalign); - for (level = 0; level < mip_levels; level++) { + for (uint32_t level = 0; level < mip_levels; level++) { struct fdl_slice *slice = &layout->slices[level]; - uint32_t tile_mode = fdl_tile_mode(layout, level); + struct fdl_slice *ubwc_slice = &layout->ubwc_slices[level]; + uint32_t tile_mode = (ubwc ? + layout->tile_mode : fdl_tile_mode(layout, level)); uint32_t width, height; /* tiled levels of 3D textures are rounded up to PoT dimensions: */ @@ -162,13 +174,30 @@ fdl6_layout(struct fdl_layout *layout, layout->size += slice->size0 * depth * layers_in_level; - if (false) { - fprintf(stderr, "%s: %ux%ux%u@%u:\t%2u: stride=%4u, size=%6u,%7u, aligned_height=%3u, blocks=%u, offset=0x%x tiling=%d\n", - util_format_name(format), - width, height, depth, layout->cpp, - level, slice->pitch * layout->cpp, - slice->size0, layout->size, aligned_height, blocks, - slice->offset, tile_mode); + if (ubwc) { + /* with UBWC every level is aligned to 4K */ + layout->size = align(layout->size, 4096); + + uint32_t block_width = tile_alignment[ta].ubwc_blockwidth; + uint32_t block_height = tile_alignment[ta].ubwc_blockheight; + uint32_t meta_pitch = align(DIV_ROUND_UP(width, block_width), + RGB_TILE_WIDTH_ALIGNMENT); + uint32_t meta_height = align(DIV_ROUND_UP(height, block_height), + RGB_TILE_HEIGHT_ALIGNMENT); + + /* it looks like mipmaps need alignment to power of two + * TODO: needs testing with large npot textures + * (needed for the first level?) + */ + if (mip_levels > 1) { + meta_pitch = util_next_power_of_two(meta_pitch); + meta_height = util_next_power_of_two(meta_height); + } + + ubwc_slice->size0 = align(meta_pitch * meta_height, UBWC_PLANE_SIZE_ALIGNMENT); + ubwc_slice->pitch = meta_pitch; + ubwc_slice->offset = layout->ubwc_size; + layout->ubwc_size += ubwc_slice->size0; } depth = u_minify(depth, 1); @@ -182,4 +211,45 @@ fdl6_layout(struct fdl_layout *layout, layout->layer_size = align(layout->size, 4096); layout->size = layout->layer_size * array_size; } + + /* Place the UBWC slices before the uncompressed slices, because the + * kernel expects UBWC to be at the start of the buffer. In the HW, we + * get to program the UBWC and non-UBWC offset/strides + * independently. + */ + if (ubwc) { + for (uint32_t level = 0; level < mip_levels; level++) + layout->slices[level].offset += layout->ubwc_size * array_size; + layout->size += layout->ubwc_size * array_size; + } + + if (false) { + for (uint32_t level = 0; level < mip_levels; level++) { + struct fdl_slice *slice = &layout->slices[level]; + struct fdl_slice *ubwc_slice = &layout->ubwc_slices[level]; + uint32_t tile_mode = (ubwc ? + layout->tile_mode : fdl_tile_mode(layout, level)); + + fprintf(stderr, "%s: %ux%ux%u@%ux%u:\t%2u: stride=%4u, size=%6u,%6u, aligned_height=%3u, offset=0x%x,0x%x tiling=%d\n", + util_format_name(format), + u_minify(layout->width0, level), + u_minify(layout->height0, level), + u_minify(layout->depth0, level), + layout->cpp, nr_samples, + level, + slice->pitch * layout->cpp, + slice->size0, ubwc_slice->size0, + slice->size0 / (slice->pitch * layout->cpp), + slice->offset, ubwc_slice->offset, + tile_mode); + } + } +} + +void +fdl6_get_ubwc_blockwidth(struct fdl_layout *layout, + uint32_t *blockwidth, uint32_t *blockheight) +{ + *blockwidth = tile_alignment[layout->cpp].ubwc_blockwidth; + *blockheight = tile_alignment[layout->cpp].ubwc_blockheight; } |