diff options
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 71 |
1 files changed, 43 insertions, 28 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 45e3ddd2c..6f63217a2 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -655,45 +655,63 @@ private: | |||
| 655 | **/ | 655 | **/ |
| 656 | std::optional<std::pair<TSurface, TView>> TryReconstructSurface(VectorSurface& overlaps, | 656 | std::optional<std::pair<TSurface, TView>> TryReconstructSurface(VectorSurface& overlaps, |
| 657 | const SurfaceParams& params, | 657 | const SurfaceParams& params, |
| 658 | const GPUVAddr gpu_addr) { | 658 | GPUVAddr gpu_addr) { |
| 659 | if (params.target == SurfaceTarget::Texture3D) { | 659 | if (params.target == SurfaceTarget::Texture3D) { |
| 660 | return {}; | 660 | return std::nullopt; |
| 661 | } | 661 | } |
| 662 | bool modified = false; | 662 | const auto test_modified = [](TSurface& surface) { return surface->IsModified(); }; |
| 663 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); | 663 | TSurface new_surface = GetUncachedSurface(gpu_addr, params); |
| 664 | u32 passed_tests = 0; | 664 | |
| 665 | if (std::none_of(overlaps.begin(), overlaps.end(), test_modified)) { | ||
| 666 | LoadSurface(new_surface); | ||
| 667 | for (const auto& surface : overlaps) { | ||
| 668 | Unregister(surface); | ||
| 669 | } | ||
| 670 | Register(new_surface); | ||
| 671 | return {{new_surface, new_surface->GetMainView()}}; | ||
| 672 | } | ||
| 673 | |||
| 674 | std::size_t passed_tests = 0; | ||
| 665 | for (auto& surface : overlaps) { | 675 | for (auto& surface : overlaps) { |
| 666 | const SurfaceParams& src_params = surface->GetSurfaceParams(); | 676 | const SurfaceParams& src_params = surface->GetSurfaceParams(); |
| 667 | if (src_params.is_layered || src_params.num_levels > 1) { | 677 | const auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())}; |
| 668 | // We send this cases to recycle as they are more complex to handle | ||
| 669 | return {}; | ||
| 670 | } | ||
| 671 | const std::size_t candidate_size = surface->GetSizeInBytes(); | ||
| 672 | auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())}; | ||
| 673 | if (!mipmap_layer) { | 678 | if (!mipmap_layer) { |
| 674 | continue; | 679 | continue; |
| 675 | } | 680 | } |
| 676 | const auto [layer, mipmap] = *mipmap_layer; | 681 | const auto [base_layer, base_mipmap] = *mipmap_layer; |
| 677 | if (new_surface->GetMipmapSize(mipmap) != candidate_size) { | 682 | if (new_surface->GetMipmapSize(base_mipmap) != surface->GetMipmapSize(0)) { |
| 678 | continue; | 683 | continue; |
| 679 | } | 684 | } |
| 680 | modified |= surface->IsModified(); | 685 | ++passed_tests; |
| 681 | // Now we got all the data set up | 686 | |
| 682 | const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap); | 687 | // Copy all mipmaps and layers |
| 683 | const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap); | 688 | const u32 block_width = params.GetDefaultBlockWidth(); |
| 684 | const CopyParams copy_params(0, 0, 0, 0, 0, layer, 0, mipmap, width, height, 1); | 689 | const u32 block_height = params.GetDefaultBlockHeight(); |
| 685 | passed_tests++; | 690 | for (u32 mipmap = base_mipmap; mipmap < base_mipmap + src_params.num_levels; ++mipmap) { |
| 686 | ImageCopy(surface, new_surface, copy_params); | 691 | const u32 width = SurfaceParams::IntersectWidth(src_params, params, 0, mipmap); |
| 692 | const u32 height = SurfaceParams::IntersectHeight(src_params, params, 0, mipmap); | ||
| 693 | if (width < block_width || height < block_height) { | ||
| 694 | // Current APIs forbid copying small compressed textures, avoid errors | ||
| 695 | break; | ||
| 696 | } | ||
| 697 | const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height, | ||
| 698 | src_params.depth); | ||
| 699 | ImageCopy(surface, new_surface, copy_params); | ||
| 700 | } | ||
| 687 | } | 701 | } |
| 688 | if (passed_tests == 0) { | 702 | if (passed_tests == 0) { |
| 689 | return {}; | 703 | return std::nullopt; |
| 704 | } | ||
| 705 | if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) { | ||
| 690 | // In Accurate GPU all tests should pass, else we recycle | 706 | // In Accurate GPU all tests should pass, else we recycle |
| 691 | } else if (Settings::IsGPULevelExtreme() && passed_tests != overlaps.size()) { | 707 | return std::nullopt; |
| 692 | return {}; | ||
| 693 | } | 708 | } |
| 709 | |||
| 710 | const bool modified = std::any_of(overlaps.begin(), overlaps.end(), test_modified); | ||
| 694 | for (const auto& surface : overlaps) { | 711 | for (const auto& surface : overlaps) { |
| 695 | Unregister(surface); | 712 | Unregister(surface); |
| 696 | } | 713 | } |
| 714 | |||
| 697 | new_surface->MarkAsModified(modified, Tick()); | 715 | new_surface->MarkAsModified(modified, Tick()); |
| 698 | Register(new_surface); | 716 | Register(new_surface); |
| 699 | return {{new_surface, new_surface->GetMainView()}}; | 717 | return {{new_surface, new_surface->GetMainView()}}; |
| @@ -871,12 +889,9 @@ private: | |||
| 871 | // two things either the candidate surface is a supertexture of the overlap | 889 | // two things either the candidate surface is a supertexture of the overlap |
| 872 | // or they don't match in any known way. | 890 | // or they don't match in any known way. |
| 873 | if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { | 891 | if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { |
| 874 | if (current_surface->GetGpuAddr() == gpu_addr) { | 892 | const std::optional view = TryReconstructSurface(overlaps, params, gpu_addr); |
| 875 | std::optional<std::pair<TSurface, TView>> view = | 893 | if (view) { |
| 876 | TryReconstructSurface(overlaps, params, gpu_addr); | 894 | return *view; |
| 877 | if (view) { | ||
| 878 | return *view; | ||
| 879 | } | ||
| 880 | } | 895 | } |
| 881 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, | 896 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 882 | MatchTopologyResult::FullMatch); | 897 | MatchTopologyResult::FullMatch); |