From b711cdce782ee604edc3c52628eb76e6b9a08b72 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 7 May 2019 13:58:37 -0400 Subject: [PATCH] Corrections to Structural Matching The texture will now be reconstructed if the width only matches on GoB alignment. --- src/video_core/texture_cache/surface_base.h | 66 +++++++++++++------- src/video_core/texture_cache/texture_cache.h | 11 +++- 2 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 5fd7add0a..9c048eb88 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -16,9 +16,8 @@ #include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_view.h" -template> -ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={}) -{ +template > +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) @@ -33,8 +32,14 @@ class MemoryManager; namespace VideoCommon { -using VideoCore::Surface::SurfaceTarget; using VideoCore::MortonSwizzleMode; +using VideoCore::Surface::SurfaceTarget; + +enum class MatchStructureResult : u32 { + FullMatch = 0, + SemiMatch = 1, + None = 2, +}; class SurfaceBaseImpl { public: @@ -106,17 +111,26 @@ public: return std::tie(src_bpp, params.is_tiled) == std::tie(dst_bpp, rhs.is_tiled); } - bool MatchesStructure(const SurfaceParams& rhs) const { + MatchStructureResult 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); + if (std::tie(params.height, params.depth, params.block_width, params.block_height, + params.block_depth, params.tile_width_spacing) == + std::tie(rhs.height, rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth, + rhs.tile_width_spacing)) { + if (params.width == rhs.width) { + return MatchStructureResult::FullMatch; + } + if (params.GetBlockAlignedWidth() == rhs.GetBlockAlignedWidth()) { + return MatchStructureResult::SemiMatch; + } + } + return MatchStructureResult::None; } else { - return std::tie(params.width, params.height, params.pitch) == - std::tie(rhs.width, rhs.height, rhs.pitch); + if (std::tie(params.width, params.height, params.pitch) == + std::tie(rhs.width, rhs.height, rhs.pitch)) { + return MatchStructureResult::FullMatch; + } + return MatchStructureResult::None; } } @@ -126,15 +140,16 @@ public: 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); + 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 {}; } - std::vector BreakDown() const { - auto set_up_copy = [](CopyParams& cp, const SurfaceParams& params, const u32 depth, + std::vector BreakDown(const SurfaceParams& in_params) const { + auto set_up_copy = [](CopyParams& cp, const u32 width, const u32 height, const u32 depth, const u32 level) { cp.source_x = 0; cp.source_y = 0; @@ -144,8 +159,8 @@ public: cp.dest_z = 0; cp.source_level = level; cp.dest_level = level; - cp.width = params.GetMipWidth(level); - cp.height = params.GetMipHeight(level); + cp.width = width; + cp.height = height; cp.depth = depth; }; const u32 layers = params.depth; @@ -156,7 +171,11 @@ public: 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); + const u32 width = + std::min(params.GetMipWidth(level), in_params.GetMipWidth(level)); + const u32 height = + std::min(params.GetMipHeight(level), in_params.GetMipHeight(level)); + set_up_copy(cp, width, height, layer, level); } } return result; @@ -164,7 +183,11 @@ public: std::vector result{mipmaps}; for (std::size_t level = 0; level < mipmaps; level++) { CopyParams& cp = result[level]; - set_up_copy(cp, params, params.GetMipDepth(level), level); + const u32 width = std::min(params.GetMipWidth(level), in_params.GetMipWidth(level)); + const u32 height = + std::min(params.GetMipHeight(level), in_params.GetMipHeight(level)); + const u32 depth = std::min(params.GetMipDepth(level), in_params.GetMipDepth(level)); + set_up_copy(cp, width, height, depth, level); } return result; } @@ -254,7 +277,8 @@ public: std::optional 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) { + if (params.target == SurfaceTarget::Texture3D || + view_params.target == SurfaceTarget::Texture3D) { return {}; } const std::size_t size = view_params.GetGuestSizeInBytes(); diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index eb0d9bc10..f3b28453a 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -284,7 +284,7 @@ private: const SurfaceParams& params) { const auto gpu_addr = current_surface->GetGpuAddr(); TSurface new_surface = GetUncachedSurface(gpu_addr, params); - std::vector bricks = current_surface->BreakDown(); + std::vector bricks = current_surface->BreakDown(params); for (auto& brick : bricks) { ImageCopy(current_surface, new_surface, brick); } @@ -370,11 +370,16 @@ private: if (overlaps.size() == 1) { TSurface current_surface = overlaps[0]; - if (current_surface->MatchesStructure(params) && + MatchStructureResult s_result = current_surface->MatchesStructure(params); + if (s_result != MatchStructureResult::None && current_surface->GetGpuAddr() == gpu_addr && (params.target != SurfaceTarget::Texture3D || current_surface->MatchTarget(params.target))) { - return ManageStructuralMatch(current_surface, params); + if (s_result == MatchStructureResult::FullMatch) { + return ManageStructuralMatch(current_surface, params); + } else { + return RebuildMirage(current_surface, params); + } } if (current_surface->GetSizeInBytes() <= candidate_size) { return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents,