diff options
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()}; |