From 3af03332cc759b6245e50e7527fc5ec85f6248d4 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Mon, 10 Aug 2026 01:41:21 -0400 Subject: [PATCH] [TEST] fast path on swizzle decoding --- src/video_core/textures/decoders.cpp | 94 +++++++++++++++++----------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 25b0860b0f..ffba46181c 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -1,9 +1,10 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -30,12 +31,63 @@ constexpr u32 pdep(u32 value) { return result; } +constexpr u32 SWIZZLE_RUN_BYTES = 16; +constexpr u32 SWIZZLE_RUN_SHIFT = 4; +constexpr u32 SWIZZLE_RUN_MASK = SWIZZLE_RUN_BYTES - 1; +constexpr u32 SWIZZLE_RUN_INDEX_MASK = GOB_SIZE_X / SWIZZLE_RUN_BYTES - 1; + +static_assert((SWIZZLE_X_BITS & SWIZZLE_RUN_MASK) == SWIZZLE_RUN_MASK, + "A swizzled run is only contiguous while the low bits of X map to themselves"); + +constexpr std::array SWIZZLE_X_RUN_TABLE = [] { + std::array table{}; + for (u32 index = 0; index < static_cast(table.size()); ++index) { + table[index] = pdep(index << SWIZZLE_RUN_SHIFT); + } + return table; +}(); + template void incrpdep(u32& value) { static constexpr u32 swizzled_incr = pdep(incr_amount); value = ((value | ~mask) + swizzled_incr) & mask; } +template +void SwizzleRow(std::span output, std::span input, u32 offset_zy, u32 swizzled_y, + u32 x_shift, u32 x, u32 num_bytes, u32 linear) { + const auto copy = [&](u32 swizzled_x, u32 count) { + const u32 swizzled = + offset_zy + ((x >> GOB_SIZE_X_SHIFT) << x_shift) + (swizzled_x | swizzled_y); + u8* const dst = &output[TO_LINEAR ? swizzled : linear]; + const u8* const src = &input[TO_LINEAR ? linear : swizzled]; + std::memcpy(dst, src, count); + x += count; + linear += count; + }; + + u32 swizzled_run = SWIZZLE_X_RUN_TABLE[(x >> SWIZZLE_RUN_SHIFT) & SWIZZLE_RUN_INDEX_MASK]; + u32 remaining = num_bytes; + + const u32 head = + (std::min)(SWIZZLE_RUN_BYTES - (x & SWIZZLE_RUN_MASK), remaining) & SWIZZLE_RUN_MASK; + if (head != 0) { + copy(swizzled_run | (x & SWIZZLE_RUN_MASK), head); + remaining -= head; + incrpdep(swizzled_run); + } + + while (remaining >= SWIZZLE_RUN_BYTES) { + copy(swizzled_run, SWIZZLE_RUN_BYTES); + remaining -= SWIZZLE_RUN_BYTES; + incrpdep(swizzled_run); + } + + if (remaining != 0) { + copy(swizzled_run, remaining); + } +} + template void SwizzleImpl(std::span output, std::span input, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth, u32 stride) { @@ -70,23 +122,9 @@ void SwizzleImpl(std::span output, std::span input, u32 width, u32 const u32 offset_y = (block_y >> block_height) * block_size + ((block_y & block_height_mask) << GOB_SIZE_SHIFT); - u32 swizzled_x = pdep(origin_x * BYTES_PER_PIXEL); - for (u32 column = 0; column < width; - ++column, incrpdep(swizzled_x)) { - const u32 x = (column + origin_x) * BYTES_PER_PIXEL; - const u32 offset_x = (x >> GOB_SIZE_X_SHIFT) << x_shift; - - const u32 base_swizzled_offset = offset_z + offset_y + offset_x; - const u32 swizzled_offset = base_swizzled_offset + (swizzled_x | swizzled_y); - - const u32 unswizzled_offset = - slice * pitch * height + line * pitch + column * BYTES_PER_PIXEL; - - u8* const dst = &output[TO_LINEAR ? swizzled_offset : unswizzled_offset]; - const u8* const src = &input[TO_LINEAR ? unswizzled_offset : swizzled_offset]; - - std::memcpy(dst, src, BYTES_PER_PIXEL); - } + SwizzleRow(output, input, offset_z + offset_y, swizzled_y, x_shift, + origin_x * BYTES_PER_PIXEL, width * BYTES_PER_PIXEL, + slice * pitch * height + line * pitch); } } } @@ -129,23 +167,9 @@ void SwizzleSubrectImpl(std::span output, std::span input, u32 wid const u32 offset_y = (block_y >> block_height) * block_size + ((block_y & block_height_mask) << GOB_SIZE_SHIFT); - u32 swizzled_x = pdep(origin_x * BYTES_PER_PIXEL); - for (u32 column = 0; column < extent_x; - ++column, incrpdep(swizzled_x)) { - const u32 x = (column + origin_x) * BYTES_PER_PIXEL; - const u32 offset_x = (x >> GOB_SIZE_X_SHIFT) << x_shift; - - const u32 base_swizzled_offset = offset_z + offset_y + offset_x; - const u32 swizzled_offset = base_swizzled_offset + (swizzled_x | swizzled_y); - - const u32 unswizzled_offset = - slice * pitch * height + line * pitch + column * BYTES_PER_PIXEL; - - u8* const dst = &output[TO_LINEAR ? swizzled_offset : unswizzled_offset]; - const u8* const src = &input[TO_LINEAR ? unswizzled_offset : swizzled_offset]; - - std::memcpy(dst, src, BYTES_PER_PIXEL); - } + SwizzleRow(output, input, offset_z + offset_y, swizzled_y, x_shift, + origin_x * BYTES_PER_PIXEL, extent_x * BYTES_PER_PIXEL, + slice * pitch * height + line * pitch); } unprocessed_lines -= lines_in_y; if (unprocessed_lines == 0) {