From 3a67876252d616e1221e1a83b2dbe387993ad124 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Thu, 9 Aug 2018 20:17:48 -0400
Subject: [PATCH] textures: Refactor out for Texture/Depth
 FormatFromPixelFormat.

---
 .../renderer_opengl/gl_rasterizer_cache.cpp   | 31 ++++---
 .../renderer_opengl/gl_rasterizer_cache.h     | 86 -------------------
 src/video_core/textures/decoders.cpp          | 85 +-----------------
 src/video_core/textures/decoders.h            |  4 +-
 .../debugger/graphics/graphics_surface.cpp    |  6 +-
 5 files changed, 31 insertions(+), 181 deletions(-)

diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 114d35ce6..885403cd0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -183,6 +183,21 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect() const {
     return {0, actual_height, width, 0};
 }
 
+/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
+static bool IsFormatBCn(PixelFormat format) {
+    switch (format) {
+    case PixelFormat::DXT1:
+    case PixelFormat::DXT23:
+    case PixelFormat::DXT45:
+    case PixelFormat::DXN1:
+    case PixelFormat::DXN2SNORM:
+    case PixelFormat::DXN2UNORM:
+    case PixelFormat::BC7U:
+        return true;
+    }
+    return false;
+}
+
 template <bool morton_to_gl, PixelFormat format>
 void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer,
                 Tegra::GPUVAddr addr) {
@@ -191,16 +206,12 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
     const auto& gpu = Core::System::GetInstance().GPU();
 
     if (morton_to_gl) {
-        std::vector<u8> data;
-        if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) {
-            data = Tegra::Texture::UnswizzleTexture(
-                *gpu.memory_manager->GpuToCpuAddress(addr),
-                SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height);
-        } else {
-            data = Tegra::Texture::UnswizzleDepthTexture(
-                *gpu.memory_manager->GpuToCpuAddress(addr),
-                SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height);
-        }
+        // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
+        // pixel values.
+        const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
+        const std::vector<u8> data =
+            Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size,
+                                             bytes_per_pixel, stride, height, block_height);
         const size_t size_to_copy{std::min(gl_buffer.size(), data.size())};
         gl_buffer.assign(data.begin(), data.begin() + size_to_copy);
     } else {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 26e2ee203..36213c403 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -348,92 +348,6 @@ struct SurfaceParams {
         }
     }
 
-    static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) {
-        // TODO(Subv): Properly implement this
-        switch (format) {
-        case PixelFormat::ABGR8:
-        case PixelFormat::SRGBA8:
-            return Tegra::Texture::TextureFormat::A8R8G8B8;
-        case PixelFormat::B5G6R5:
-            return Tegra::Texture::TextureFormat::B5G6R5;
-        case PixelFormat::A2B10G10R10:
-            return Tegra::Texture::TextureFormat::A2B10G10R10;
-        case PixelFormat::A1B5G5R5:
-            return Tegra::Texture::TextureFormat::A1B5G5R5;
-        case PixelFormat::R8:
-            return Tegra::Texture::TextureFormat::R8;
-        case PixelFormat::G8R8:
-            return Tegra::Texture::TextureFormat::G8R8;
-        case PixelFormat::RGBA16F:
-            return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
-        case PixelFormat::R11FG11FB10F:
-            return Tegra::Texture::TextureFormat::BF10GF11RF11;
-        case PixelFormat::RGBA32UI:
-            return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
-        case PixelFormat::DXT1:
-            return Tegra::Texture::TextureFormat::DXT1;
-        case PixelFormat::DXT23:
-            return Tegra::Texture::TextureFormat::DXT23;
-        case PixelFormat::DXT45:
-            return Tegra::Texture::TextureFormat::DXT45;
-        case PixelFormat::DXN1:
-            return Tegra::Texture::TextureFormat::DXN1;
-        case PixelFormat::DXN2UNORM:
-        case PixelFormat::DXN2SNORM:
-            return Tegra::Texture::TextureFormat::DXN2;
-        case PixelFormat::BC7U:
-            return Tegra::Texture::TextureFormat::BC7U;
-        case PixelFormat::ASTC_2D_4X4:
-            return Tegra::Texture::TextureFormat::ASTC_2D_4X4;
-        case PixelFormat::BGRA8:
-            // TODO(bunnei): This is fine for unswizzling (since we just need the right component
-            // sizes), but could be a bug if we used this function in different ways.
-            return Tegra::Texture::TextureFormat::A8R8G8B8;
-        case PixelFormat::RGBA32F:
-            return Tegra::Texture::TextureFormat::R32_G32_B32_A32;
-        case PixelFormat::RGB32F:
-            return Tegra::Texture::TextureFormat::R32_G32_B32;
-        case PixelFormat::RG32F:
-            return Tegra::Texture::TextureFormat::R32_G32;
-        case PixelFormat::R32F:
-            return Tegra::Texture::TextureFormat::R32;
-        case PixelFormat::R16F:
-        case PixelFormat::R16UNORM:
-            return Tegra::Texture::TextureFormat::R16;
-        case PixelFormat::Z32F:
-            return Tegra::Texture::TextureFormat::ZF32;
-        case PixelFormat::Z24S8:
-            return Tegra::Texture::TextureFormat::Z24S8;
-        case PixelFormat::RG16F:
-        case PixelFormat::RG16:
-        case PixelFormat::RG16UI:
-        case PixelFormat::RG16I:
-        case PixelFormat::RG16S:
-            return Tegra::Texture::TextureFormat::R16_G16;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
-    static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) {
-        switch (format) {
-        case PixelFormat::S8Z24:
-            return Tegra::DepthFormat::S8_Z24_UNORM;
-        case PixelFormat::Z24S8:
-            return Tegra::DepthFormat::Z24_S8_UNORM;
-        case PixelFormat::Z32F:
-            return Tegra::DepthFormat::Z32_FLOAT;
-        case PixelFormat::Z16:
-            return Tegra::DepthFormat::Z16_UNORM;
-        case PixelFormat::Z32FS8:
-            return Tegra::DepthFormat::Z32_S8_X24_FLOAT;
-        default:
-            LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
-            UNREACHABLE();
-        }
-    }
-
     static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
         // TODO(Subv): Implement more component types
         switch (type) {
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 7ea66584c..70746a34e 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -86,88 +86,11 @@ u32 BytesPerPixel(TextureFormat format) {
     }
 }
 
-static u32 DepthBytesPerPixel(DepthFormat format) {
-    switch (format) {
-    case DepthFormat::Z16_UNORM:
-        return 2;
-    case DepthFormat::S8_Z24_UNORM:
-    case DepthFormat::Z24_S8_UNORM:
-    case DepthFormat::Z32_FLOAT:
-        return 4;
-    case DepthFormat::Z32_S8_X24_FLOAT:
-        return 8;
-    default:
-        UNIMPLEMENTED_MSG("Format not implemented");
-        break;
-    }
-}
-
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
-                                 u32 block_height) {
-    u8* data = Memory::GetPointer(address);
-    u32 bytes_per_pixel = BytesPerPixel(format);
-
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
+                                 u32 height, u32 block_height) {
     std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
-
-    switch (format) {
-    case TextureFormat::DXT1:
-    case TextureFormat::DXT23:
-    case TextureFormat::DXT45:
-    case TextureFormat::DXN1:
-    case TextureFormat::DXN2:
-    case TextureFormat::BC7U:
-        // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel
-        // values.
-        CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
-                         unswizzled_data.data(), true, block_height);
-        break;
-    case TextureFormat::A8R8G8B8:
-    case TextureFormat::A2B10G10R10:
-    case TextureFormat::A1B5G5R5:
-    case TextureFormat::B5G6R5:
-    case TextureFormat::R8:
-    case TextureFormat::G8R8:
-    case TextureFormat::R16_G16_B16_A16:
-    case TextureFormat::R32_G32_B32_A32:
-    case TextureFormat::R32_G32:
-    case TextureFormat::R32:
-    case TextureFormat::R16:
-    case TextureFormat::R16_G16:
-    case TextureFormat::BF10GF11RF11:
-    case TextureFormat::ASTC_2D_4X4:
-    case TextureFormat::R32_G32_B32:
-        CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
-                         unswizzled_data.data(), true, block_height);
-        break;
-    default:
-        UNIMPLEMENTED_MSG("Format not implemented");
-        break;
-    }
-
-    return unswizzled_data;
-}
-
-std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height,
-                                      u32 block_height) {
-    u8* data = Memory::GetPointer(address);
-    u32 bytes_per_pixel = DepthBytesPerPixel(format);
-
-    std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
-
-    switch (format) {
-    case DepthFormat::Z16_UNORM:
-    case DepthFormat::S8_Z24_UNORM:
-    case DepthFormat::Z24_S8_UNORM:
-    case DepthFormat::Z32_FLOAT:
-    case DepthFormat::Z32_S8_X24_FLOAT:
-        CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
-                         unswizzled_data.data(), true, block_height);
-        break;
-    default:
-        UNIMPLEMENTED_MSG("Format not implemented");
-        break;
-    }
-
+    CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
+                     Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
     return unswizzled_data;
 }
 
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 73a4924d1..1f7b731be 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -13,8 +13,8 @@ namespace Tegra::Texture {
 /**
  * Unswizzles a swizzled texture without changing its format.
  */
-std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height,
-                                 u32 block_height = TICEntry::DefaultBlockHeight);
+std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
+                                 u32 height, u32 block_height = TICEntry::DefaultBlockHeight);
 
 /**
  * Unswizzles a swizzled depth texture without changing its format.
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 3f7103ab9..e037223c2 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -383,8 +383,10 @@ void GraphicsSurfaceWidget::OnUpdate() {
     QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
     boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address);
 
-    auto unswizzled_data =
-        Tegra::Texture::UnswizzleTexture(*address, surface_format, surface_width, surface_height);
+    // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
+    // Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
+    auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
+        *address, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height);
 
     auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
                                                       surface_width, surface_height);