summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp110
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h37
3 files changed, 20 insertions, 132 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 96851ccb5..41a58598b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -571,12 +571,10 @@ void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {}
571 571
572void RasterizerOpenGL::FlushAll() { 572void RasterizerOpenGL::FlushAll() {
573 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 573 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
574 res_cache.FlushRegion(0, Kernel::VMManager::MAX_ADDRESS);
575} 574}
576 575
577void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) { 576void RasterizerOpenGL::FlushRegion(Tegra::GPUVAddr addr, u64 size) {
578 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 577 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
579 res_cache.FlushRegion(addr, size);
580} 578}
581 579
582void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) { 580void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
@@ -586,8 +584,7 @@ void RasterizerOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
586 584
587void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) { 585void RasterizerOpenGL::FlushAndInvalidateRegion(Tegra::GPUVAddr addr, u64 size) {
588 MICROPROFILE_SCOPE(OpenGL_CacheManagement); 586 MICROPROFILE_SCOPE(OpenGL_CacheManagement);
589 res_cache.FlushRegion(addr, size); 587 InvalidateRegion(addr, size);
590 res_cache.InvalidateRegion(addr, size);
591} 588}
592 589
593bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) { 590bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 83d8d3d94..65305000c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -677,12 +677,6 @@ RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
677 draw_framebuffer.Create(); 677 draw_framebuffer.Create();
678} 678}
679 679
680RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
681 while (!surface_cache.empty()) {
682 UnregisterSurface(surface_cache.begin()->second);
683 }
684}
685
686Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) { 680Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextureInfo& config) {
687 return GetSurface(SurfaceParams::CreateForTexture(config)); 681 return GetSurface(SurfaceParams::CreateForTexture(config));
688} 682}
@@ -766,27 +760,25 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
766 return {}; 760 return {};
767 761
768 // Look up surface in the cache based on address 762 // Look up surface in the cache based on address
769 const auto& search{surface_cache.find(params.addr)}; 763 Surface surface{TryGet(params.addr)};
770 Surface surface; 764 if (surface) {
771 if (search != surface_cache.end()) {
772 surface = search->second;
773 if (Settings::values.use_accurate_framebuffers) { 765 if (Settings::values.use_accurate_framebuffers) {
774 // If use_accurate_framebuffers is enabled, always load from memory 766 // If use_accurate_framebuffers is enabled, always load from memory
775 FlushSurface(surface); 767 FlushSurface(surface);
776 UnregisterSurface(surface); 768 Unregister(surface);
777 } else if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { 769 } else if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
778 // Use the cached surface as-is 770 // Use the cached surface as-is
779 return surface; 771 return surface;
780 } else if (preserve_contents) { 772 } else if (preserve_contents) {
781 // If surface parameters changed and we care about keeping the previous data, recreate 773 // If surface parameters changed and we care about keeping the previous data, recreate
782 // the surface from the old one 774 // the surface from the old one
783 UnregisterSurface(surface); 775 Unregister(surface);
784 Surface new_surface{RecreateSurface(surface, params)}; 776 Surface new_surface{RecreateSurface(surface, params)};
785 RegisterSurface(new_surface); 777 Register(new_surface);
786 return new_surface; 778 return new_surface;
787 } else { 779 } else {
788 // Delete the old surface before creating a new one to prevent collisions. 780 // Delete the old surface before creating a new one to prevent collisions.
789 UnregisterSurface(surface); 781 Unregister(surface);
790 } 782 }
791 } 783 }
792 784
@@ -797,7 +789,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
797 if (!surface) { 789 if (!surface) {
798 surface = std::make_shared<CachedSurface>(params); 790 surface = std::make_shared<CachedSurface>(params);
799 ReserveSurface(surface); 791 ReserveSurface(surface);
800 RegisterSurface(surface); 792 Register(surface);
801 } 793 }
802 794
803 // Only load surface from memory if we care about the contents 795 // Only load surface from memory if we care about the contents
@@ -894,7 +886,7 @@ Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const {
894 // framebuffer overlaps surfaces. 886 // framebuffer overlaps surfaces.
895 887
896 std::vector<Surface> surfaces; 888 std::vector<Surface> surfaces;
897 for (const auto& surface : surface_cache) { 889 for (const auto& surface : GetCache()) {
898 const auto& params = surface.second->GetSurfaceParams(); 890 const auto& params = surface.second->GetSurfaceParams();
899 const VAddr surface_cpu_addr = params.GetCpuAddr(); 891 const VAddr surface_cpu_addr = params.GetCpuAddr();
900 if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + params.size_in_bytes)) { 892 if (cpu_addr >= surface_cpu_addr && cpu_addr < (surface_cpu_addr + params.size_in_bytes)) {
@@ -912,51 +904,6 @@ Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const {
912 return surfaces[0]; 904 return surfaces[0];
913} 905}
914 906
915void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr /*addr*/, size_t /*size*/) {
916 // TODO(bunnei): This is unused in the current implementation of the rasterizer cache. We should
917 // probably implement this in the future, but for now, the `use_accurate_framebufers` setting
918 // can be used to always flush.
919}
920
921void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, size_t size) {
922 for (auto iter = surface_cache.cbegin(); iter != surface_cache.cend();) {
923 const auto& surface{iter->second};
924 const auto& params{surface->GetSurfaceParams()};
925
926 ++iter;
927
928 if (params.IsOverlappingRegion(addr, size)) {
929 UnregisterSurface(surface);
930 }
931 }
932}
933
934void RasterizerCacheOpenGL::RegisterSurface(const Surface& surface) {
935 const auto& params{surface->GetSurfaceParams()};
936 const auto& search{surface_cache.find(params.addr)};
937
938 if (search != surface_cache.end()) {
939 // Registered already
940 return;
941 }
942
943 surface_cache[params.addr] = surface;
944 UpdatePagesCachedCount(params.addr, params.size_in_bytes, 1);
945}
946
947void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
948 const auto& params{surface->GetSurfaceParams()};
949 const auto& search{surface_cache.find(params.addr)};
950
951 if (search == surface_cache.end()) {
952 // Unregistered already
953 return;
954 }
955
956 UpdatePagesCachedCount(params.addr, params.size_in_bytes, -1);
957 surface_cache.erase(search);
958}
959
960void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) { 907void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) {
961 const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())}; 908 const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())};
962 surface_reserve[surface_reserve_key] = surface; 909 surface_reserve[surface_reserve_key] = surface;
@@ -966,49 +913,10 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params
966 const auto& surface_reserve_key{SurfaceReserveKey::Create(params)}; 913 const auto& surface_reserve_key{SurfaceReserveKey::Create(params)};
967 auto search{surface_reserve.find(surface_reserve_key)}; 914 auto search{surface_reserve.find(surface_reserve_key)};
968 if (search != surface_reserve.end()) { 915 if (search != surface_reserve.end()) {
969 RegisterSurface(search->second); 916 Register(search->second);
970 return search->second; 917 return search->second;
971 } 918 }
972 return {}; 919 return {};
973} 920}
974 921
975template <typename Map, typename Interval>
976constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
977 return boost::make_iterator_range(map.equal_range(interval));
978}
979
980void RasterizerCacheOpenGL::UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) {
981 const u64 num_pages = ((addr + size - 1) >> Tegra::MemoryManager::PAGE_BITS) -
982 (addr >> Tegra::MemoryManager::PAGE_BITS) + 1;
983 const u64 page_start = addr >> Tegra::MemoryManager::PAGE_BITS;
984 const u64 page_end = page_start + num_pages;
985
986 // Interval maps will erase segments if count reaches 0, so if delta is negative we have to
987 // subtract after iterating
988 const auto pages_interval = PageMap::interval_type::right_open(page_start, page_end);
989 if (delta > 0)
990 cached_pages.add({pages_interval, delta});
991
992 for (const auto& pair : RangeFromInterval(cached_pages, pages_interval)) {
993 const auto interval = pair.first & pages_interval;
994 const int count = pair.second;
995
996 const Tegra::GPUVAddr interval_start_addr = boost::icl::first(interval)
997 << Tegra::MemoryManager::PAGE_BITS;
998 const Tegra::GPUVAddr interval_end_addr = boost::icl::last_next(interval)
999 << Tegra::MemoryManager::PAGE_BITS;
1000 const u64 interval_size = interval_end_addr - interval_start_addr;
1001
1002 if (delta > 0 && count == delta)
1003 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
1004 else if (delta < 0 && count == -delta)
1005 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
1006 else
1007 ASSERT(count >= 0);
1008 }
1009
1010 if (delta < 0)
1011 cached_pages.add({pages_interval, delta});
1012}
1013
1014} // namespace OpenGL 922} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index c8c615df2..8a6ca2a4b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -8,12 +8,12 @@
8#include <map> 8#include <map>
9#include <memory> 9#include <memory>
10#include <vector> 10#include <vector>
11#include <boost/icl/interval_map.hpp>
12 11
13#include "common/common_types.h" 12#include "common/common_types.h"
14#include "common/hash.h" 13#include "common/hash.h"
15#include "common/math_util.h" 14#include "common/math_util.h"
16#include "video_core/engines/maxwell_3d.h" 15#include "video_core/engines/maxwell_3d.h"
16#include "video_core/rasterizer_cache.h"
17#include "video_core/renderer_opengl/gl_resource_manager.h" 17#include "video_core/renderer_opengl/gl_resource_manager.h"
18#include "video_core/textures/texture.h" 18#include "video_core/textures/texture.h"
19 19
@@ -22,7 +22,6 @@ namespace OpenGL {
22class CachedSurface; 22class CachedSurface;
23using Surface = std::shared_ptr<CachedSurface>; 23using Surface = std::shared_ptr<CachedSurface>;
24using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; 24using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
25using PageMap = boost::icl::interval_map<u64, int>;
26 25
27struct SurfaceParams { 26struct SurfaceParams {
28 enum class PixelFormat { 27 enum class PixelFormat {
@@ -632,11 +631,6 @@ struct SurfaceParams {
632 /// Returns the CPU virtual address for this surface 631 /// Returns the CPU virtual address for this surface
633 VAddr GetCpuAddr() const; 632 VAddr GetCpuAddr() const;
634 633
635 /// Returns true if the specified region overlaps with this surface's region in Switch memory
636 bool IsOverlappingRegion(Tegra::GPUVAddr region_addr, size_t region_size) const {
637 return addr <= (region_addr + region_size) && region_addr <= (addr + size_in_bytes);
638 }
639
640 /// Creates SurfaceParams from a texture configuration 634 /// Creates SurfaceParams from a texture configuration
641 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config); 635 static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
642 636
@@ -708,6 +702,14 @@ class CachedSurface final {
708public: 702public:
709 CachedSurface(const SurfaceParams& params); 703 CachedSurface(const SurfaceParams& params);
710 704
705 Tegra::GPUVAddr GetAddr() const {
706 return params.addr;
707 }
708
709 size_t GetSizeInBytes() const {
710 return params.size_in_bytes;
711 }
712
711 const OGLTexture& Texture() const { 713 const OGLTexture& Texture() const {
712 return texture; 714 return texture;
713 } 715 }
@@ -737,10 +739,9 @@ private:
737 SurfaceParams params; 739 SurfaceParams params;
738}; 740};
739 741
740class RasterizerCacheOpenGL final : NonCopyable { 742class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
741public: 743public:
742 RasterizerCacheOpenGL(); 744 RasterizerCacheOpenGL();
743 ~RasterizerCacheOpenGL();
744 745
745 /// Get a surface based on the texture configuration 746 /// Get a surface based on the texture configuration
746 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); 747 Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config);
@@ -755,12 +756,6 @@ public:
755 /// Tries to find a framebuffer GPU address based on the provided CPU address 756 /// Tries to find a framebuffer GPU address based on the provided CPU address
756 Surface TryFindFramebufferSurface(VAddr cpu_addr) const; 757 Surface TryFindFramebufferSurface(VAddr cpu_addr) const;
757 758
758 /// Write any cached resources overlapping the region back to memory (if dirty)
759 void FlushRegion(Tegra::GPUVAddr addr, size_t size);
760
761 /// Mark the specified region as being invalidated
762 void InvalidateRegion(Tegra::GPUVAddr addr, size_t size);
763
764private: 759private:
765 void LoadSurface(const Surface& surface); 760 void LoadSurface(const Surface& surface);
766 Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); 761 Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true);
@@ -768,24 +763,12 @@ private:
768 /// Recreates a surface with new parameters 763 /// Recreates a surface with new parameters
769 Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params); 764 Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params);
770 765
771 /// Register surface into the cache
772 void RegisterSurface(const Surface& surface);
773
774 /// Remove surface from the cache
775 void UnregisterSurface(const Surface& surface);
776
777 /// Reserves a unique surface that can be reused later 766 /// Reserves a unique surface that can be reused later
778 void ReserveSurface(const Surface& surface); 767 void ReserveSurface(const Surface& surface);
779 768
780 /// Tries to get a reserved surface for the specified parameters 769 /// Tries to get a reserved surface for the specified parameters
781 Surface TryGetReservedSurface(const SurfaceParams& params); 770 Surface TryGetReservedSurface(const SurfaceParams& params);
782 771
783 /// Increase/decrease the number of surface in pages touching the specified region
784 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
785
786 std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
787 PageMap cached_pages;
788
789 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have 772 /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
790 /// previously been used. This is to prevent surfaces from being constantly created and 773 /// previously been used. This is to prevent surfaces from being constantly created and
791 /// destroyed when used with different surface parameters. 774 /// destroyed when used with different surface parameters.