From bcde71d4d93abb40539058e683fd39dd8ad39760 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 17 Oct 2018 21:26:40 -0400
Subject: [PATCH] decoders: Introduce functions for un/swizzling subrects.

---
 src/video_core/textures/decoders.cpp | 40 ++++++++++++++++++++++++++++
 src/video_core/textures/decoders.h   |  9 +++++++
 2 files changed, 49 insertions(+)

diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 18ab723f73..f1b40e7f55 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -237,6 +237,46 @@ std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pix
     return unswizzled_data;
 }
 
+void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
+                    u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
+                    u32 block_height) {
+    const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + 63) / 64};
+    for (u32 line = 0; line < subrect_height; ++line) {
+        const u32 gob_address_y =
+            (line / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
+            (line % (8 * block_height) / 8) * 512;
+        const auto& table = legacy_swizzle_table[line % 8];
+        for (u32 x = 0; x < subrect_width; ++x) {
+            const u32 gob_address = gob_address_y + (x * bytes_per_pixel / 64) * 512 * block_height;
+            const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % 64];
+            const VAddr source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel;
+            const VAddr dest_addr = swizzled_data + swizzled_offset;
+
+            Memory::CopyBlock(dest_addr, source_line, bytes_per_pixel);
+        }
+    }
+}
+
+void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width,
+                      u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
+                      u32 block_height, u32 offset_x, u32 offset_y) {
+    for (u32 line = 0; line < subrect_height; ++line) {
+        const u32 y2 = line + offset_y;
+        const u32 gob_address_y =
+            (y2 / (8 * block_height)) * 512 * block_height + (y2 % (8 * block_height) / 8) * 512;
+        const auto& table = legacy_swizzle_table[y2 % 8];
+        for (u32 x = 0; x < subrect_width; ++x) {
+            const u32 x2 = (x + offset_x) * bytes_per_pixel;
+            const u32 gob_address = gob_address_y + (x2 / 64) * 512 * block_height;
+            const u32 swizzled_offset = gob_address + table[x2 % 64];
+            const VAddr dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel;
+            const VAddr source_addr = swizzled_data + swizzled_offset;
+
+            Memory::CopyBlock(dest_line, source_addr, bytes_per_pixel);
+        }
+    }
+}
+
 std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat format, u32 width,
                               u32 height) {
     std::vector<u8> rgba_data;
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index aaf316947e..4726f54a5e 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -35,4 +35,13 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
 std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
                           u32 block_height, u32 block_depth);
 
+/// Copies an untiled subrectangle into a tiled surface.
+void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width,
+                    u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
+                    u32 block_height);
+/// Copies a tiled subrectangle into a linear surface.
+void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width,
+                      u32 bytes_per_pixel, VAddr swizzled_data, VAddr unswizzled_data,
+                      u32 block_height, u32 offset_x, u32 offset_y);
+
 } // namespace Tegra::Texture