summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-23 12:04:37 -0400
committerGravatar GitHub2018-08-23 12:04:37 -0400
commit0dce6d70083d07daa44aebdbf72e1d88e05a63f5 (patch)
treeced6866d85746af7b46bcf12b95ba923adeecc5b
parentMerge pull request #1153 from bunnei/stencil-clear (diff)
parentgl_rasterizer_cache: Blit when possible on RecreateSurface. (diff)
downloadyuzu-0dce6d70083d07daa44aebdbf72e1d88e05a63f5.tar.gz
yuzu-0dce6d70083d07daa44aebdbf72e1d88e05a63f5.tar.xz
yuzu-0dce6d70083d07daa44aebdbf72e1d88e05a63f5.zip
Merge pull request #1160 from bunnei/surface-reserve
gl_rasterizer_cache: Several improvements
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp75
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h33
2 files changed, 91 insertions, 17 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b1769c99b..83d8d3d94 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -780,17 +780,30 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
780 } else if (preserve_contents) { 780 } else if (preserve_contents) {
781 // If surface parameters changed and we care about keeping the previous data, recreate 781 // If surface parameters changed and we care about keeping the previous data, recreate
782 // the surface from the old one 782 // the surface from the old one
783 return RecreateSurface(surface, params); 783 UnregisterSurface(surface);
784 Surface new_surface{RecreateSurface(surface, params)};
785 RegisterSurface(new_surface);
786 return new_surface;
784 } else { 787 } else {
785 // Delete the old surface before creating a new one to prevent collisions. 788 // Delete the old surface before creating a new one to prevent collisions.
786 UnregisterSurface(surface); 789 UnregisterSurface(surface);
787 } 790 }
788 } 791 }
789 792
793 // Try to get a previously reserved surface
794 surface = TryGetReservedSurface(params);
795
790 // No surface found - create a new one 796 // No surface found - create a new one
791 surface = std::make_shared<CachedSurface>(params); 797 if (!surface) {
792 RegisterSurface(surface); 798 surface = std::make_shared<CachedSurface>(params);
793 LoadSurface(surface); 799 ReserveSurface(surface);
800 RegisterSurface(surface);
801 }
802
803 // Only load surface from memory if we care about the contents
804 if (preserve_contents) {
805 LoadSurface(surface);
806 }
794 807
795 return surface; 808 return surface;
796} 809}
@@ -799,13 +812,18 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
799 const SurfaceParams& new_params) { 812 const SurfaceParams& new_params) {
800 // Verify surface is compatible for blitting 813 // Verify surface is compatible for blitting
801 const auto& params{surface->GetSurfaceParams()}; 814 const auto& params{surface->GetSurfaceParams()};
802 ASSERT(params.type == new_params.type);
803 ASSERT_MSG(params.GetCompressionFactor(params.pixel_format) == 1,
804 "Compressed texture reinterpretation is not supported");
805 815
806 // Create a new surface with the new parameters, and blit the previous surface to it 816 // Create a new surface with the new parameters, and blit the previous surface to it
807 Surface new_surface{std::make_shared<CachedSurface>(new_params)}; 817 Surface new_surface{std::make_shared<CachedSurface>(new_params)};
808 818
819 // If format is unchanged, we can do a faster blit without reinterpreting pixel data
820 if (params.pixel_format == new_params.pixel_format) {
821 BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
822 new_surface->GetSurfaceParams().GetRect(), params.type,
823 read_framebuffer.handle, draw_framebuffer.handle);
824 return new_surface;
825 }
826
809 auto source_format = GetFormatTuple(params.pixel_format, params.component_type); 827 auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
810 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); 828 auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
811 829
@@ -818,9 +836,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
818 836
819 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); 837 glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
820 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); 838 glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
821 glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type, 839 if (source_format.compressed) {
822 params.SizeInBytes(), nullptr); 840 glGetCompressedTextureImage(surface->Texture().handle, 0,
823 841 static_cast<GLsizei>(params.SizeInBytes()), nullptr);
842 } else {
843 glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type,
844 static_cast<GLsizei>(params.SizeInBytes()), nullptr);
845 }
824 // If the new texture is bigger than the previous one, we need to fill in the rest with data 846 // If the new texture is bigger than the previous one, we need to fill in the rest with data
825 // from the CPU. 847 // from the CPU.
826 if (params.SizeInBytes() < new_params.SizeInBytes()) { 848 if (params.SizeInBytes() < new_params.SizeInBytes()) {
@@ -846,17 +868,21 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
846 const auto& dest_rect{new_params.GetRect()}; 868 const auto& dest_rect{new_params.GetRect()};
847 869
848 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); 870 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
849 glTextureSubImage2D( 871 if (dest_format.compressed) {
850 new_surface->Texture().handle, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()), 872 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
851 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr); 873 static_cast<GLsizei>(dest_rect.GetWidth()),
874 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
875 static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
876 } else {
877 glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
878 static_cast<GLsizei>(dest_rect.GetWidth()),
879 static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
880 dest_format.type, nullptr);
881 }
852 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); 882 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
853 883
854 pbo.Release(); 884 pbo.Release();
855 885
856 // Update cache accordingly
857 UnregisterSurface(surface);
858 RegisterSurface(new_surface);
859
860 return new_surface; 886 return new_surface;
861} 887}
862 888
@@ -931,6 +957,21 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
931 surface_cache.erase(search); 957 surface_cache.erase(search);
932} 958}
933 959
960void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) {
961 const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())};
962 surface_reserve[surface_reserve_key] = surface;
963}
964
965Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params) {
966 const auto& surface_reserve_key{SurfaceReserveKey::Create(params)};
967 auto search{surface_reserve.find(surface_reserve_key)};
968 if (search != surface_reserve.end()) {
969 RegisterSurface(search->second);
970 return search->second;
971 }
972 return {};
973}
974
934template <typename Map, typename Interval> 975template <typename Map, typename Interval>
935constexpr auto RangeFromInterval(Map& map, const Interval& interval) { 976constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
936 return boost::make_iterator_range(map.equal_range(interval)); 977 return boost::make_iterator_range(map.equal_range(interval));
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index f273152a2..c8c615df2 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -11,6 +11,7 @@
11#include <boost/icl/interval_map.hpp> 11#include <boost/icl/interval_map.hpp>
12 12
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/hash.h"
14#include "common/math_util.h" 15#include "common/math_util.h"
15#include "video_core/engines/maxwell_3d.h" 16#include "video_core/engines/maxwell_3d.h"
16#include "video_core/renderer_opengl/gl_resource_manager.h" 17#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -682,6 +683,27 @@ struct SurfaceParams {
682 u32 cache_height; 683 u32 cache_height;
683}; 684};
684 685
686}; // namespace OpenGL
687
688/// Hashable variation of SurfaceParams, used for a key in the surface cache
689struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
690 static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) {
691 SurfaceReserveKey res;
692 res.state = params;
693 return res;
694 }
695};
696namespace std {
697template <>
698struct hash<SurfaceReserveKey> {
699 size_t operator()(const SurfaceReserveKey& k) const {
700 return k.Hash();
701 }
702};
703} // namespace std
704
705namespace OpenGL {
706
685class CachedSurface final { 707class CachedSurface final {
686public: 708public:
687 CachedSurface(const SurfaceParams& params); 709 CachedSurface(const SurfaceParams& params);
@@ -752,12 +774,23 @@ private:
752 /// Remove surface from the cache 774 /// Remove surface from the cache
753 void UnregisterSurface(const Surface& surface); 775 void UnregisterSurface(const Surface& surface);
754 776
777 /// Reserves a unique surface that can be reused later
778 void ReserveSurface(const Surface& surface);
779
780 /// Tries to get a reserved surface for the specified parameters
781 Surface TryGetReservedSurface(const SurfaceParams& params);
782
755 /// Increase/decrease the number of surface in pages touching the specified region 783 /// Increase/decrease the number of surface in pages touching the specified region
756 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta); 784 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
757 785
758 std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache; 786 std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
759 PageMap cached_pages; 787 PageMap cached_pages;
760 788
789 /// 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
791 /// destroyed when used with different surface parameters.
792 std::unordered_map<SurfaceReserveKey, Surface> surface_reserve;
793
761 OGLFramebuffer read_framebuffer; 794 OGLFramebuffer read_framebuffer;
762 OGLFramebuffer draw_framebuffer; 795 OGLFramebuffer draw_framebuffer;
763}; 796};