diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/textures/decoders.cpp | 51 |
1 files changed, 49 insertions, 2 deletions
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 58b65de1a..20ba6d4f6 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -46,6 +46,48 @@ void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_ | |||
| 46 | } | 46 | } |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | template <std::size_t N, std::size_t M> | ||
| 50 | struct alignas(64) SwizzleTable { | ||
| 51 | constexpr SwizzleTable() { | ||
| 52 | for (u32 y = 0; y < N; ++y) { | ||
| 53 | for (u32 x = 0; x < M; ++x) { | ||
| 54 | const u32 x2 = x * 16; | ||
| 55 | values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 + | ||
| 56 | ((x2 % 32) / 16) * 32 + (y % 2) * 16); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } | ||
| 60 | const std::array<u16, M>& operator[](std::size_t index) const { | ||
| 61 | return values[index]; | ||
| 62 | } | ||
| 63 | std::array<std::array<u16, M>, N> values{}; | ||
| 64 | }; | ||
| 65 | |||
| 66 | constexpr auto swizzle_table = SwizzleTable<8, 4>(); | ||
| 67 | |||
| 68 | void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_data, | ||
| 69 | u8* unswizzled_data, bool unswizzle, u32 block_height) { | ||
| 70 | std::array<u8*, 2> data_ptrs; | ||
| 71 | const std::size_t stride{width * bytes_per_pixel}; | ||
| 72 | const std::size_t image_width_in_gobs{(stride + 63) / 64}; | ||
| 73 | const std::size_t copy_size{16}; | ||
| 74 | for (std::size_t y = 0; y < height; ++y) { | ||
| 75 | const std::size_t initial_gob = | ||
| 76 | (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs + | ||
| 77 | (y % (8 * block_height) / 8) * 512; | ||
| 78 | const std::size_t pixel_base{y * width * bytes_per_pixel}; | ||
| 79 | const auto& table = swizzle_table[y % 8]; | ||
| 80 | for (std::size_t xb = 0; xb < stride; xb += copy_size) { | ||
| 81 | const std::size_t gob_address{initial_gob + (xb / 64) * 512 * block_height}; | ||
| 82 | const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]}; | ||
| 83 | const std::size_t pixel_index{xb + pixel_base}; | ||
| 84 | data_ptrs[unswizzle] = swizzled_data + swizzle_offset; | ||
| 85 | data_ptrs[!unswizzle] = unswizzled_data + pixel_index; | ||
| 86 | std::memcpy(data_ptrs[0], data_ptrs[1], copy_size); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 49 | u32 BytesPerPixel(TextureFormat format) { | 91 | u32 BytesPerPixel(TextureFormat format) { |
| 50 | switch (format) { | 92 | switch (format) { |
| 51 | case TextureFormat::DXT1: | 93 | case TextureFormat::DXT1: |
| @@ -92,8 +134,13 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 92 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, | 134 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, |
| 93 | u32 height, u32 block_height) { | 135 | u32 height, u32 block_height) { |
| 94 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); | 136 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); |
| 95 | CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, | 137 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) { |
| 96 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); | 138 | FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel, |
| 139 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); | ||
| 140 | } else { | ||
| 141 | CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, | ||
| 142 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); | ||
| 143 | } | ||
| 97 | return unswizzled_data; | 144 | return unswizzled_data; |
| 98 | } | 145 | } |
| 99 | 146 | ||