From 44ea2810e422c6b53e56b26fc8aa918c48b80c8b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 8 Feb 2019 19:40:32 -0400 Subject: [PATCH] rasterizer_cache: mark reinterpreted surfaces and add ability to reload marked surfaces on next use. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 5 ++ .../renderer_opengl/gl_rasterizer_cache.h | 73 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 2d2bbd6acb..fe81ff2279 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -1007,6 +1007,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres if (surface) { if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { // Use the cached surface as-is + if (surface->MustReload()) + LoadSurface(surface); return surface; } else if (preserve_contents) { // If surface parameters changed and we care about keeping the previous data, recreate @@ -1014,6 +1016,9 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres Surface new_surface{RecreateSurface(surface, params)}; Unregister(surface); Register(new_surface); + if (new_surface->IsUploaded()) { + RegisterReinterpretSurface(new_surface); + } return new_surface; } else { // Delete the old surface before creating a new one to prevent collisions. diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index cc27fefb53..0b4d720e28 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -347,6 +347,10 @@ public: return cached_size_in_bytes; } + std::size_t GetMemorySize() const { + return memory_size; + } + void Flush() override { FlushGLBuffer(); } @@ -396,6 +400,26 @@ public: Tegra::Texture::SwizzleSource swizzle_z, Tegra::Texture::SwizzleSource swizzle_w); + void MarkReinterpreted() { + reinterpreted = true; + } + + bool IsReinterpreted() { + return reinterpreted; + } + + void MarkForReload(bool reload) { + must_reload = reload; + } + + bool MustReload() { + return must_reload; + } + + bool IsUploaded() { + return params.identity == SurfaceParams::SurfaceClass::Uploaded; + } + private: void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); @@ -409,6 +433,9 @@ private: GLenum gl_internal_format{}; std::size_t cached_size_in_bytes{}; std::array swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; + std::size_t memory_size; + bool reinterpreted = false; + bool must_reload = false; }; class RasterizerCacheOpenGL final : public RasterizerCache { @@ -469,6 +496,9 @@ private: OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; + bool run_texception_pass = false; + bool texception = false; + /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one /// using the new format. OGLBuffer copy_pbo; @@ -476,6 +506,49 @@ private: std::array last_color_buffers; std::array current_color_buffers; Surface last_depth_buffer; + + using SurfaceIntervalCache = boost::icl::interval_map; + using SurfaceInterval = typename IntervalCache::interval_type; + + static auto GetReinterpretInterval(const Surface& object) { + return SurfaceInterval::right_open(object->GetAddr() + 1, + object->GetAddr() + object->GetMemorySize() - 1); + } + + // Reinterpreted surfaces are very fragil as the game may keep rendering into them. + SurfaceIntervalCache reinterpreted_surfaces; + + void RegisterReinterpretSurface(Surface r_surface) { + auto interval = GetReinterpretInterval(r_surface); + reinterpreted_surfaces.insert({interval, r_surface}); + r_surface->MarkReinterpreted(); + run_texception_pass = true; + } + + Surface CollideOnReinterpretedSurface(VAddr addr) const { + const SurfaceInterval interval{addr}; + for (auto& pair : + boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) { + return pair.second; + } + return nullptr; + } + +protected: + void Register(const Surface& object) { + RasterizerCache::Register(object); + } + + /// Unregisters an object from the cache + void Unregister(const Surface& object) { + const auto& params = object->GetSurfaceParams(); + if (object->IsReinterpreted()) { + auto interval = GetReinterpretInterval(object); + reinterpreted_surfaces.erase(interval); + } + RasterizerCache::Unregister(object); + } + }; } // namespace OpenGL