mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #5710 from BreadFish64/bonk_textures
gl_rasterizer_cache: Remove all fully invalid surfaces from the cache
This commit is contained in:
		
						commit
						e6c479f497
					
				
					 2 changed files with 81 additions and 36 deletions
				
			
		|  | @ -311,13 +311,21 @@ static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl | |||
| }; | ||||
| 
 | ||||
| // Allocate an uninitialized texture of appropriate size and format for the surface
 | ||||
| static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, | ||||
|                                    u32 height) { | ||||
|     OpenGLState cur_state = OpenGLState::GetCurState(); | ||||
| OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width, | ||||
|                                                          u32 height) { | ||||
|     auto recycled_tex = host_texture_recycler.find({format_tuple, width, height}); | ||||
|     if (recycled_tex != host_texture_recycler.end()) { | ||||
|         OGLTexture texture = std::move(recycled_tex->second); | ||||
|         host_texture_recycler.erase(recycled_tex); | ||||
|         return texture; | ||||
|     } | ||||
|     OGLTexture texture; | ||||
|     texture.Create(); | ||||
| 
 | ||||
|     OpenGLState cur_state = OpenGLState::GetCurState(); | ||||
|     // Keep track of previous texture bindings
 | ||||
|     GLuint old_tex = cur_state.texture_units[0].texture_2d; | ||||
|     cur_state.texture_units[0].texture_2d = texture; | ||||
|     cur_state.texture_units[0].texture_2d = texture.handle; | ||||
|     cur_state.Apply(); | ||||
|     glActiveTexture(GL_TEXTURE0); | ||||
| 
 | ||||
|  | @ -332,6 +340,8 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup | |||
|     // Restore previous texture bindings
 | ||||
|     cur_state.texture_units[0].texture_2d = old_tex; | ||||
|     cur_state.Apply(); | ||||
| 
 | ||||
|     return texture; | ||||
| } | ||||
| 
 | ||||
| static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple, u32 width) { | ||||
|  | @ -494,6 +504,17 @@ static bool FillSurface(const Surface& surface, const u8* fill_data, | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| CachedSurface::~CachedSurface() { | ||||
|     if (texture.handle) { | ||||
|         auto tag = is_custom ? HostTextureTag{GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                               custom_tex_info.width, custom_tex_info.height} | ||||
|                              : HostTextureTag{GetFormatTuple(pixel_format), GetScaledWidth(), | ||||
|                                               GetScaledHeight()}; | ||||
| 
 | ||||
|         owner.host_texture_recycler.emplace(tag, std::move(texture)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool CachedSurface::CanFill(const SurfaceParams& dest_surface, | ||||
|                             SurfaceInterval fill_interval) const { | ||||
|     if (type == SurfaceType::Fill && IsRegionValid(fill_interval) && | ||||
|  | @ -812,12 +833,11 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_ | |||
|         x0 = 0; | ||||
|         y0 = 0; | ||||
| 
 | ||||
|         unscaled_tex.Create(); | ||||
|         if (is_custom) { | ||||
|             AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                    custom_tex_info.width, custom_tex_info.height); | ||||
|             unscaled_tex = owner.AllocateSurfaceTexture( | ||||
|                 GetFormatTuple(PixelFormat::RGBA8), custom_tex_info.width, custom_tex_info.height); | ||||
|         } else { | ||||
|             AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); | ||||
|             unscaled_tex = owner.AllocateSurfaceTexture(tuple, rect.GetWidth(), rect.GetHeight()); | ||||
|         } | ||||
|         target_tex = unscaled_tex.handle; | ||||
|     } | ||||
|  | @ -832,8 +852,8 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_ | |||
|     ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); | ||||
|     if (is_custom) { | ||||
|         if (res_scale == 1) { | ||||
|             AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                    custom_tex_info.width, custom_tex_info.height); | ||||
|             texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8), | ||||
|                                                    custom_tex_info.width, custom_tex_info.height); | ||||
|             cur_state.texture_units[0].texture_2d = texture.handle; | ||||
|             cur_state.Apply(); | ||||
|         } | ||||
|  | @ -910,11 +930,9 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint | |||
|         scaled_rect.right *= res_scale; | ||||
|         scaled_rect.bottom *= res_scale; | ||||
| 
 | ||||
|         OGLTexture unscaled_tex; | ||||
|         unscaled_tex.Create(); | ||||
| 
 | ||||
|         Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; | ||||
|         AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); | ||||
|         OGLTexture unscaled_tex = | ||||
|             owner.AllocateSurfaceTexture(tuple, rect.GetWidth(), rect.GetHeight()); | ||||
|         BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type, | ||||
|                      read_fb_handle, draw_fb_handle); | ||||
| 
 | ||||
|  | @ -1734,15 +1752,12 @@ bool RasterizerCacheOpenGL::ValidateByReinterpretation(const Surface& surface, | |||
|             if (!texture_filterer->IsNull() && reinterpret_surface->res_scale == 1 && | ||||
|                 surface->res_scale == resolution_scale_factor) { | ||||
|                 // The destination surface is either a framebuffer, or a filtered texture.
 | ||||
|                 OGLTexture tmp_tex; | ||||
|                 tmp_tex.Create(); | ||||
|                 // Create an intermediate surface to convert to before blitting to the
 | ||||
|                 // destination.
 | ||||
|                 Common::Rectangle<u32> tmp_rect{0, dest_rect.GetHeight() / resolution_scale_factor, | ||||
|                                                 dest_rect.GetWidth() / resolution_scale_factor, 0}; | ||||
|                 AllocateSurfaceTexture(tmp_tex.handle, | ||||
|                                        GetFormatTuple(reinterpreter->first.dst_format), | ||||
|                                        tmp_rect.right, tmp_rect.top); | ||||
|                 OGLTexture tmp_tex = AllocateSurfaceTexture( | ||||
|                     GetFormatTuple(reinterpreter->first.dst_format), tmp_rect.right, tmp_rect.top); | ||||
|                 reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect, | ||||
|                                                    read_framebuffer.handle, tmp_tex.handle, | ||||
|                                                    tmp_rect, draw_framebuffer.handle); | ||||
|  | @ -1857,9 +1872,9 @@ void RasterizerCacheOpenGL::InvalidateRegion(PAddr addr, u32 size, const Surface | |||
|             cached_surface->invalid_regions.insert(interval); | ||||
|             cached_surface->InvalidateAllWatcher(); | ||||
| 
 | ||||
|             // Remove only "empty" fill surfaces to avoid destroying and recreating OGL textures
 | ||||
|             if (cached_surface->type == SurfaceType::Fill && | ||||
|                 cached_surface->IsSurfaceFullyInvalid()) { | ||||
|             // If the surface has no salvageable data it should be removed from the cache to avoid
 | ||||
|             // clogging the data structure
 | ||||
|             if (cached_surface->IsSurfaceFullyInvalid()) { | ||||
|                 remove_surfaces.emplace(cached_surface); | ||||
|             } | ||||
|         } | ||||
|  | @ -1892,12 +1907,11 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) { | |||
|     Surface surface = std::make_shared<CachedSurface>(*this); | ||||
|     static_cast<SurfaceParams&>(*surface) = params; | ||||
| 
 | ||||
|     surface->texture.Create(); | ||||
| 
 | ||||
|     surface->gl_buffer.resize(0); | ||||
|     surface->invalid_regions.insert(surface->GetInterval()); | ||||
|     AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format), | ||||
|                            surface->GetScaledWidth(), surface->GetScaledHeight()); | ||||
| 
 | ||||
|     surface->texture = | ||||
|         AllocateSurfaceTexture(GetFormatTuple(surface->pixel_format), surface->GetScaledWidth(), | ||||
|                                surface->GetScaledHeight()); | ||||
| 
 | ||||
|     return surface; | ||||
| } | ||||
|  |  | |||
|  | @ -36,6 +36,27 @@ class RasterizerCacheOpenGL; | |||
| class TextureFilterer; | ||||
| class FormatReinterpreterOpenGL; | ||||
| 
 | ||||
| struct FormatTuple { | ||||
|     GLint internal_format; | ||||
|     GLenum format; | ||||
|     GLenum type; | ||||
| }; | ||||
| 
 | ||||
| constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; | ||||
| 
 | ||||
| const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format); | ||||
| 
 | ||||
| struct HostTextureTag { | ||||
|     FormatTuple format_tuple; | ||||
|     u32 width; | ||||
|     u32 height; | ||||
|     bool operator==(const HostTextureTag& rhs) const noexcept { | ||||
|         return std::tie(format_tuple.format, format_tuple.internal_format, width, height) == | ||||
|                std::tie(rhs.format_tuple.format, rhs.format_tuple.internal_format, rhs.width, | ||||
|                         rhs.height); | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
| struct TextureCubeConfig { | ||||
|     PAddr px; | ||||
|     PAddr nx; | ||||
|  | @ -59,6 +80,18 @@ struct TextureCubeConfig { | |||
| } // namespace OpenGL
 | ||||
| 
 | ||||
| namespace std { | ||||
| template <> | ||||
| struct hash<OpenGL::HostTextureTag> { | ||||
|     std::size_t operator()(const OpenGL::HostTextureTag& tag) const noexcept { | ||||
|         std::size_t hash = 0; | ||||
|         boost::hash_combine(hash, tag.format_tuple.format); | ||||
|         boost::hash_combine(hash, tag.format_tuple.internal_format); | ||||
|         boost::hash_combine(hash, tag.width); | ||||
|         boost::hash_combine(hash, tag.height); | ||||
|         return hash; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| template <> | ||||
| struct hash<OpenGL::TextureCubeConfig> { | ||||
|     std::size_t operator()(const OpenGL::TextureCubeConfig& config) const noexcept { | ||||
|  | @ -139,6 +172,7 @@ private: | |||
| 
 | ||||
| struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface> { | ||||
|     CachedSurface(RasterizerCacheOpenGL& owner) : owner{owner} {} | ||||
|     ~CachedSurface(); | ||||
| 
 | ||||
|     bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const; | ||||
|     bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const; | ||||
|  | @ -326,17 +360,14 @@ private: | |||
|     std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache; | ||||
| 
 | ||||
| public: | ||||
|     OGLTexture AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width, u32 height); | ||||
| 
 | ||||
|     // Textures from destroyed surfaces are stored here to be recyled to reduce allocation overhead
 | ||||
|     // in the driver
 | ||||
|     std::unordered_multimap<HostTextureTag, OGLTexture> host_texture_recycler; | ||||
| 
 | ||||
|     std::unique_ptr<TextureFilterer> texture_filterer; | ||||
|     std::unique_ptr<FormatReinterpreterOpenGL> format_reinterpreter; | ||||
| }; | ||||
| 
 | ||||
| struct FormatTuple { | ||||
|     GLint internal_format; | ||||
|     GLenum format; | ||||
|     GLenum type; | ||||
| }; | ||||
| 
 | ||||
| constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}; | ||||
| 
 | ||||
| const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format); | ||||
| } // namespace OpenGL
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue