diff --git a/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp b/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp index 24b5dc993d..fea31aea59 100644 --- a/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_framebuffer_cache.cpp @@ -27,11 +27,11 @@ bool FramebufferCacheKey::operator==(const FramebufferCacheKey& rhs) const { rhs.zeta); } -FramebufferCacheOpenGL::FramebufferCacheOpenGL() = default; +FramebufferCacheOpenGLImpl::FramebufferCacheOpenGLImpl() = default; -FramebufferCacheOpenGL::~FramebufferCacheOpenGL() = default; +FramebufferCacheOpenGLImpl::~FramebufferCacheOpenGLImpl() = default; -GLuint FramebufferCacheOpenGL::GetFramebuffer(const FramebufferCacheKey& key) { +GLuint FramebufferCacheOpenGLImpl::GetFramebuffer(const FramebufferCacheKey& key) { const auto [entry, is_cache_miss] = cache.try_emplace(key); auto& framebuffer{entry->second}; if (is_cache_miss) { @@ -40,7 +40,13 @@ GLuint FramebufferCacheOpenGL::GetFramebuffer(const FramebufferCacheKey& key) { return framebuffer.handle; } -OGLFramebuffer FramebufferCacheOpenGL::CreateFramebuffer(const FramebufferCacheKey& key) { +void FramebufferCacheOpenGLImpl::InvalidateTexture(GLuint texture) { + for (auto it = cache.begin(); it != cache.end();) { + it = TryTextureInvalidation(texture, it); + } +} + +OGLFramebuffer FramebufferCacheOpenGLImpl::CreateFramebuffer(const FramebufferCacheKey& key) { OGLFramebuffer framebuffer; framebuffer.Create(); @@ -73,4 +79,19 @@ OGLFramebuffer FramebufferCacheOpenGL::CreateFramebuffer(const FramebufferCacheK return framebuffer; } +FramebufferCacheOpenGLImpl::CacheType::iterator FramebufferCacheOpenGLImpl::TryTextureInvalidation( + GLuint texture, CacheType::iterator it) { + const auto& [key, framebuffer] = *it; + const std::size_t count = key.is_single_buffer ? 1 : static_cast(key.colors_count); + for (std::size_t i = 0; i < count; ++i) { + if (texture == key.colors[i]) { + return cache.erase(it); + } + } + if (texture == key.zeta) { + return cache.erase(it); + } + return ++it; +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_framebuffer_cache.h b/src/video_core/renderer_opengl/gl_framebuffer_cache.h index 192e3fd0a6..9318cdf298 100644 --- a/src/video_core/renderer_opengl/gl_framebuffer_cache.h +++ b/src/video_core/renderer_opengl/gl_framebuffer_cache.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -17,6 +18,9 @@ namespace OpenGL { +class FramebufferCacheOpenGLImpl; +using FramebufferCacheOpenGL = std::shared_ptr; + struct alignas(sizeof(u64)) FramebufferCacheKey { bool is_single_buffer = false; bool stencil_enable = false; @@ -51,18 +55,28 @@ struct hash { namespace OpenGL { -class FramebufferCacheOpenGL { +class FramebufferCacheOpenGLImpl { public: - FramebufferCacheOpenGL(); - ~FramebufferCacheOpenGL(); + FramebufferCacheOpenGLImpl(); + ~FramebufferCacheOpenGLImpl(); + /// Returns and caches a framebuffer with the passed arguments. GLuint GetFramebuffer(const FramebufferCacheKey& key); + /// Invalidates a texture inside the cache. + void InvalidateTexture(GLuint texture); + private: + using CacheType = std::unordered_map; + + /// Returns a new framebuffer from the passed arguments. OGLFramebuffer CreateFramebuffer(const FramebufferCacheKey& key); + /// Attempts to destroy the framebuffer cache entry in `it` and returns the next one. + CacheType::iterator TryTextureInvalidation(GLuint texture, CacheType::iterator it); + OpenGLState local_state; - std::unordered_map cache; + CacheType cache; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 44cd7af828..8cf3d2ef1d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -81,8 +81,10 @@ struct DrawParameters { }; RasterizerOpenGL::RasterizerOpenGL(Core::System& system, ScreenInfo& info) - : res_cache{*this}, shader_cache{*this, system}, global_cache{*this}, system{system}, - screen_info{info}, buffer_cache(*this, STREAM_BUFFER_SIZE) { + : framebuffer_cache{std::make_shared()}, + res_cache{*this, framebuffer_cache}, shader_cache{*this, system}, + global_cache{*this}, system{system}, screen_info{info}, + buffer_cache(*this, STREAM_BUFFER_SIZE) { // Create sampler objects for (std::size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); @@ -512,7 +514,7 @@ std::pair RasterizerOpenGL::ConfigureFramebuffers( depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil; } - current_state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(fbkey); + current_state.draw.draw_framebuffer = framebuffer_cache->GetFramebuffer(fbkey); SyncViewport(current_state); return current_depth_stencil_usage = {static_cast(depth_surface), fbkey.stencil_enable}; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 34ee5a3db4..c0f98a7ab7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -209,10 +209,10 @@ private: OpenGLState state; + FramebufferCacheOpenGL framebuffer_cache; RasterizerCacheOpenGL res_cache; ShaderCacheOpenGL shader_cache; GlobalRegionCacheOpenGL global_cache; - FramebufferCacheOpenGL framebuffer_cache; Core::System& system; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index aba6ce7310..3cbf343033 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -561,8 +561,9 @@ void RasterizerCacheOpenGL::CopySurface(const Surface& src_surface, const Surfac dst_surface->MarkAsModified(true, *this); } -CachedSurface::CachedSurface(const SurfaceParams& params) - : RasterizerCacheObject{params.host_ptr}, params{params}, +CachedSurface::CachedSurface(const SurfaceParams& params, FramebufferCacheOpenGL framebuffer_cache_) + : RasterizerCacheObject{params.host_ptr}, framebuffer_cache{std::move(framebuffer_cache_)}, + texture{framebuffer_cache}, discrepant_view{framebuffer_cache}, params{params}, gl_target{SurfaceTargetToGL(params.target)}, cached_size_in_bytes{params.size_in_bytes} { const auto optional_cpu_addr{ @@ -611,6 +612,8 @@ CachedSurface::CachedSurface(const SurfaceParams& params) OpenGL::LabelGLObject(GL_TEXTURE, texture.handle, params.gpu_addr, params.IdentityString()); } +CachedSurface::~CachedSurface() = default; + MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64)); void CachedSurface::LoadGLBuffer() { MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); @@ -852,8 +855,9 @@ void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x, } } -RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer) - : RasterizerCache{rasterizer} { +RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer, + FramebufferCacheOpenGL framebuffer_cache) + : RasterizerCache{rasterizer}, framebuffer_cache{std::move(framebuffer_cache)} { read_framebuffer.Create(); draw_framebuffer.Create(); copy_pbo.Create(); @@ -961,7 +965,7 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { Surface surface{TryGetReservedSurface(params)}; if (!surface) { // No reserved surface available, create a new one and reserve it - surface = std::make_shared(params); + surface = std::make_shared(params, framebuffer_cache); ReserveSurface(surface); } return surface; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index e8073579f7..f3177dced4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -18,6 +18,7 @@ #include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/rasterizer_cache.h" +#include "video_core/renderer_opengl/gl_framebuffer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_gen.h" #include "video_core/surface.h" @@ -350,7 +351,8 @@ class RasterizerOpenGL; class CachedSurface final : public RasterizerCacheObject { public: - explicit CachedSurface(const SurfaceParams& params); + explicit CachedSurface(const SurfaceParams& params, FramebufferCacheOpenGL framebuffer_cache_); + ~CachedSurface(); VAddr GetCpuAddr() const override { return cpu_addr; @@ -426,6 +428,7 @@ private: void EnsureTextureDiscrepantView(); + FramebufferCacheOpenGL framebuffer_cache; OGLTexture texture; OGLTexture discrepant_view; std::vector> gl_buffer; @@ -434,7 +437,7 @@ 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; + std::size_t memory_size{}; bool reinterpreted = false; bool must_reload = false; VAddr cpu_addr{}; @@ -442,7 +445,8 @@ private: class RasterizerCacheOpenGL final : public RasterizerCache { public: - explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer); + explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer, + FramebufferCacheOpenGL framebuffer_cache); /// Get a surface based on the texture configuration Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, @@ -499,6 +503,8 @@ private: /// destroyed when used with different surface parameters. std::unordered_map surface_reserve; + FramebufferCacheOpenGL framebuffer_cache; + OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index bfe666a73f..6e6a30f907 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -6,6 +6,7 @@ #include #include "common/common_types.h" #include "common/microprofile.h" +#include "video_core/renderer_opengl/gl_framebuffer_cache.h" #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_state.h" @@ -15,6 +16,16 @@ MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_R namespace OpenGL { +OGLTexture::OGLTexture(FramebufferCacheOpenGL framebuffer_cache) + : framebuffer_cache{std::move(framebuffer_cache)} {} + +OGLTexture::OGLTexture(OGLTexture&& o) noexcept + : handle{std::exchange(o.handle, 0)}, framebuffer_cache{std::move(o.framebuffer_cache)} {} + +OGLTexture::~OGLTexture() { + Release(); +} + void OGLTexture::Create(GLenum target) { if (handle != 0) return; @@ -28,6 +39,9 @@ void OGLTexture::Release() { return; MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); + if (framebuffer_cache) { + framebuffer_cache->InvalidateTexture(handle); + } glDeleteTextures(1, &handle); OpenGLState::GetCurState().UnbindTexture(handle).Apply(); handle = 0; diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index fbb93ee499..1c5b01b223 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include "common/common_types.h" @@ -11,15 +12,15 @@ namespace OpenGL { +class FramebufferCacheOpenGLImpl; +using FramebufferCacheOpenGL = std::shared_ptr; + class OGLTexture : private NonCopyable { public: - OGLTexture() = default; + explicit OGLTexture(FramebufferCacheOpenGL framebuffer_cache); + OGLTexture(OGLTexture&& o) noexcept; - OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {} - - ~OGLTexture() { - Release(); - } + ~OGLTexture(); OGLTexture& operator=(OGLTexture&& o) noexcept { Release(); @@ -34,6 +35,9 @@ public: void Release(); GLuint handle = 0; + +private: + FramebufferCacheOpenGL framebuffer_cache; }; class OGLSampler : private NonCopyable { diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 6cbf9d2cba..cd32f3523d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -28,7 +28,7 @@ namespace OpenGL { /// Structure used for storing information about the textures for the Switch screen struct TextureInfo { - OGLTexture resource; + OGLTexture resource{nullptr}; GLsizei width; GLsizei height; GLenum gl_format;