diff options
| author | 2020-05-29 01:48:01 -0300 | |
|---|---|---|
| committer | 2020-05-29 02:57:30 -0300 | |
| commit | 5b37cecd76205612bfc2cc1d0b475d893fe7ee6a (patch) | |
| tree | 0a940887849f485a854b3d88b89d16e0dabc7dac /src/video_core/texture_cache | |
| parent | Merge pull request #3991 from ReinUsesLisp/depth-sampling (diff) | |
| download | yuzu-5b37cecd76205612bfc2cc1d0b475d893fe7ee6a.tar.gz yuzu-5b37cecd76205612bfc2cc1d0b475d893fe7ee6a.tar.xz yuzu-5b37cecd76205612bfc2cc1d0b475d893fe7ee6a.zip | |
texture_cache: Handle overlaps with multiple subresources
Implement more surface reconstruct cases. Allow overlaps with more than
one layer and mipmap and copies all of them to the new texture.
- Fixes textures moving around objects on Xenoblade games
Diffstat (limited to 'src/video_core/texture_cache')
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 8bfc541d4..658264860 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -652,45 +652,54 @@ private: | |||
| 652 | **/ | 652 | **/ |
| 653 | std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps, | 653 | std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps, |
| 654 | const SurfaceParams& params, | 654 | const SurfaceParams& params, |
| 655 | const GPUVAddr gpu_addr) { | 655 | GPUVAddr gpu_addr) { |
| 656 | if (params.target == SurfaceTarget::Texture3D) { | 656 | if (params.target == SurfaceTarget::Texture3D) { |
| 657 | return {}; | 657 | return std::nullopt; |
| 658 | } | 658 | } |
| 659 | bool modified = false; | ||
| 660 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); | 659 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); |
| 661 | u32 passed_tests = 0; | 660 | std::size_t passed_tests = 0; |
| 661 | bool modified = false; | ||
| 662 | |||
| 662 | for (auto& surface : overlaps) { | 663 | for (auto& surface : overlaps) { |
| 663 | const SurfaceParams& src_params = surface->GetSurfaceParams(); | 664 | const SurfaceParams& src_params = surface->GetSurfaceParams(); |
| 664 | if (src_params.is_layered || src_params.num_levels > 1) { | 665 | const auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())}; |
| 665 | // We send this cases to recycle as they are more complex to handle | ||
| 666 | return {}; | ||
| 667 | } | ||
| 668 | const std::size_t candidate_size = surface->GetSizeInBytes(); | ||
| 669 | auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())}; | ||
| 670 | if (!mipmap_layer) { | 666 | if (!mipmap_layer) { |
| 671 | continue; | 667 | continue; |
| 672 | } | 668 | } |
| 673 | const auto [layer, mipmap] = *mipmap_layer; | 669 | const auto [base_layer, base_mipmap] = *mipmap_layer; |
| 674 | if (new_surface->GetMipmapSize(mipmap) != candidate_size) { | 670 | if (new_surface->GetMipmapSize(base_mipmap) != surface->GetMipmapSize(0)) { |
| 675 | continue; | 671 | continue; |
| 676 | } | 672 | } |
| 673 | |||
| 674 | // Copy all mipmaps and layers | ||
| 675 | const u32 block_width = params.GetDefaultBlockWidth(); | ||
| 676 | const u32 block_height = params.GetDefaultBlockHeight(); | ||
| 677 | for (u32 mipmap = base_mipmap; mipmap < base_mipmap + src_params.num_levels; ++mipmap) { | ||
| 678 | const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap); | ||
| 679 | const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap); | ||
| 680 | if (width < block_width || height < block_height) { | ||
| 681 | // Current APIs forbid copying small compressed textures, avoid errors | ||
| 682 | break; | ||
| 683 | } | ||
| 684 | const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height, | ||
| 685 | src_params.depth); | ||
| 686 | ImageCopy(surface, new_surface, copy_params); | ||
| 687 | } | ||
| 688 | ++passed_tests; | ||
| 677 | modified |= surface->IsModified(); | 689 | modified |= surface->IsModified(); |
| 678 | // Now we got all the data set up | ||
| 679 | const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap); | ||
| 680 | const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap); | ||
| 681 | const CopyParams copy_params(0, 0, 0, 0, 0, layer, 0, mipmap, width, height, 1); | ||
| 682 | passed_tests++; | ||
| 683 | ImageCopy(surface, new_surface, copy_params); | ||
| 684 | } | 690 | } |
| 685 | if (passed_tests == 0) { | 691 | if (passed_tests == 0) { |
| 686 | return {}; | 692 | return std::nullopt; |
| 693 | } | ||
| 694 | if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) { | ||
| 687 | // In Accurate GPU all tests should pass, else we recycle | 695 | // In Accurate GPU all tests should pass, else we recycle |
| 688 | } else if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) { | 696 | return std::nullopt; |
| 689 | return {}; | ||
| 690 | } | 697 | } |
| 698 | |||
| 691 | for (const auto& surface : overlaps) { | 699 | for (const auto& surface : overlaps) { |
| 692 | Unregister(surface); | 700 | Unregister(surface); |
| 693 | } | 701 | } |
| 702 | |||
| 694 | new_surface->MarkAsModified(modified, Tick()); | 703 | new_surface->MarkAsModified(modified, Tick()); |
| 695 | Register(new_surface); | 704 | Register(new_surface); |
| 696 | return {{new_surface, new_surface->GetMainView()}}; | 705 | return {{new_surface, new_surface->GetMainView()}}; |
| @@ -868,12 +877,9 @@ private: | |||
| 868 | // two things either the candidate surface is a supertexture of the overlap | 877 | // two things either the candidate surface is a supertexture of the overlap |
| 869 | // or they don't match in any known way. | 878 | // or they don't match in any known way. |
| 870 | if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { | 879 | if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { |
| 871 | if (current_surface->GetGpuAddr() == gpu_addr) { | 880 | const std::optional view = TryReconstructSurface(overlaps, params, gpu_addr); |
| 872 | std::optional<std::pair<TSurface, TView>> view = | 881 | if (view) { |
| 873 | TryReconstructSurface(overlaps, params, gpu_addr); | 882 | return *view; |
| 874 | if (view) { | ||
| 875 | return *view; | ||
| 876 | } | ||
| 877 | } | 883 | } |
| 878 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, | 884 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 879 | MatchTopologyResult::FullMatch); | 885 | MatchTopologyResult::FullMatch); |