summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/texture_cache/texture_cache.h71
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);