From ebf57683405c12ce7c56d07bed1c040b149ef31f Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 21 Aug 2018 01:04:46 -0400 Subject: [PATCH 1/4] gl_rasterizer_cache: Implement compressed texture copies. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 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..dc582b2df 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -800,8 +800,6 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // Verify surface is compatible for blitting const auto& params{surface->GetSurfaceParams()}; ASSERT(params.type == new_params.type); - ASSERT_MSG(params.GetCompressionFactor(params.pixel_format) == 1, - "Compressed texture reinterpretation is not supported"); // Create a new surface with the new parameters, and blit the previous surface to it Surface new_surface{std::make_shared(new_params)}; @@ -818,9 +816,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); - glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type, - params.SizeInBytes(), nullptr); - + if (source_format.compressed) { + glGetCompressedTextureImage(surface->Texture().handle, 0, + static_cast(params.SizeInBytes()), nullptr); + } else { + glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type, + static_cast(params.SizeInBytes()), nullptr); + } // If the new texture is bigger than the previous one, we need to fill in the rest with data // from the CPU. if (params.SizeInBytes() < new_params.SizeInBytes()) { @@ -846,9 +848,17 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, const auto& dest_rect{new_params.GetRect()}; glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle); - glTextureSubImage2D( - new_surface->Texture().handle, 0, 0, 0, static_cast(dest_rect.GetWidth()), - static_cast(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr); + if (dest_format.compressed) { + glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + static_cast(dest_rect.GetWidth()), + static_cast(dest_rect.GetHeight()), dest_format.format, + static_cast(new_params.SizeInBytes()), nullptr); + } else { + glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0, + static_cast(dest_rect.GetWidth()), + static_cast(dest_rect.GetHeight()), dest_format.format, + dest_format.type, nullptr); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); pbo.Release(); From fde2017a3f626c3c4620d19dc1113bb277a99db0 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 21 Aug 2018 01:05:27 -0400 Subject: [PATCH 2/4] gl_rasterizer_cache: Remove assert for RecreateSurface type. --- src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index dc582b2df..a13c1d97d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -799,7 +799,6 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, const SurfaceParams& new_params) { // Verify surface is compatible for blitting const auto& params{surface->GetSurfaceParams()}; - ASSERT(params.type == new_params.type); // Create a new surface with the new parameters, and blit the previous surface to it Surface new_surface{std::make_shared(new_params)}; From fee8bdd90c3c8fd61385a84152cf22c107013747 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 21 Aug 2018 22:04:54 -0400 Subject: [PATCH 3/4] gl_rasterizer_cache: Reserve surfaces that have already been created for later use. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 31 +++++++++++++++-- .../renderer_opengl/gl_rasterizer_cache.h | 33 +++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index a13c1d97d..10b2d8f3c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -787,10 +787,20 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres } } + // Try to get a previously reserved surface + surface = TryGetReservedSurface(params); + // No surface found - create a new one - surface = std::make_shared(params); - RegisterSurface(surface); - LoadSurface(surface); + if (!surface) { + surface = std::make_shared(params); + ReserveSurface(surface); + RegisterSurface(surface); + } + + // Only load surface from memory if we care about the contents + if (preserve_contents) { + LoadSurface(surface); + } return surface; } @@ -940,6 +950,21 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) { surface_cache.erase(search); } +void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) { + const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())}; + surface_reserve[surface_reserve_key] = surface; +} + +Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params) { + const auto& surface_reserve_key{SurfaceReserveKey::Create(params)}; + auto search{surface_reserve.find(surface_reserve_key)}; + if (search != surface_reserve.end()) { + RegisterSurface(search->second); + return search->second; + } + return {}; +} + template constexpr auto RangeFromInterval(Map& map, const Interval& interval) { 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 @@ #include #include "common/common_types.h" +#include "common/hash.h" #include "common/math_util.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/renderer_opengl/gl_resource_manager.h" @@ -682,6 +683,27 @@ struct SurfaceParams { u32 cache_height; }; +}; // namespace OpenGL + +/// Hashable variation of SurfaceParams, used for a key in the surface cache +struct SurfaceReserveKey : Common::HashableStruct { + static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) { + SurfaceReserveKey res; + res.state = params; + return res; + } +}; +namespace std { +template <> +struct hash { + size_t operator()(const SurfaceReserveKey& k) const { + return k.Hash(); + } +}; +} // namespace std + +namespace OpenGL { + class CachedSurface final { public: CachedSurface(const SurfaceParams& params); @@ -752,12 +774,23 @@ private: /// Remove surface from the cache void UnregisterSurface(const Surface& surface); + /// Reserves a unique surface that can be reused later + void ReserveSurface(const Surface& surface); + + /// Tries to get a reserved surface for the specified parameters + Surface TryGetReservedSurface(const SurfaceParams& params); + /// Increase/decrease the number of surface in pages touching the specified region void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta); std::unordered_map surface_cache; PageMap cached_pages; + /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have + /// previously been used. This is to prevent surfaces from being constantly created and + /// destroyed when used with different surface parameters. + std::unordered_map surface_reserve; + OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; }; From d65f079cc130827112e0e74f787447d01a204ff8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 22 Aug 2018 18:46:05 -0400 Subject: [PATCH 4/4] gl_rasterizer_cache: Blit when possible on RecreateSurface. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 10b2d8f3c..83d8d3d94 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -780,7 +780,10 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres } else if (preserve_contents) { // If surface parameters changed and we care about keeping the previous data, recreate // the surface from the old one - return RecreateSurface(surface, params); + UnregisterSurface(surface); + Surface new_surface{RecreateSurface(surface, params)}; + RegisterSurface(new_surface); + return new_surface; } else { // Delete the old surface before creating a new one to prevent collisions. UnregisterSurface(surface); @@ -813,6 +816,14 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, // Create a new surface with the new parameters, and blit the previous surface to it Surface new_surface{std::make_shared(new_params)}; + // If format is unchanged, we can do a faster blit without reinterpreting pixel data + if (params.pixel_format == new_params.pixel_format) { + BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle, + new_surface->GetSurfaceParams().GetRect(), params.type, + read_framebuffer.handle, draw_framebuffer.handle); + return new_surface; + } + auto source_format = GetFormatTuple(params.pixel_format, params.component_type); auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); @@ -872,10 +883,6 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface, pbo.Release(); - // Update cache accordingly - UnregisterSurface(surface); - RegisterSurface(new_surface); - return new_surface; }