diff options
| author | 2020-04-26 19:53:02 -0300 | |
|---|---|---|
| committer | 2020-04-26 19:53:02 -0300 | |
| commit | 8da16cf9fb6c2133faed1164a8573992e84a4297 (patch) | |
| tree | a0d14c5ec0955d35cbc22b1670eadcdbdbe5ba31 /src/video_core/texture_cache | |
| parent | Merge pull request #3795 from vitor-k/fix-folder (diff) | |
| download | yuzu-8da16cf9fb6c2133faed1164a8573992e84a4297.tar.gz yuzu-8da16cf9fb6c2133faed1164a8573992e84a4297.tar.xz yuzu-8da16cf9fb6c2133faed1164a8573992e84a4297.zip | |
texture_cache: Reintroduce preserve_contents accurately
This reverts commit 94b0e2e5dae4e0bd0021ac2d8fe1ff904a93ee69.
preserve_contents proved to be a meaningful optimization. This commit
reintroduces it but properly implemented on OpenGL.
We have to make sure the clear removes all the previous contents of the
image.
It's not currently implemented on Vulkan because we can do smart things
there that's preferred to be introduced in a separate commit.
Diffstat (limited to 'src/video_core/texture_cache')
| -rw-r--r-- | src/video_core/texture_cache/texture_cache.h | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index cf6bd005a..d2d2846e6 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -143,7 +143,7 @@ public: | |||
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)}; | 145 | const auto params{SurfaceParams::CreateForTexture(format_lookup_table, tic, entry)}; |
| 146 | const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false); | 146 | const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, true, false); |
| 147 | if (guard_samplers) { | 147 | if (guard_samplers) { |
| 148 | sampled_textures.push_back(surface); | 148 | sampled_textures.push_back(surface); |
| 149 | } | 149 | } |
| @@ -163,7 +163,7 @@ public: | |||
| 163 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); | 163 | return GetNullSurface(SurfaceParams::ExpectedTarget(entry)); |
| 164 | } | 164 | } |
| 165 | const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)}; | 165 | const auto params{SurfaceParams::CreateForImage(format_lookup_table, tic, entry)}; |
| 166 | const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, false); | 166 | const auto [surface, view] = GetSurface(gpu_addr, *cpu_addr, params, true, false); |
| 167 | if (guard_samplers) { | 167 | if (guard_samplers) { |
| 168 | sampled_textures.push_back(surface); | 168 | sampled_textures.push_back(surface); |
| 169 | } | 169 | } |
| @@ -178,7 +178,7 @@ public: | |||
| 178 | return any_rt; | 178 | return any_rt; |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | TView GetDepthBufferSurface() { | 181 | TView GetDepthBufferSurface(bool preserve_contents) { |
| 182 | std::lock_guard lock{mutex}; | 182 | std::lock_guard lock{mutex}; |
| 183 | auto& maxwell3d = system.GPU().Maxwell3D(); | 183 | auto& maxwell3d = system.GPU().Maxwell3D(); |
| 184 | if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) { | 184 | if (!maxwell3d.dirty.flags[VideoCommon::Dirty::ZetaBuffer]) { |
| @@ -199,7 +199,7 @@ public: | |||
| 199 | return {}; | 199 | return {}; |
| 200 | } | 200 | } |
| 201 | const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)}; | 201 | const auto depth_params{SurfaceParams::CreateForDepthBuffer(system)}; |
| 202 | auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, true); | 202 | auto surface_view = GetSurface(gpu_addr, *cpu_addr, depth_params, preserve_contents, true); |
| 203 | if (depth_buffer.target) | 203 | if (depth_buffer.target) |
| 204 | depth_buffer.target->MarkAsRenderTarget(false, NO_RT); | 204 | depth_buffer.target->MarkAsRenderTarget(false, NO_RT); |
| 205 | depth_buffer.target = surface_view.first; | 205 | depth_buffer.target = surface_view.first; |
| @@ -209,7 +209,7 @@ public: | |||
| 209 | return surface_view.second; | 209 | return surface_view.second; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | TView GetColorBufferSurface(std::size_t index) { | 212 | TView GetColorBufferSurface(std::size_t index, bool preserve_contents) { |
| 213 | std::lock_guard lock{mutex}; | 213 | std::lock_guard lock{mutex}; |
| 214 | ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); | 214 | ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); |
| 215 | auto& maxwell3d = system.GPU().Maxwell3D(); | 215 | auto& maxwell3d = system.GPU().Maxwell3D(); |
| @@ -239,8 +239,9 @@ public: | |||
| 239 | return {}; | 239 | return {}; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | auto surface_view = GetSurface(gpu_addr, *cpu_addr, | 242 | auto surface_view = |
| 243 | SurfaceParams::CreateForFramebuffer(system, index), true); | 243 | GetSurface(gpu_addr, *cpu_addr, SurfaceParams::CreateForFramebuffer(system, index), |
| 244 | preserve_contents, true); | ||
| 244 | if (render_targets[index].target) { | 245 | if (render_targets[index].target) { |
| 245 | auto& surface = render_targets[index].target; | 246 | auto& surface = render_targets[index].target; |
| 246 | surface->MarkAsRenderTarget(false, NO_RT); | 247 | surface->MarkAsRenderTarget(false, NO_RT); |
| @@ -300,9 +301,9 @@ public: | |||
| 300 | const std::optional<VAddr> src_cpu_addr = | 301 | const std::optional<VAddr> src_cpu_addr = |
| 301 | system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr); | 302 | system.GPU().MemoryManager().GpuToCpuAddress(src_gpu_addr); |
| 302 | std::pair<TSurface, TView> dst_surface = | 303 | std::pair<TSurface, TView> dst_surface = |
| 303 | GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, false); | 304 | GetSurface(dst_gpu_addr, *dst_cpu_addr, dst_params, true, false); |
| 304 | std::pair<TSurface, TView> src_surface = | 305 | std::pair<TSurface, TView> src_surface = |
| 305 | GetSurface(src_gpu_addr, *src_cpu_addr, src_params, false); | 306 | GetSurface(src_gpu_addr, *src_cpu_addr, src_params, true, false); |
| 306 | ImageBlit(src_surface.second, dst_surface.second, copy_config); | 307 | ImageBlit(src_surface.second, dst_surface.second, copy_config); |
| 307 | dst_surface.first->MarkAsModified(true, Tick()); | 308 | dst_surface.first->MarkAsModified(true, Tick()); |
| 308 | } | 309 | } |
| @@ -532,18 +533,22 @@ private: | |||
| 532 | * @param overlaps The overlapping surfaces registered in the cache. | 533 | * @param overlaps The overlapping surfaces registered in the cache. |
| 533 | * @param params The parameters for the new surface. | 534 | * @param params The parameters for the new surface. |
| 534 | * @param gpu_addr The starting address of the new surface. | 535 | * @param gpu_addr The starting address of the new surface. |
| 536 | * @param preserve_contents Indicates that the new surface should be loaded from memory or left | ||
| 537 | * blank. | ||
| 535 | * @param untopological Indicates to the recycler that the texture has no way to match the | 538 | * @param untopological Indicates to the recycler that the texture has no way to match the |
| 536 | * overlaps due to topological reasons. | 539 | * overlaps due to topological reasons. |
| 537 | **/ | 540 | **/ |
| 538 | std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps, | 541 | std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps, |
| 539 | const SurfaceParams& params, const GPUVAddr gpu_addr, | 542 | const SurfaceParams& params, const GPUVAddr gpu_addr, |
| 543 | const bool preserve_contents, | ||
| 540 | const MatchTopologyResult untopological) { | 544 | const MatchTopologyResult untopological) { |
| 545 | const bool do_load = preserve_contents && Settings::IsGPULevelExtreme(); | ||
| 541 | for (auto& surface : overlaps) { | 546 | for (auto& surface : overlaps) { |
| 542 | Unregister(surface); | 547 | Unregister(surface); |
| 543 | } | 548 | } |
| 544 | switch (PickStrategy(overlaps, params, gpu_addr, untopological)) { | 549 | switch (PickStrategy(overlaps, params, gpu_addr, untopological)) { |
| 545 | case RecycleStrategy::Ignore: { | 550 | case RecycleStrategy::Ignore: { |
| 546 | return InitializeSurface(gpu_addr, params, Settings::IsGPULevelExtreme()); | 551 | return InitializeSurface(gpu_addr, params, do_load); |
| 547 | } | 552 | } |
| 548 | case RecycleStrategy::Flush: { | 553 | case RecycleStrategy::Flush: { |
| 549 | std::sort(overlaps.begin(), overlaps.end(), | 554 | std::sort(overlaps.begin(), overlaps.end(), |
| @@ -553,7 +558,7 @@ private: | |||
| 553 | for (auto& surface : overlaps) { | 558 | for (auto& surface : overlaps) { |
| 554 | FlushSurface(surface); | 559 | FlushSurface(surface); |
| 555 | } | 560 | } |
| 556 | return InitializeSurface(gpu_addr, params); | 561 | return InitializeSurface(gpu_addr, params, preserve_contents); |
| 557 | } | 562 | } |
| 558 | case RecycleStrategy::BufferCopy: { | 563 | case RecycleStrategy::BufferCopy: { |
| 559 | auto new_surface = GetUncachedSurface(gpu_addr, params); | 564 | auto new_surface = GetUncachedSurface(gpu_addr, params); |
| @@ -562,7 +567,7 @@ private: | |||
| 562 | } | 567 | } |
| 563 | default: { | 568 | default: { |
| 564 | UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!"); | 569 | UNIMPLEMENTED_MSG("Unimplemented Texture Cache Recycling Strategy!"); |
| 565 | return InitializeSurface(gpu_addr, params); | 570 | return InitializeSurface(gpu_addr, params, do_load); |
| 566 | } | 571 | } |
| 567 | } | 572 | } |
| 568 | } | 573 | } |
| @@ -700,11 +705,14 @@ private: | |||
| 700 | * @param params The parameters on the new surface. | 705 | * @param params The parameters on the new surface. |
| 701 | * @param gpu_addr The starting address of the new surface. | 706 | * @param gpu_addr The starting address of the new surface. |
| 702 | * @param cpu_addr The starting address of the new surface on physical memory. | 707 | * @param cpu_addr The starting address of the new surface on physical memory. |
| 708 | * @param preserve_contents Indicates that the new surface should be loaded from memory or | ||
| 709 | * left blank. | ||
| 703 | */ | 710 | */ |
| 704 | std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps, | 711 | std::optional<std::pair<TSurface, TView>> Manage3DSurfaces(std::vector<TSurface>& overlaps, |
| 705 | const SurfaceParams& params, | 712 | const SurfaceParams& params, |
| 706 | const GPUVAddr gpu_addr, | 713 | const GPUVAddr gpu_addr, |
| 707 | const VAddr cpu_addr) { | 714 | const VAddr cpu_addr, |
| 715 | bool preserve_contents) { | ||
| 708 | if (params.target == SurfaceTarget::Texture3D) { | 716 | if (params.target == SurfaceTarget::Texture3D) { |
| 709 | bool failed = false; | 717 | bool failed = false; |
| 710 | if (params.num_levels > 1) { | 718 | if (params.num_levels > 1) { |
| @@ -754,7 +762,7 @@ private: | |||
| 754 | return std::nullopt; | 762 | return std::nullopt; |
| 755 | } | 763 | } |
| 756 | Unregister(surface); | 764 | Unregister(surface); |
| 757 | return InitializeSurface(gpu_addr, params); | 765 | return InitializeSurface(gpu_addr, params, preserve_contents); |
| 758 | } | 766 | } |
| 759 | return std::nullopt; | 767 | return std::nullopt; |
| 760 | } | 768 | } |
| @@ -765,7 +773,7 @@ private: | |||
| 765 | return {{surface, surface->GetMainView()}}; | 773 | return {{surface, surface->GetMainView()}}; |
| 766 | } | 774 | } |
| 767 | } | 775 | } |
| 768 | return InitializeSurface(gpu_addr, params); | 776 | return InitializeSurface(gpu_addr, params, preserve_contents); |
| 769 | } | 777 | } |
| 770 | } | 778 | } |
| 771 | 779 | ||
| @@ -788,10 +796,13 @@ private: | |||
| 788 | * | 796 | * |
| 789 | * @param gpu_addr The starting address of the candidate surface. | 797 | * @param gpu_addr The starting address of the candidate surface. |
| 790 | * @param params The parameters on the candidate surface. | 798 | * @param params The parameters on the candidate surface. |
| 799 | * @param preserve_contents Indicates that the new surface should be loaded from memory or | ||
| 800 | * left blank. | ||
| 791 | * @param is_render Whether or not the surface is a render target. | 801 | * @param is_render Whether or not the surface is a render target. |
| 792 | **/ | 802 | **/ |
| 793 | std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const VAddr cpu_addr, | 803 | std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const VAddr cpu_addr, |
| 794 | const SurfaceParams& params, bool is_render) { | 804 | const SurfaceParams& params, bool preserve_contents, |
| 805 | bool is_render) { | ||
| 795 | // Step 1 | 806 | // Step 1 |
| 796 | // Check Level 1 Cache for a fast structural match. If candidate surface | 807 | // Check Level 1 Cache for a fast structural match. If candidate surface |
| 797 | // matches at certain level we are pretty much done. | 808 | // matches at certain level we are pretty much done. |
| @@ -800,7 +811,8 @@ private: | |||
| 800 | const auto topological_result = current_surface->MatchesTopology(params); | 811 | const auto topological_result = current_surface->MatchesTopology(params); |
| 801 | if (topological_result != MatchTopologyResult::FullMatch) { | 812 | if (topological_result != MatchTopologyResult::FullMatch) { |
| 802 | std::vector<TSurface> overlaps{current_surface}; | 813 | std::vector<TSurface> overlaps{current_surface}; |
| 803 | return RecycleSurface(overlaps, params, gpu_addr, topological_result); | 814 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 815 | topological_result); | ||
| 804 | } | 816 | } |
| 805 | 817 | ||
| 806 | const auto struct_result = current_surface->MatchesStructure(params); | 818 | const auto struct_result = current_surface->MatchesStructure(params); |
| @@ -825,7 +837,7 @@ private: | |||
| 825 | 837 | ||
| 826 | // If none are found, we are done. we just load the surface and create it. | 838 | // If none are found, we are done. we just load the surface and create it. |
| 827 | if (overlaps.empty()) { | 839 | if (overlaps.empty()) { |
| 828 | return InitializeSurface(gpu_addr, params); | 840 | return InitializeSurface(gpu_addr, params, preserve_contents); |
| 829 | } | 841 | } |
| 830 | 842 | ||
| 831 | // Step 3 | 843 | // Step 3 |
| @@ -835,13 +847,15 @@ private: | |||
| 835 | for (const auto& surface : overlaps) { | 847 | for (const auto& surface : overlaps) { |
| 836 | const auto topological_result = surface->MatchesTopology(params); | 848 | const auto topological_result = surface->MatchesTopology(params); |
| 837 | if (topological_result != MatchTopologyResult::FullMatch) { | 849 | if (topological_result != MatchTopologyResult::FullMatch) { |
| 838 | return RecycleSurface(overlaps, params, gpu_addr, topological_result); | 850 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 851 | topological_result); | ||
| 839 | } | 852 | } |
| 840 | } | 853 | } |
| 841 | 854 | ||
| 842 | // Check if it's a 3D texture | 855 | // Check if it's a 3D texture |
| 843 | if (params.block_depth > 0) { | 856 | if (params.block_depth > 0) { |
| 844 | auto surface = Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr); | 857 | auto surface = |
| 858 | Manage3DSurfaces(overlaps, params, gpu_addr, cpu_addr, preserve_contents); | ||
| 845 | if (surface) { | 859 | if (surface) { |
| 846 | return *surface; | 860 | return *surface; |
| 847 | } | 861 | } |
| @@ -861,7 +875,8 @@ private: | |||
| 861 | return *view; | 875 | return *view; |
| 862 | } | 876 | } |
| 863 | } | 877 | } |
| 864 | return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch); | 878 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 879 | MatchTopologyResult::FullMatch); | ||
| 865 | } | 880 | } |
| 866 | // Now we check if the candidate is a mipmap/layer of the overlap | 881 | // Now we check if the candidate is a mipmap/layer of the overlap |
| 867 | std::optional<TView> view = | 882 | std::optional<TView> view = |
| @@ -885,7 +900,7 @@ private: | |||
| 885 | pair.first->EmplaceView(params, gpu_addr, candidate_size); | 900 | pair.first->EmplaceView(params, gpu_addr, candidate_size); |
| 886 | if (mirage_view) | 901 | if (mirage_view) |
| 887 | return {pair.first, *mirage_view}; | 902 | return {pair.first, *mirage_view}; |
| 888 | return RecycleSurface(overlaps, params, gpu_addr, | 903 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 889 | MatchTopologyResult::FullMatch); | 904 | MatchTopologyResult::FullMatch); |
| 890 | } | 905 | } |
| 891 | return {current_surface, *view}; | 906 | return {current_surface, *view}; |
| @@ -901,7 +916,8 @@ private: | |||
| 901 | } | 916 | } |
| 902 | } | 917 | } |
| 903 | // We failed all the tests, recycle the overlaps into a new texture. | 918 | // We failed all the tests, recycle the overlaps into a new texture. |
| 904 | return RecycleSurface(overlaps, params, gpu_addr, MatchTopologyResult::FullMatch); | 919 | return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, |
| 920 | MatchTopologyResult::FullMatch); | ||
| 905 | } | 921 | } |
| 906 | 922 | ||
| 907 | /** | 923 | /** |
| @@ -1059,10 +1075,10 @@ private: | |||
| 1059 | } | 1075 | } |
| 1060 | 1076 | ||
| 1061 | std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params, | 1077 | std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params, |
| 1062 | bool do_load = true) { | 1078 | bool preserve_contents) { |
| 1063 | auto new_surface{GetUncachedSurface(gpu_addr, params)}; | 1079 | auto new_surface{GetUncachedSurface(gpu_addr, params)}; |
| 1064 | Register(new_surface); | 1080 | Register(new_surface); |
| 1065 | if (do_load) { | 1081 | if (preserve_contents) { |
| 1066 | LoadSurface(new_surface); | 1082 | LoadSurface(new_surface); |
| 1067 | } | 1083 | } |
| 1068 | return {new_surface, new_surface->GetMainView()}; | 1084 | return {new_surface, new_surface->GetMainView()}; |