From 0ba63d5c26e812ff63a7fdaee897d7c39be6e6de Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 23 Nov 2022 20:38:23 +0900 Subject: [PATCH] ail: Introduce support for compression The main buffer is twiddled as before, but there's now also an auxiliary compression buffer that we need to reserve space for. With compression, the main buffer is aligned less. The macOS logic seems to be to align to the page size only if the texture is both 3D and mipmapped, *and* the layer stride is greater than the page size. That's gated on compression being enabled. Page alignment seems to be needed for uncompressed twiddled cube maps. Signed-off-by: Asahi Lina Part-of: --- src/asahi/layout/layout.c | 61 +++++++++++++++++++++++--- src/asahi/layout/layout.h | 14 ++++++ src/asahi/layout/tests/test-layout.cpp | 2 +- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/asahi/layout/layout.c b/src/asahi/layout/layout.c index eec482896c1..dcc5bc749b8 100644 --- a/src/asahi/layout/layout.c +++ b/src/asahi/layout/layout.c @@ -163,11 +163,52 @@ ail_initialize_twiddled(struct ail_layout *layout) poth_el = u_minify(poth_el, 1); } - /* Arrays and cubemaps have the entire miptree duplicated and page aligned */ - layout->layer_stride_B = ALIGN_POT(offset_B, AIL_PAGESIZE); + /* Arrays and cubemaps have the entire miptree duplicated and page aligned, + * but only when mipmaps are enabled and the layer is larger than one page. + */ + if ((layout->levels != 1 && layout->depth_px != 1 && offset_B > AIL_PAGESIZE) + || layout->tiling != AIL_TILING_TWIDDLED_COMPRESSED) + layout->layer_stride_B = ALIGN_POT(offset_B, AIL_PAGESIZE); + else + layout->layer_stride_B = offset_B; + layout->size_B = layout->layer_stride_B * layout->depth_px; } +static void +ail_initialize_compression(struct ail_layout *layout) +{ + assert(!util_format_is_compressed(layout->format) && "Compressed pixel formats not supported"); + assert(util_format_get_blockwidth(layout->format) == 1); + assert(util_format_get_blockheight(layout->format) == 1); + assert(layout->width_px >= 16 && "Small textures are never compressed"); + assert(layout->height_px >= 16 && "Small textures are never compressed"); + + layout->metadata_offset_B = layout->size_B; + + unsigned width_px = layout->width_px; + unsigned height_px = layout->height_px; + + unsigned compbuf_B = 0; + + for (unsigned l = 0; l < layout->levels; ++l) { + if (width_px < 16 && height_px < 16) + break; + + /* The compression buffer seems to have one byte per 8 x 4 + * pixel block. + */ + unsigned cmpw_el = DIV_ROUND_UP(util_next_power_of_two(width_px), 8); + unsigned cmph_el = DIV_ROUND_UP(util_next_power_of_two(height_px), 4); + compbuf_B += ALIGN_POT(cmpw_el * cmph_el, AIL_CACHELINE); + + width_px = u_minify(width_px, 1); + height_px = u_minify(height_px, 1); + } + + layout->size_B += compbuf_B * layout->depth_px; +} + void ail_make_miptree(struct ail_layout *layout) { @@ -193,13 +234,21 @@ ail_make_miptree(struct ail_layout *layout) assert(util_format_get_blockdepth(layout->format) == 1 && "Deep formats unsupported"); - if (layout->tiling == AIL_TILING_LINEAR) + switch (layout->tiling) { + case AIL_TILING_LINEAR: ail_initialize_linear(layout); - else if (layout->tiling == AIL_TILING_TWIDDLED) + break; + case AIL_TILING_TWIDDLED: ail_initialize_twiddled(layout); - else + break; + case AIL_TILING_TWIDDLED_COMPRESSED: + ail_initialize_twiddled(layout); + ail_initialize_compression(layout); + break; + default: unreachable("Unsupported tiling"); + } - layout->size_B = ALIGN_POT(layout->size_B, AIL_PAGESIZE); + layout->size_B = ALIGN_POT(layout->size_B, AIL_CACHELINE); assert(layout->size_B > 0 && "Invalid dimensions"); } diff --git a/src/asahi/layout/layout.h b/src/asahi/layout/layout.h index 2282d36649d..24cab6687c2 100644 --- a/src/asahi/layout/layout.h +++ b/src/asahi/layout/layout.h @@ -48,6 +48,11 @@ enum ail_tiling { * Twiddled (Morton order). Always allowed. */ AIL_TILING_TWIDDLED, + + /** + * Twiddled (Morton order) with compression. + */ + AIL_TILING_TWIDDLED_COMPRESSED, }; /* @@ -106,6 +111,9 @@ struct ail_layout { */ struct ail_tile tilesize_el[AIL_MAX_MIP_LEVELS]; + /* Offset of the start of the compression metadata buffer */ + uint32_t metadata_offset_B; + /* Size of entire texture */ uint32_t size_B; }; @@ -174,6 +182,12 @@ ail_get_linear_pixel_B(struct ail_layout *layout, ASSERTED unsigned level, (x_px * util_format_get_blocksize(layout->format)); } +static inline bool +ail_is_compressed(struct ail_layout *layout) +{ + return layout->tiling == AIL_TILING_TWIDDLED_COMPRESSED; +} + void ail_make_miptree(struct ail_layout *layout); void diff --git a/src/asahi/layout/tests/test-layout.cpp b/src/asahi/layout/tests/test-layout.cpp index 3e007079953..08648d95ccf 100644 --- a/src/asahi/layout/tests/test-layout.cpp +++ b/src/asahi/layout/tests/test-layout.cpp @@ -56,7 +56,7 @@ TEST(Miptree, SmokeTestBuffer) ail_make_miptree(&layout); - EXPECT_EQ(layout.size_B, ALIGN_POT(81946, 0x4000)); + EXPECT_EQ(layout.size_B, ALIGN_POT(81946, AIL_CACHELINE)); } /*