From 6d9f347e22d3b198ff8f623d1efafcf7dae27321 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp <reinuseslisp@airmail.cc>
Date: Sun, 18 Jul 2021 00:44:32 -0300
Subject: [PATCH] texture_cache/util: Fix size calculations of multisampled
 images

On the texture cache we handle multisampled images by keeping their real
size in samples (e.g. 1920x1080 with 4 samples is 3840x2160).

This works nicely with size matches and other comparisons, but the
calculation for guest sizes was not having this in mind, and the size
was being multiplied (again) by the number of samples per dimension.
For example a 3840x2160 texture cache image had its width and height
multiplied by 2, resulting in a much larger texture.

Fix this issue.

- Fixes performance regression on cooking related titles when an
  unrelated bug was fixed.
---
 src/video_core/texture_cache/util.cpp | 84 ++++++++++-----------------
 1 file changed, 32 insertions(+), 52 deletions(-)

diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp
index c872517b8..59cf2f561 100644
--- a/src/video_core/texture_cache/util.cpp
+++ b/src/video_core/texture_cache/util.cpp
@@ -169,23 +169,6 @@ template <u32 GOB_EXTENT>
     return Common::DivCeil(AdjustMipSize(size, level), block_size);
 }
 
-[[nodiscard]] constexpr std::pair<int, int> Samples(int num_samples) {
-    switch (num_samples) {
-    case 1:
-        return {1, 1};
-    case 2:
-        return {2, 1};
-    case 4:
-        return {2, 2};
-    case 8:
-        return {4, 2};
-    case 16:
-        return {4, 4};
-    }
-    UNREACHABLE_MSG("Invalid number of samples={}", num_samples);
-    return {1, 1};
-}
-
 [[nodiscard]] constexpr Extent2D DefaultBlockSize(PixelFormat format) {
     return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
 }
@@ -283,14 +266,13 @@ template <u32 GOB_EXTENT>
 }
 
 [[nodiscard]] constexpr LevelInfo MakeLevelInfo(PixelFormat format, Extent3D size, Extent3D block,
-                                                u32 num_samples, u32 tile_width_spacing) {
-    const auto [samples_x, samples_y] = Samples(num_samples);
+                                                u32 tile_width_spacing) {
     const u32 bytes_per_block = BytesPerBlock(format);
     return {
         .size =
             {
-                .width = size.width * samples_x,
-                .height = size.height * samples_y,
+                .width = size.width,
+                .height = size.height,
                 .depth = size.depth,
             },
         .block = block,
@@ -301,14 +283,12 @@ template <u32 GOB_EXTENT>
 }
 
 [[nodiscard]] constexpr LevelInfo MakeLevelInfo(const ImageInfo& info) {
-    return MakeLevelInfo(info.format, info.size, info.block, info.num_samples,
-                         info.tile_width_spacing);
+    return MakeLevelInfo(info.format, info.size, info.block, info.tile_width_spacing);
 }
 
 [[nodiscard]] constexpr u32 CalculateLevelOffset(PixelFormat format, Extent3D size, Extent3D block,
-                                                 u32 num_samples, u32 tile_width_spacing,
-                                                 u32 level) {
-    const LevelInfo info = MakeLevelInfo(format, size, block, num_samples, tile_width_spacing);
+                                                 u32 tile_width_spacing, u32 level) {
+    const LevelInfo info = MakeLevelInfo(format, size, block, tile_width_spacing);
     u32 offset = 0;
     for (u32 current_level = 0; current_level < level; ++current_level) {
         offset += CalculateLevelSize(info, current_level);
@@ -645,8 +625,8 @@ u32 CalculateLayerStride(const ImageInfo& info) noexcept {
 
 u32 CalculateLayerSize(const ImageInfo& info) noexcept {
     ASSERT(info.type != ImageType::Linear);
-    return CalculateLevelOffset(info.format, info.size, info.block, info.num_samples,
-                                info.tile_width_spacing, info.resources.levels);
+    return CalculateLevelOffset(info.format, info.size, info.block, info.tile_width_spacing,
+                                info.resources.levels);
 }
 
 LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
@@ -1195,37 +1175,37 @@ static_assert(CalculateLevelSize(LevelInfo{{1920, 1080, 1}, {0, 2, 0}, {1, 1}, 2
               0x7f8000);
 static_assert(CalculateLevelSize(LevelInfo{{32, 32, 1}, {0, 0, 4}, {1, 1}, 4, 0}, 0) == 0x4000);
 
-static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 1, 0, 7) ==
+static_assert(CalculateLevelOffset(PixelFormat::R8_SINT, {1920, 1080, 1}, {0, 2, 0}, 0, 7) ==
               0x2afc00);
-static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 1,
-                                   0, 12) == 0x50d200);
+static_assert(CalculateLevelOffset(PixelFormat::ASTC_2D_12X12_UNORM, {8192, 4096, 1}, {0, 2, 0}, 0,
+                                   12) == 0x50d200);
 
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   0) == 0);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   1) == 0x400000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   2) == 0x500000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   3) == 0x540000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   4) == 0x550000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   5) == 0x554000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   6) == 0x555000);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   7) == 0x555400);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   8) == 0x555600);
-static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 1, 0,
-                                   9) == 0x555800);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 0) ==
+              0);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 1) ==
+              0x400000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 2) ==
+              0x500000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 3) ==
+              0x540000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 4) ==
+              0x550000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 5) ==
+              0x554000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 6) ==
+              0x555000);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 7) ==
+              0x555400);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 8) ==
+              0x555600);
+static_assert(CalculateLevelOffset(PixelFormat::A8B8G8R8_UNORM, {1024, 1024, 1}, {0, 4, 0}, 0, 9) ==
+              0x555800);
 
 constexpr u32 ValidateLayerSize(PixelFormat format, u32 width, u32 height, u32 block_height,
                                 u32 tile_width_spacing, u32 level) {
     const Extent3D size{width, height, 1};
     const Extent3D block{0, block_height, 0};
-    const u32 offset = CalculateLevelOffset(format, size, block, 1, tile_width_spacing, level);
+    const u32 offset = CalculateLevelOffset(format, size, block, tile_width_spacing, level);
     return AlignLayerSize(offset, size, block, DefaultBlockHeight(format), tile_width_spacing);
 }