Просмотр исходного кода

Correct Surface Base and Views for new Texture Cache

Fernando Sahmkow 7 лет назад
Родитель
Сommit
3d471e732d

+ 25 - 0
src/video_core/texture_cache/copy_params.h

@@ -0,0 +1,25 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace VideoCommon {
+
+struct CopyParams {
+    u32 source_x;
+    u32 source_y;
+    u32 source_z;
+    u32 dest_x;
+    u32 dest_y;
+    u32 dest_z;
+    u32 source_level;
+    u32 dest_level;
+    u32 width;
+    u32 height;
+    u32 depth;
+};
+
+} // namespace VideoCommon

+ 62 - 46
src/video_core/texture_cache/surface_base.cpp

@@ -4,104 +4,120 @@
 
 
 #include "common/assert.h"
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/common_types.h"
-#include "video_core/morton.h"
+#include "common/microprofile.h"
+#include "video_core/memory_manager.h"
 #include "video_core/texture_cache/surface_base.h"
 #include "video_core/texture_cache/surface_base.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/textures/convert.h"
 #include "video_core/textures/convert.h"
 
 
 namespace VideoCommon {
 namespace VideoCommon {
 
 
+MICROPROFILE_DEFINE(GPU_Load_Texture, "GPU", "Texture Load", MP_RGB(128, 192, 128));
+MICROPROFILE_DEFINE(GPU_Flush_Texture, "GPU", "Texture Flush", MP_RGB(128, 192, 128));
+
 using Tegra::Texture::ConvertFromGuestToHost;
 using Tegra::Texture::ConvertFromGuestToHost;
 using VideoCore::MortonSwizzleMode;
 using VideoCore::MortonSwizzleMode;
 
 
-namespace {
-void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
-                 u32 level) {
+SurfaceBaseImpl::SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params)
+    : gpu_addr{gpu_vaddr}, params{params}, mipmap_sizes{params.num_levels},
+      mipmap_offsets{params.num_levels}, layer_size{params.GetGuestLayerSize()},
+      memory_size{params.GetGuestSizeInBytes()}, host_memory_size{params.GetHostSizeInBytes()} {
+    u32 offset = 0;
+    mipmap_offsets.resize(params.num_levels);
+    mipmap_sizes.resize(params.num_levels);
+    gpu_addr_end = gpu_addr + memory_size;
+    for (u32 i = 0; i < params.num_levels; i++) {
+        mipmap_offsets[i] = offset;
+        mipmap_sizes[i] = params.GetGuestMipmapSize(i);
+        offset += mipmap_sizes[i];
+    }
+}
+
+void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params,
+                                  u8* buffer, u32 level) {
     const u32 width{params.GetMipWidth(level)};
     const u32 width{params.GetMipWidth(level)};
     const u32 height{params.GetMipHeight(level)};
     const u32 height{params.GetMipHeight(level)};
     const u32 block_height{params.GetMipBlockHeight(level)};
     const u32 block_height{params.GetMipBlockHeight(level)};
     const u32 block_depth{params.GetMipBlockDepth(level)};
     const u32 block_depth{params.GetMipBlockDepth(level)};
 
 
-    std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)};
-    if (params.IsLayered()) {
+    std::size_t guest_offset{mipmap_offsets[level]};
+    if (params.is_layered) {
         std::size_t host_offset{0};
         std::size_t host_offset{0};
-        const std::size_t guest_stride = params.GetGuestLayerSize();
+        const std::size_t guest_stride = layer_size;
         const std::size_t host_stride = params.GetHostLayerSize(level);
         const std::size_t host_stride = params.GetHostLayerSize(level);
-        for (u32 layer = 0; layer < params.GetNumLayers(); layer++) {
-            MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
-                          1, params.GetTileWidthSpacing(), buffer + host_offset,
-                          memory + guest_offset);
+        for (u32 layer = 0; layer < params.depth; layer++) {
+            MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth, 1,
+                          params.tile_width_spacing, buffer + host_offset, memory + guest_offset);
             guest_offset += guest_stride;
             guest_offset += guest_stride;
             host_offset += host_stride;
             host_offset += host_stride;
         }
         }
     } else {
     } else {
-        MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth,
-                      params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer,
+        MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth,
+                      params.GetMipDepth(level), params.tile_width_spacing, buffer,
                       memory + guest_offset);
                       memory + guest_offset);
     }
     }
 }
 }
-} // Anonymous namespace
 
 
-SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} {
-    staging_buffer.resize(params.GetHostSizeInBytes());
-}
-
-SurfaceBaseImpl::~SurfaceBaseImpl() = default;
-
-void SurfaceBaseImpl::LoadBuffer() {
-    if (params.IsTiled()) {
-        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}",
-                   params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
-        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
+void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager,
+                                 std::vector<u8>& staging_buffer) {
+    MICROPROFILE_SCOPE(GPU_Load_Texture);
+    auto host_ptr = memory_manager.GetPointer(gpu_addr);
+    if (params.is_tiled) {
+        ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture target {}",
+                   params.block_width, static_cast<u32>(params.target));
+        for (u32 level = 0; level < params.num_levels; ++level) {
+            const u32 host_offset = params.GetHostMipmapLevelOffset(level);
             SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params,
             SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params,
-                        GetStagingBufferLevelData(level), level);
+                        staging_buffer.data() + host_offset, level);
         }
         }
     } else {
     } else {
-        ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented");
-        const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT};
+        ASSERT_MSG(params.num_levels == 1, "Linear mipmap loading is not implemented");
+        const u32 bpp{params.GetBytesPerPixel()};
         const u32 block_width{params.GetDefaultBlockWidth()};
         const u32 block_width{params.GetDefaultBlockWidth()};
         const u32 block_height{params.GetDefaultBlockHeight()};
         const u32 block_height{params.GetDefaultBlockHeight()};
-        const u32 width{(params.GetWidth() + block_width - 1) / block_width};
-        const u32 height{(params.GetHeight() + block_height - 1) / block_height};
+        const u32 width{(params.width + block_width - 1) / block_width};
+        const u32 height{(params.height + block_height - 1) / block_height};
         const u32 copy_size{width * bpp};
         const u32 copy_size{width * bpp};
-        if (params.GetPitch() == copy_size) {
+        if (params.pitch == copy_size) {
             std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
             std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
         } else {
         } else {
             const u8* start{host_ptr};
             const u8* start{host_ptr};
             u8* write_to{staging_buffer.data()};
             u8* write_to{staging_buffer.data()};
             for (u32 h = height; h > 0; --h) {
             for (u32 h = height; h > 0; --h) {
                 std::memcpy(write_to, start, copy_size);
                 std::memcpy(write_to, start, copy_size);
-                start += params.GetPitch();
+                start += params.pitch;
                 write_to += copy_size;
                 write_to += copy_size;
             }
             }
         }
         }
     }
     }
 
 
-    for (u32 level = 0; level < params.GetNumLevels(); ++level) {
-        ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(),
+    for (u32 level = 0; level < params.num_levels; ++level) {
+        const u32 host_offset = params.GetHostMipmapLevelOffset(level);
+        ConvertFromGuestToHost(staging_buffer.data() + host_offset, params.pixel_format,
                                params.GetMipWidth(level), params.GetMipHeight(level),
                                params.GetMipWidth(level), params.GetMipHeight(level),
                                params.GetMipDepth(level), true, true);
                                params.GetMipDepth(level), true, true);
     }
     }
 }
 }
 
 
-void SurfaceBaseImpl::FlushBuffer() {
-    if (params.IsTiled()) {
-        ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}",
-                   params.GetBlockWidth());
-        for (u32 level = 0; level < params.GetNumLevels(); ++level) {
-            SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params,
-                        GetStagingBufferLevelData(level), level);
+void SurfaceBaseImpl::FlushBuffer(std::vector<u8>& staging_buffer) {
+    MICROPROFILE_SCOPE(GPU_Flush_Texture);
+    if (params.is_tiled) {
+        ASSERT_MSG(params.block_width == 1, "Block width is defined as {}", params.block_width);
+        for (u32 level = 0; level < params.num_levels; ++level) {
+            const u32 host_offset = params.GetHostMipmapLevelOffset(level);
+            SwizzleFunc(MortonSwizzleMode::LinearToMorton, host_ptr, params,
+                        staging_buffer.data() + host_offset, level);
         }
         }
     } else {
     } else {
         UNIMPLEMENTED();
         UNIMPLEMENTED();
         /*
         /*
-        ASSERT(params.GetTarget() == SurfaceTarget::Texture2D);
-        ASSERT(params.GetNumLevels() == 1);
+        ASSERT(params.target == SurfaceTarget::Texture2D);
+        ASSERT(params.num_levels == 1);
 
 
         const u32 bpp{params.GetFormatBpp() / 8};
         const u32 bpp{params.GetFormatBpp() / 8};
-        const u32 copy_size{params.GetWidth() * bpp};
-        if (params.GetPitch() == copy_size) {
-            std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes());
+        const u32 copy_size{params.width * bpp};
+        if (params.pitch == copy_size) {
+            std::memcpy(host_ptr, staging_buffer.data(), memory_size);
         } else {
         } else {
             u8* start{host_ptr};
             u8* start{host_ptr};
             const u8* read_to{staging_buffer.data()};
             const u8* read_to{staging_buffer.data()};

+ 220 - 77
src/video_core/texture_cache/surface_base.h

@@ -4,166 +4,309 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <algorithm>
 #include <unordered_map>
 #include <unordered_map>
+#include <vector>
 
 
 #include "common/assert.h"
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "video_core/gpu.h"
 #include "video_core/gpu.h"
+#include "video_core/morton.h"
+#include "video_core/texture_cache/copy_params.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/texture_cache/surface_view.h"
 #include "video_core/texture_cache/surface_view.h"
 
 
+template<class ForwardIt, class T, class Compare=std::less<>>
+ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={})
+{
+    // Note: BOTH type T and the type after ForwardIt is dereferenced
+    // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
+    // This is stricter than lower_bound requirement (see above)
+
+    first = std::lower_bound(first, last, value, comp);
+    return first != last && !comp(value, *first) ? first : last;
+}
+
+namespace Tegra {
+class MemoryManager;
+}
+
 namespace VideoCommon {
 namespace VideoCommon {
 
 
+using VideoCore::Surface::SurfaceTarget;
+using VideoCore::MortonSwizzleMode;
+
 class SurfaceBaseImpl {
 class SurfaceBaseImpl {
 public:
 public:
-    void LoadBuffer();
+    void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
 
 
-    void FlushBuffer();
+    void FlushBuffer(std::vector<u8>& staging_buffer);
 
 
     GPUVAddr GetGpuAddr() const {
     GPUVAddr GetGpuAddr() const {
-        ASSERT(is_registered);
         return gpu_addr;
         return gpu_addr;
     }
     }
 
 
+    GPUVAddr GetGpuAddrEnd() const {
+        return gpu_addr_end;
+    }
+
+    bool Overlaps(const GPUVAddr start, const GPUVAddr end) const {
+        return (gpu_addr < end) && (gpu_addr_end > start);
+    }
+
+    // Use only when recycling a surface
+    void SetGpuAddr(const GPUVAddr new_addr) {
+        gpu_addr = new_addr;
+        gpu_addr_end = new_addr + memory_size;
+    }
+
     VAddr GetCpuAddr() const {
     VAddr GetCpuAddr() const {
-        ASSERT(is_registered);
-        return cpu_addr;
+        return gpu_addr;
+    }
+
+    void SetCpuAddr(const VAddr new_addr) {
+        cpu_addr = new_addr;
     }
     }
 
 
     u8* GetHostPtr() const {
     u8* GetHostPtr() const {
-        ASSERT(is_registered);
         return host_ptr;
         return host_ptr;
     }
     }
 
 
-    CacheAddr GetCacheAddr() const {
-        ASSERT(is_registered);
-        return cache_addr;
+    void SetHostPtr(u8* new_addr) {
+        host_ptr = new_addr;
     }
     }
 
 
     const SurfaceParams& GetSurfaceParams() const {
     const SurfaceParams& GetSurfaceParams() const {
         return params;
         return params;
     }
     }
 
 
-    void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) {
-        ASSERT(!is_registered);
-        is_registered = true;
-        gpu_addr = gpu_addr_;
-        cpu_addr = cpu_addr_;
-        host_ptr = host_ptr_;
-        cache_addr = ToCacheAddr(host_ptr_);
-        DecorateSurfaceName();
+    std::size_t GetSizeInBytes() const {
+        return memory_size;
     }
     }
 
 
-    void Unregister() {
-        ASSERT(is_registered);
-        is_registered = false;
+    std::size_t GetHostSizeInBytes() const {
+        return host_memory_size;
     }
     }
 
 
-    bool IsRegistered() const {
-        return is_registered;
+    std::size_t GetMipmapSize(const u32 level) const {
+        return mipmap_sizes[level];
     }
     }
 
 
-    std::size_t GetSizeInBytes() const {
-        return params.GetGuestSizeInBytes();
+    bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const {
+        return params.pixel_format == pixel_format;
+    }
+
+    bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const {
+        return params.target == target;
+    }
+
+    bool MatchesTopology(const SurfaceParams& rhs) const {
+        const u32 src_bpp = params.GetBytesPerPixel();
+        const u32 dst_bpp = rhs.GetBytesPerPixel();
+        return std::tie(src_bpp, params.is_tiled) == std::tie(dst_bpp, rhs.is_tiled);
+    }
+
+    bool MatchesStructure(const SurfaceParams& rhs) const {
+        if (params.is_tiled) {
+            const u32 a_width1 = params.GetBlockAlignedWidth();
+            const u32 a_width2 = rhs.GetBlockAlignedWidth();
+            return std::tie(a_width1, params.height, params.depth, params.block_width,
+                            params.block_height, params.block_depth, params.tile_width_spacing) ==
+                   std::tie(a_width2, rhs.height, rhs.depth, rhs.block_width, rhs.block_height,
+                            rhs.block_depth, rhs.tile_width_spacing);
+        } else {
+            return std::tie(params.width, params.height, params.pitch) ==
+                   std::tie(rhs.width, rhs.height, rhs.pitch);
+        }
+    }
+
+    std::optional<std::pair<u32, u32>> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const {
+        if (candidate_gpu_addr < gpu_addr)
+            return {};
+        const GPUVAddr relative_address = candidate_gpu_addr - gpu_addr;
+        const u32 layer = relative_address / layer_size;
+        const GPUVAddr mipmap_address = relative_address - layer_size * layer;
+        const auto mipmap_it = binary_find(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address);
+        if (mipmap_it != mipmap_offsets.end()) {
+            return {{layer, std::distance(mipmap_offsets.begin(), mipmap_it)}};
+        }
+        return {};
     }
     }
 
 
-    u8* GetStagingBufferLevelData(u32 level) {
-        return staging_buffer.data() + params.GetHostMipmapLevelOffset(level);
+    std::vector<CopyParams> BreakDown() const {
+        auto set_up_copy = [](CopyParams& cp, const SurfaceParams& params, const u32 depth,
+                              const u32 level) {
+            cp.source_x = 0;
+            cp.source_y = 0;
+            cp.source_z = 0;
+            cp.dest_x = 0;
+            cp.dest_y = 0;
+            cp.dest_z = 0;
+            cp.source_level = level;
+            cp.dest_level = level;
+            cp.width = params.GetMipWidth(level);
+            cp.height = params.GetMipHeight(level);
+            cp.depth = depth;
+        };
+        const u32 layers = params.depth;
+        const u32 mipmaps = params.num_levels;
+        if (params.is_layered) {
+            std::vector<CopyParams> result{layers * mipmaps};
+            for (std::size_t layer = 0; layer < layers; layer++) {
+                const u32 layer_offset = layer * mipmaps;
+                for (std::size_t level = 0; level < mipmaps; level++) {
+                    CopyParams& cp = result[layer_offset + level];
+                    set_up_copy(cp, params, layer, level);
+                }
+            }
+            return result;
+        } else {
+            std::vector<CopyParams> result{mipmaps};
+            for (std::size_t level = 0; level < mipmaps; level++) {
+                CopyParams& cp = result[level];
+                set_up_copy(cp, params, params.GetMipDepth(level), level);
+            }
+            return result;
+        }
     }
     }
 
 
 protected:
 protected:
-    explicit SurfaceBaseImpl(const SurfaceParams& params);
-    ~SurfaceBaseImpl(); // non-virtual is intended
+    explicit SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params);
+    ~SurfaceBaseImpl() = default;
 
 
     virtual void DecorateSurfaceName() = 0;
     virtual void DecorateSurfaceName() = 0;
 
 
     const SurfaceParams params;
     const SurfaceParams params;
-
-private:
     GPUVAddr gpu_addr{};
     GPUVAddr gpu_addr{};
-    VAddr cpu_addr{};
-    u8* host_ptr{};
-    CacheAddr cache_addr{};
-    bool is_registered{};
+    GPUVAddr gpu_addr_end{};
+    std::vector<u32> mipmap_sizes;
+    std::vector<u32> mipmap_offsets;
+    const std::size_t layer_size;
+    const std::size_t memory_size;
+    const std::size_t host_memory_size;
+    u8* host_ptr;
+    VAddr cpu_addr;
 
 
-    std::vector<u8> staging_buffer;
+private:
+    void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
+                     u32 level);
 };
 };
 
 
-template <typename TTextureCache, typename TView>
+template <typename TView>
 class SurfaceBase : public SurfaceBaseImpl {
 class SurfaceBase : public SurfaceBaseImpl {
 public:
 public:
-    virtual void UploadTexture() = 0;
+    virtual void UploadTexture(std::vector<u8>& staging_buffer) = 0;
 
 
-    virtual void DownloadTexture() = 0;
+    virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
 
 
-    TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
-        if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) {
-            // It can't be a view if it's in a prior address.
-            return {};
-        }
+    void MarkAsModified(const bool is_modified_, const u64 tick) {
+        is_modified = is_modified_ || is_protected;
+        modification_tick = tick;
+    }
 
 
-        const auto relative_offset{static_cast<u64>(view_addr - GetGpuAddr())};
-        const auto it{view_offset_map.find(relative_offset)};
-        if (it == view_offset_map.end()) {
-            // Couldn't find an aligned view.
-            return {};
-        }
-        const auto [layer, level] = it->second;
+    void MarkAsProtected(const bool is_protected) {
+        this->is_protected = is_protected;
+    }
 
 
-        if (!params.IsViewValid(view_params, layer, level)) {
-            return {};
-        }
+    void MarkAsPicked(const bool is_picked) {
+        this->is_picked = is_picked;
+    }
 
 
-        return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
+    bool IsModified() const {
+        return is_modified;
     }
     }
 
 
-    void MarkAsModified(bool is_modified_) {
-        is_modified = is_modified_;
-        if (is_modified_) {
-            modification_tick = texture_cache.Tick();
-        }
+    bool IsProtected() const {
+        return is_protected;
     }
     }
 
 
-    TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
-        TView* view{TryGetView(view_addr, view_params)};
-        ASSERT(view != nullptr);
-        return view;
+    bool IsRegistered() const {
+        return is_registered;
     }
     }
 
 
-    bool IsModified() const {
-        return is_modified;
+    bool IsPicked() const {
+        return is_picked;
+    }
+
+    void MarkAsRegistered(bool is_reg) {
+        is_registered = is_reg;
     }
     }
 
 
     u64 GetModificationTick() const {
     u64 GetModificationTick() const {
         return modification_tick;
         return modification_tick;
     }
     }
 
 
+    TView EmplaceOverview(const SurfaceParams& overview_params) {
+        ViewParams vp{};
+        vp.base_level = 0;
+        vp.num_levels = params.num_levels;
+        vp.target = overview_params.target;
+        if (params.is_layered && !overview_params.is_layered) {
+            vp.base_layer = 0;
+            vp.num_layers = 1;
+        } else {
+            vp.base_layer = 0;
+            vp.num_layers = params.depth;
+        }
+        return GetView(vp);
+    }
+
+    std::optional<TView> EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) {
+        if (view_addr < gpu_addr)
+            return {};
+        if (params.target == SurfaceTarget::Texture3D || view_params.target == SurfaceTarget::Texture3D) {
+            return {};
+        }
+        const std::size_t size = view_params.GetGuestSizeInBytes();
+        const GPUVAddr relative_address = view_addr - gpu_addr;
+        auto layer_mipmap = GetLayerMipmap(relative_address);
+        if (!layer_mipmap) {
+            return {};
+        }
+        const u32 layer = (*layer_mipmap).first;
+        const u32 mipmap = (*layer_mipmap).second;
+        if (GetMipmapSize(mipmap) != size) {
+            // TODO: the view may cover many mimaps, this case can still go on
+            return {};
+        }
+        ViewParams vp{};
+        vp.base_layer = layer;
+        vp.num_layers = 1;
+        vp.base_level = mipmap;
+        vp.num_levels = 1;
+        vp.target = params.target;
+        return {GetView(vp)};
+    }
+
+    TView GetMainView() const {
+        return main_view;
+    }
+
 protected:
 protected:
-    explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params)
-        : SurfaceBaseImpl{params}, texture_cache{texture_cache},
-          view_offset_map{params.CreateViewOffsetMap()} {}
+    explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params)
+        : SurfaceBaseImpl(gpu_addr, params) {}
 
 
     ~SurfaceBase() = default;
     ~SurfaceBase() = default;
 
 
-    virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0;
+    virtual TView CreateView(const ViewParams& view_key) = 0;
+
+    std::unordered_map<ViewParams, TView> views;
+    TView main_view;
 
 
 private:
 private:
-    TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) {
-        const ViewKey key{base_layer, num_layers, base_level, num_levels};
+    TView GetView(const ViewParams& key) {
         const auto [entry, is_cache_miss] = views.try_emplace(key);
         const auto [entry, is_cache_miss] = views.try_emplace(key);
         auto& view{entry->second};
         auto& view{entry->second};
         if (is_cache_miss) {
         if (is_cache_miss) {
             view = CreateView(key);
             view = CreateView(key);
         }
         }
-        return view.get();
+        return view;
     }
     }
 
 
-    TTextureCache& texture_cache;
-    const std::map<u64, std::pair<u32, u32>> view_offset_map;
-
-    std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
-
     bool is_modified{};
     bool is_modified{};
+    bool is_protected{};
+    bool is_registered{};
+    bool is_picked{};
     u64 modification_tick{};
     u64 modification_tick{};
 };
 };
 
 

+ 75 - 135
src/video_core/texture_cache/surface_params.cpp

@@ -7,6 +7,7 @@
 #include "common/cityhash.h"
 #include "common/cityhash.h"
 #include "common/alignment.h"
 #include "common/alignment.h"
 #include "core/core.h"
 #include "core/core.h"
+#include "video_core/engines/shader_bytecode.h"
 #include "video_core/surface.h"
 #include "video_core/surface.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/texture_cache/surface_params.h"
 #include "video_core/textures/decoders.h"
 #include "video_core/textures/decoders.h"
@@ -22,6 +23,37 @@ using VideoCore::Surface::PixelFormatFromTextureFormat;
 using VideoCore::Surface::SurfaceTarget;
 using VideoCore::Surface::SurfaceTarget;
 using VideoCore::Surface::SurfaceTargetFromTextureType;
 using VideoCore::Surface::SurfaceTargetFromTextureType;
 
 
+SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
+    switch (type) {
+    case Tegra::Shader::TextureType::Texture1D: {
+        if (is_array)
+            return SurfaceTarget::Texture1DArray;
+        else
+            return SurfaceTarget::Texture1D;
+    }
+    case Tegra::Shader::TextureType::Texture2D: {
+        if (is_array)
+            return SurfaceTarget::Texture2DArray;
+        else
+            return SurfaceTarget::Texture2D;
+    }
+    case Tegra::Shader::TextureType::Texture3D: {
+        ASSERT(!is_array);
+        return SurfaceTarget::Texture3D;
+    }
+    case Tegra::Shader::TextureType::TextureCube: {
+        if (is_array)
+            return SurfaceTarget::TextureCubeArray;
+        else
+            return SurfaceTarget::TextureCubemap;
+    }
+    default: {
+        UNREACHABLE();
+        return SurfaceTarget::Texture2D;
+    }
+    }
+}
+
 namespace {
 namespace {
 constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
 constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
     return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
     return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
@@ -29,7 +61,8 @@ constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
 } // Anonymous namespace
 } // Anonymous namespace
 
 
 SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
 SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
-                                              const Tegra::Texture::FullTextureInfo& config) {
+                                              const Tegra::Texture::FullTextureInfo& config,
+                                              const VideoCommon::Shader::Sampler& entry) {
     SurfaceParams params;
     SurfaceParams params;
     params.is_tiled = config.tic.IsTiled();
     params.is_tiled = config.tic.IsTiled();
     params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
     params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
@@ -41,7 +74,8 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
                                                        params.srgb_conversion);
                                                        params.srgb_conversion);
     params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
     params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
     params.type = GetFormatType(params.pixel_format);
     params.type = GetFormatType(params.pixel_format);
-    params.target = SurfaceTargetFromTextureType(config.tic.texture_type);
+    // TODO: on 1DBuffer we should use the tic info.
+    params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray());
     params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
     params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
     params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
     params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
     params.depth = config.tic.Depth();
     params.depth = config.tic.Depth();
@@ -52,8 +86,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
     params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
     params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
     params.unaligned_height = config.tic.Height();
     params.unaligned_height = config.tic.Height();
     params.num_levels = config.tic.max_mip_level + 1;
     params.num_levels = config.tic.max_mip_level + 1;
-
-    params.CalculateCachedValues();
+    params.is_layered = params.IsLayered();
     return params;
     return params;
 }
 }
 
 
@@ -77,8 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(
     params.target = SurfaceTarget::Texture2D;
     params.target = SurfaceTarget::Texture2D;
     params.depth = 1;
     params.depth = 1;
     params.num_levels = 1;
     params.num_levels = 1;
-
-    params.CalculateCachedValues();
+    params.is_layered = false;
     return params;
     return params;
 }
 }
 
 
@@ -108,8 +140,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
     params.unaligned_height = config.height;
     params.unaligned_height = config.height;
     params.target = SurfaceTarget::Texture2D;
     params.target = SurfaceTarget::Texture2D;
     params.num_levels = 1;
     params.num_levels = 1;
-
-    params.CalculateCachedValues();
+    params.is_layered = false;
     return params;
     return params;
 }
 }
 
 
@@ -128,13 +159,13 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
     params.type = GetFormatType(params.pixel_format);
     params.type = GetFormatType(params.pixel_format);
     params.width = config.width;
     params.width = config.width;
     params.height = config.height;
     params.height = config.height;
+    params.pitch = config.pitch;
     params.unaligned_height = config.height;
     params.unaligned_height = config.height;
     // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
     // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
     params.target = SurfaceTarget::Texture2D;
     params.target = SurfaceTarget::Texture2D;
     params.depth = 1;
     params.depth = 1;
     params.num_levels = 1;
     params.num_levels = 1;
-
-    params.CalculateCachedValues();
+    params.is_layered = params.IsLayered();
     return params;
     return params;
 }
 }
 
 
@@ -147,7 +178,7 @@ u32 SurfaceParams::GetMipHeight(u32 level) const {
 }
 }
 
 
 u32 SurfaceParams::GetMipDepth(u32 level) const {
 u32 SurfaceParams::GetMipDepth(u32 level) const {
-    return IsLayered() ? depth : std::max(1U, depth >> level);
+    return is_layered ? depth : std::max(1U, depth >> level);
 }
 }
 
 
 bool SurfaceParams::IsLayered() const {
 bool SurfaceParams::IsLayered() const {
@@ -183,7 +214,7 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
     if (level == 0) {
     if (level == 0) {
         return this->block_depth;
         return this->block_depth;
     }
     }
-    if (IsLayered()) {
+    if (is_layered) {
         return 1;
         return 1;
     }
     }
 
 
@@ -216,6 +247,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
     return offset;
     return offset;
 }
 }
 
 
+std::size_t SurfaceParams::GetGuestMipmapSize(u32 level) const {
+    return GetInnerMipmapMemorySize(level, false, false);
+}
+
 std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
 std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
     return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers();
     return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers();
 }
 }
@@ -229,7 +264,7 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co
     for (u32 level = 0; level < num_levels; ++level) {
     for (u32 level = 0; level < num_levels; ++level) {
         size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed);
         size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed);
     }
     }
-    if (is_tiled && (IsLayered() || target == SurfaceTarget::Texture3D)) {
+    if (is_tiled && is_layered) {
         return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
         return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
     }
     }
     return size;
     return size;
@@ -256,150 +291,32 @@ u32 SurfaceParams::GetBytesPerPixel() const {
     return VideoCore::Surface::GetBytesPerPixel(pixel_format);
     return VideoCore::Surface::GetBytesPerPixel(pixel_format);
 }
 }
 
 
-bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const {
-    if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) !=
-        std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format,
-                 view_params.component_type, view_params.type)) {
-        return false;
-    }
-
-    const SurfaceTarget view_target{view_params.target};
-    if (view_target == target) {
-        return true;
-    }
-
-    switch (target) {
-    case SurfaceTarget::Texture1D:
-    case SurfaceTarget::Texture2D:
-    case SurfaceTarget::Texture3D:
-        return false;
-    case SurfaceTarget::Texture1DArray:
-        return view_target == SurfaceTarget::Texture1D;
-    case SurfaceTarget::Texture2DArray:
-        return view_target == SurfaceTarget::Texture2D;
-    case SurfaceTarget::TextureCubemap:
-        return view_target == SurfaceTarget::Texture2D ||
-               view_target == SurfaceTarget::Texture2DArray;
-    case SurfaceTarget::TextureCubeArray:
-        return view_target == SurfaceTarget::Texture2D ||
-               view_target == SurfaceTarget::Texture2DArray ||
-               view_target == SurfaceTarget::TextureCubemap;
-    default:
-        UNIMPLEMENTED_MSG("Unimplemented texture family={}", static_cast<u32>(target));
-        return false;
-    }
-}
-
 bool SurfaceParams::IsPixelFormatZeta() const {
 bool SurfaceParams::IsPixelFormatZeta() const {
     return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat &&
     return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat &&
            pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat;
            pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat;
 }
 }
 
 
-void SurfaceParams::CalculateCachedValues() {
-    switch (target) {
-    case SurfaceTarget::Texture1D:
-    case SurfaceTarget::Texture2D:
-    case SurfaceTarget::Texture3D:
-        num_layers = 1;
-        break;
-    case SurfaceTarget::Texture1DArray:
-    case SurfaceTarget::Texture2DArray:
-    case SurfaceTarget::TextureCubemap:
-    case SurfaceTarget::TextureCubeArray:
-        num_layers = depth;
-        break;
-    default:
-        UNREACHABLE();
-    }
-
-    guest_size_in_bytes = GetInnerMemorySize(false, false, false);
-
-    if (IsPixelFormatASTC(pixel_format)) {
-        // ASTC is uncompressed in software, in emulated as RGBA8
-        host_size_in_bytes = static_cast<std::size_t>(width) * static_cast<std::size_t>(height) *
-                             static_cast<std::size_t>(depth) * 4ULL;
-    } else {
-        host_size_in_bytes = GetInnerMemorySize(true, false, false);
-    }
-}
-
 std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size,
 std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size,
                                                     bool uncompressed) const {
                                                     bool uncompressed) const {
     const bool tiled{as_host_size ? false : is_tiled};
     const bool tiled{as_host_size ? false : is_tiled};
     const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
     const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
     const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
     const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())};
-    const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U};
+    const u32 depth{is_layered ? 1U : GetMipDepth(level)};
     return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
     return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
                                          GetMipBlockHeight(level), GetMipBlockDepth(level));
                                          GetMipBlockHeight(level), GetMipBlockDepth(level));
 }
 }
 
 
 std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
 std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
                                               bool uncompressed) const {
                                               bool uncompressed) const {
-    return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers);
-}
-
-std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const {
-    std::map<u64, std::pair<u32, u32>> view_offset_map;
-    switch (target) {
-    case SurfaceTarget::Texture1D:
-    case SurfaceTarget::Texture2D:
-    case SurfaceTarget::Texture3D: {
-        // TODO(Rodrigo): Add layer iterations for 3D textures
-        constexpr u32 layer = 0;
-        for (u32 level = 0; level < num_levels; ++level) {
-            const std::size_t offset{GetGuestMipmapLevelOffset(level)};
-            view_offset_map.insert({offset, {layer, level}});
-        }
-        break;
-    }
-    case SurfaceTarget::Texture1DArray:
-    case SurfaceTarget::Texture2DArray:
-    case SurfaceTarget::TextureCubemap:
-    case SurfaceTarget::TextureCubeArray: {
-        const std::size_t layer_size{GetGuestLayerSize()};
-        for (u32 level = 0; level < num_levels; ++level) {
-            const std::size_t level_offset{GetGuestMipmapLevelOffset(level)};
-            for (u32 layer = 0; layer < num_layers; ++layer) {
-                const auto layer_offset{static_cast<std::size_t>(layer_size * layer)};
-                const std::size_t offset{level_offset + layer_offset};
-                view_offset_map.insert({offset, {layer, level}});
-            }
-        }
-        break;
-    }
-    default:
-        UNIMPLEMENTED_MSG("Unimplemented surface target {}", static_cast<u32>(target));
-    }
-    return view_offset_map;
-}
-
-bool SurfaceParams::IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const {
-    return IsDimensionValid(view_params, level) && IsDepthValid(view_params, level) &&
-           IsInBounds(view_params, layer, level);
+    return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth);
 }
 }
 
 
-bool SurfaceParams::IsDimensionValid(const SurfaceParams& view_params, u32 level) const {
-    return view_params.width == GetMipWidth(level) && view_params.height == GetMipHeight(level);
-}
-
-bool SurfaceParams::IsDepthValid(const SurfaceParams& view_params, u32 level) const {
-    if (view_params.target != SurfaceTarget::Texture3D) {
-        return true;
-    }
-    return view_params.depth == GetMipDepth(level);
-}
-
-bool SurfaceParams::IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const {
-    return layer + view_params.num_layers <= num_layers &&
-           level + view_params.num_levels <= num_levels;
-}
-
-std::size_t HasheableSurfaceParams::Hash() const {
+std::size_t SurfaceParams::Hash() const {
     return static_cast<std::size_t>(
     return static_cast<std::size_t>(
         Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
         Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this)));
 }
 }
 
 
-bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const {
+bool SurfaceParams::operator==(const SurfaceParams& rhs) const {
     return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width,
     return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width,
                     height, depth, pitch, unaligned_height, num_levels, pixel_format,
                     height, depth, pitch, unaligned_height, num_levels, pixel_format,
                     component_type, type, target) ==
                     component_type, type, target) ==
@@ -409,4 +326,27 @@ bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const
                     rhs.type, rhs.target);
                     rhs.type, rhs.target);
 }
 }
 
 
+std::string SurfaceParams::TargetName() const {
+    switch (target) {
+    case SurfaceTarget::Texture1D:
+        return "1D";
+    case SurfaceTarget::Texture2D:
+        return "2D";
+    case SurfaceTarget::Texture3D:
+        return "3D";
+    case SurfaceTarget::Texture1DArray:
+        return "1DArray";
+    case SurfaceTarget::Texture2DArray:
+        return "2DArray";
+    case SurfaceTarget::TextureCubemap:
+        return "Cube";
+    case SurfaceTarget::TextureCubeArray:
+        return "CubeArray";
+    default:
+        LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
+        UNREACHABLE();
+        return fmt::format("TUK({})", static_cast<u32>(target));
+    }
+}
+
 } // namespace VideoCommon
 } // namespace VideoCommon

+ 47 - 112
src/video_core/texture_cache/surface_params.h

@@ -6,50 +6,21 @@
 
 
 #include <map>
 #include <map>
 
 
+#include "common/alignment.h"
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "video_core/engines/fermi_2d.h"
 #include "video_core/engines/fermi_2d.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/engines/maxwell_3d.h"
 #include "video_core/surface.h"
 #include "video_core/surface.h"
+#include "video_core/shader/shader_ir.h"
 
 
 namespace VideoCommon {
 namespace VideoCommon {
 
 
-class HasheableSurfaceParams {
-public:
-    std::size_t Hash() const;
-
-    bool operator==(const HasheableSurfaceParams& rhs) const;
-
-    bool operator!=(const HasheableSurfaceParams& rhs) const {
-        return !operator==(rhs);
-    }
-
-protected:
-    // Avoid creation outside of a managed environment.
-    HasheableSurfaceParams() = default;
-
-    bool is_tiled;
-    bool srgb_conversion;
-    u32 block_width;
-    u32 block_height;
-    u32 block_depth;
-    u32 tile_width_spacing;
-    u32 width;
-    u32 height;
-    u32 depth;
-    u32 pitch;
-    u32 unaligned_height;
-    u32 num_levels;
-    VideoCore::Surface::PixelFormat pixel_format;
-    VideoCore::Surface::ComponentType component_type;
-    VideoCore::Surface::SurfaceType type;
-    VideoCore::Surface::SurfaceTarget target;
-};
-
-class SurfaceParams final : public HasheableSurfaceParams {
+class SurfaceParams {
 public:
 public:
     /// Creates SurfaceCachedParams from a texture configuration.
     /// Creates SurfaceCachedParams from a texture configuration.
     static SurfaceParams CreateForTexture(Core::System& system,
     static SurfaceParams CreateForTexture(Core::System& system,
-                                          const Tegra::Texture::FullTextureInfo& config);
+                                          const Tegra::Texture::FullTextureInfo& config,
+                                          const VideoCommon::Shader::Sampler& entry);
 
 
     /// Creates SurfaceCachedParams for a depth buffer configuration.
     /// Creates SurfaceCachedParams for a depth buffer configuration.
     static SurfaceParams CreateForDepthBuffer(
     static SurfaceParams CreateForDepthBuffer(
@@ -64,68 +35,33 @@ public:
     static SurfaceParams CreateForFermiCopySurface(
     static SurfaceParams CreateForFermiCopySurface(
         const Tegra::Engines::Fermi2D::Regs::Surface& config);
         const Tegra::Engines::Fermi2D::Regs::Surface& config);
 
 
-    bool IsTiled() const {
-        return is_tiled;
-    }
-
-    bool GetSrgbConversion() const {
-        return srgb_conversion;
-    }
-
-    u32 GetBlockWidth() const {
-        return block_width;
-    }
-
-    u32 GetTileWidthSpacing() const {
-        return tile_width_spacing;
-    }
-
-    u32 GetWidth() const {
-        return width;
-    }
-
-    u32 GetHeight() const {
-        return height;
-    }
-
-    u32 GetDepth() const {
-        return depth;
-    }
-
-    u32 GetPitch() const {
-        return pitch;
-    }
-
-    u32 GetNumLevels() const {
-        return num_levels;
-    }
-
-    VideoCore::Surface::PixelFormat GetPixelFormat() const {
-        return pixel_format;
-    }
-
-    VideoCore::Surface::ComponentType GetComponentType() const {
-        return component_type;
-    }
+    std::size_t Hash() const;
 
 
-    VideoCore::Surface::SurfaceTarget GetTarget() const {
-        return target;
-    }
+    bool operator==(const SurfaceParams& rhs) const;
 
 
-    VideoCore::Surface::SurfaceType GetType() const {
-        return type;
+    bool operator!=(const SurfaceParams& rhs) const {
+        return !operator==(rhs);
     }
     }
 
 
     std::size_t GetGuestSizeInBytes() const {
     std::size_t GetGuestSizeInBytes() const {
-        return guest_size_in_bytes;
+        return GetInnerMemorySize(false, false, false);
     }
     }
 
 
     std::size_t GetHostSizeInBytes() const {
     std::size_t GetHostSizeInBytes() const {
+        std::size_t host_size_in_bytes;
+        if (IsPixelFormatASTC(pixel_format)) {
+            // ASTC is uncompressed in software, in emulated as RGBA8
+            host_size_in_bytes = static_cast<std::size_t>(Common::AlignUp(width, GetDefaultBlockWidth())) *
+                                 static_cast<std::size_t>(Common::AlignUp(height, GetDefaultBlockHeight())) *
+                                 static_cast<std::size_t>(depth) * 4ULL;
+        } else {
+            host_size_in_bytes = GetInnerMemorySize(true, false, false);
+        }
         return host_size_in_bytes;
         return host_size_in_bytes;
     }
     }
 
 
-    u32 GetNumLayers() const {
-        return num_layers;
+    u32 GetBlockAlignedWidth() const {
+        return Common::AlignUp(width, 64 / GetBytesPerPixel());
     }
     }
 
 
     /// Returns the width of a given mipmap level.
     /// Returns the width of a given mipmap level.
@@ -137,9 +73,6 @@ public:
     /// Returns the depth of a given mipmap level.
     /// Returns the depth of a given mipmap level.
     u32 GetMipDepth(u32 level) const;
     u32 GetMipDepth(u32 level) const;
 
 
-    /// Returns true if these parameters are from a layered surface.
-    bool IsLayered() const;
-
     /// Returns the block height of a given mipmap level.
     /// Returns the block height of a given mipmap level.
     u32 GetMipBlockHeight(u32 level) const;
     u32 GetMipBlockHeight(u32 level) const;
 
 
@@ -152,6 +85,9 @@ public:
     /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
     /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
     std::size_t GetHostMipmapLevelOffset(u32 level) const;
     std::size_t GetHostMipmapLevelOffset(u32 level) const;
 
 
+    /// Returns the size in bytes in guest memory of a given mipmap level.
+    std::size_t GetGuestMipmapSize(u32 level) const;
+
     /// Returns the size in bytes in host memory (linear) of a given mipmap level.
     /// Returns the size in bytes in host memory (linear) of a given mipmap level.
     std::size_t GetHostMipmapSize(u32 level) const;
     std::size_t GetHostMipmapSize(u32 level) const;
 
 
@@ -173,24 +109,30 @@ public:
     /// Returns the bytes per pixel.
     /// Returns the bytes per pixel.
     u32 GetBytesPerPixel() const;
     u32 GetBytesPerPixel() const;
 
 
-    /// Returns true if another surface can be familiar with this. This is a loosely defined term
-    /// that reflects the possibility of these two surface parameters potentially being part of a
-    /// bigger superset.
-    bool IsFamiliar(const SurfaceParams& view_params) const;
-
     /// Returns true if the pixel format is a depth and/or stencil format.
     /// Returns true if the pixel format is a depth and/or stencil format.
     bool IsPixelFormatZeta() const;
     bool IsPixelFormatZeta() const;
 
 
-    /// Creates a map that redirects an address difference to a layer and mipmap level.
-    std::map<u64, std::pair<u32, u32>> CreateViewOffsetMap() const;
+    std::string TargetName() const;
 
 
-    /// Returns true if the passed surface view parameters is equal or a valid subset of this.
-    bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const;
+    bool is_tiled;
+    bool srgb_conversion;
+    bool is_layered;
+    u32 block_width;
+    u32 block_height;
+    u32 block_depth;
+    u32 tile_width_spacing;
+    u32 width;
+    u32 height;
+    u32 depth;
+    u32 pitch;
+    u32 unaligned_height;
+    u32 num_levels;
+    VideoCore::Surface::PixelFormat pixel_format;
+    VideoCore::Surface::ComponentType component_type;
+    VideoCore::Surface::SurfaceType type;
+    VideoCore::Surface::SurfaceTarget target;
 
 
 private:
 private:
-    /// Calculates values that can be deduced from HasheableSurfaceParams.
-    void CalculateCachedValues();
-
     /// Returns the size of a given mipmap level inside a layer.
     /// Returns the size of a given mipmap level inside a layer.
     std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
     std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
 
 
@@ -200,19 +142,12 @@ private:
     /// Returns the size of a layer
     /// Returns the size of a layer
     std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
     std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const;
 
 
-    /// Returns true if the passed view width and height match the size of this params in a given
-    /// mipmap level.
-    bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const;
-
-    /// Returns true if the passed view depth match the size of this params in a given mipmap level.
-    bool IsDepthValid(const SurfaceParams& view_params, u32 level) const;
-
-    /// Returns true if the passed view layers and mipmap levels are in bounds.
-    bool IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const;
+    std::size_t GetNumLayers() const {
+        return is_layered ? depth : 1;
+    }
 
 
-    std::size_t guest_size_in_bytes;
-    std::size_t host_size_in_bytes;
-    u32 num_layers;
+    /// Returns true if these parameters are from a layered surface.
+    bool IsLayered() const;
 };
 };
 
 
 } // namespace VideoCommon
 } // namespace VideoCommon

+ 6 - 6
src/video_core/texture_cache/surface_view.cpp

@@ -9,15 +9,15 @@
 
 
 namespace VideoCommon {
 namespace VideoCommon {
 
 
-std::size_t ViewKey::Hash() const {
+std::size_t ViewParams::Hash() const {
     return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^
     return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^
-           (static_cast<std::size_t>(base_level) << 32) ^
-           (static_cast<std::size_t>(num_levels) << 48);
+           (static_cast<std::size_t>(base_level) << 24) ^
+           (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36);
 }
 }
 
 
-bool ViewKey::operator==(const ViewKey& rhs) const {
-    return std::tie(base_layer, num_layers, base_level, num_levels) ==
-           std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels);
+bool ViewParams::operator==(const ViewParams& rhs) const {
+    return std::tie(base_layer, num_layers, base_level, num_levels, target) ==
+           std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels, rhs.target);
 }
 }
 
 
 } // namespace VideoCommon
 } // namespace VideoCommon

+ 31 - 4
src/video_core/texture_cache/surface_view.h

@@ -7,18 +7,45 @@
 #include <functional>
 #include <functional>
 
 
 #include "common/common_types.h"
 #include "common/common_types.h"
+#include "video_core/surface.h"
+#include "video_core/texture_cache/surface_params.h"
 
 
 namespace VideoCommon {
 namespace VideoCommon {
 
 
-struct ViewKey {
+struct ViewParams {
     std::size_t Hash() const;
     std::size_t Hash() const;
 
 
-    bool operator==(const ViewKey& rhs) const;
+    bool operator==(const ViewParams& rhs) const;
 
 
     u32 base_layer{};
     u32 base_layer{};
     u32 num_layers{};
     u32 num_layers{};
     u32 base_level{};
     u32 base_level{};
     u32 num_levels{};
     u32 num_levels{};
+    VideoCore::Surface::SurfaceTarget target;
+    bool IsLayered() const {
+        switch (target) {
+        case VideoCore::Surface::SurfaceTarget::Texture1DArray:
+        case VideoCore::Surface::SurfaceTarget::Texture2DArray:
+        case VideoCore::Surface::SurfaceTarget::TextureCubemap:
+        case VideoCore::Surface::SurfaceTarget::TextureCubeArray:
+            return true;
+        default:
+            return false;
+        }
+    }
+};
+
+class ViewBase {
+public:
+    ViewBase(const ViewParams& params) : params{params} {}
+    ~ViewBase() = default;
+
+    const ViewParams& GetViewParams() const {
+        return params;
+    }
+
+protected:
+    ViewParams params;
 };
 };
 
 
 } // namespace VideoCommon
 } // namespace VideoCommon
@@ -26,8 +53,8 @@ struct ViewKey {
 namespace std {
 namespace std {
 
 
 template <>
 template <>
-struct hash<VideoCommon::ViewKey> {
-    std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept {
+struct hash<VideoCommon::ViewParams> {
+    std::size_t operator()(const VideoCommon::ViewParams& k) const noexcept {
         return k.Hash();
         return k.Hash();
     }
     }
 };
 };