diff options
| author | 2018-08-23 12:04:37 -0400 | |
|---|---|---|
| committer | 2018-08-23 12:04:37 -0400 | |
| commit | 0dce6d70083d07daa44aebdbf72e1d88e05a63f5 (patch) | |
| tree | ced6866d85746af7b46bcf12b95ba923adeecc5b | |
| parent | Merge pull request #1153 from bunnei/stencil-clear (diff) | |
| parent | gl_rasterizer_cache: Blit when possible on RecreateSurface. (diff) | |
| download | yuzu-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.cpp | 75 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 33 |
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 | ||
| 960 | void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) { | ||
| 961 | const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())}; | ||
| 962 | surface_reserve[surface_reserve_key] = surface; | ||
| 963 | } | ||
| 964 | |||
| 965 | Surface 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 | |||
| 934 | template <typename Map, typename Interval> | 975 | template <typename Map, typename Interval> |
| 935 | constexpr auto RangeFromInterval(Map& map, const Interval& interval) { | 976 | constexpr 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 | ||
| 689 | struct 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 | }; | ||
| 696 | namespace std { | ||
| 697 | template <> | ||
| 698 | struct hash<SurfaceReserveKey> { | ||
| 699 | size_t operator()(const SurfaceReserveKey& k) const { | ||
| 700 | return k.Hash(); | ||
| 701 | } | ||
| 702 | }; | ||
| 703 | } // namespace std | ||
| 704 | |||
| 705 | namespace OpenGL { | ||
| 706 | |||
| 685 | class CachedSurface final { | 707 | class CachedSurface final { |
| 686 | public: | 708 | public: |
| 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 | }; |