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)); } /*