summaryrefslogtreecommitdiff
path: root/src/video_core/texture_cache
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-04-26 19:53:02 -0300
committerGravatar ReinUsesLisp2020-04-26 19:53:02 -0300
commit8da16cf9fb6c2133faed1164a8573992e84a4297 (patch)
treea0d14c5ec0955d35cbc22b1670eadcdbdbe5ba31 /src/video_core/texture_cache
parentMerge pull request #3795 from vitor-k/fix-folder (diff)
downloadyuzu-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.h66
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()};