From fcf2b2c78a3c45ddcda6594b2fd3df733ceb951c Mon Sep 17 00:00:00 2001 From: ameerj <52414509+ameerj@users.noreply.github.com> Date: Fri, 10 Sep 2021 01:10:59 -0400 Subject: [PATCH] gl_texture_cache: Simplify scaling We don't need to reconstruct new textures every time we ScaleUp/ScaleDown. We can scale up once, and revert to the original texture whenever scaling down. Fixes memory leaks due to glDeleteTextures being deferred for later handling on some drivers --- .../renderer_opengl/gl_texture_cache.cpp | 67 ++++++++++--------- .../renderer_opengl/gl_texture_cache.h | 3 +- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index edb8503cb..22fffb19b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -696,6 +696,7 @@ void Image::UploadMemory(const ImageBufferMap& map, const bool is_rescaled = True(flags & ImageFlagBits::Rescaled); if (is_rescaled) { ScaleDown(); + scale_backup.Release(); } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, map.buffer); glFlushMappedBufferRange(GL_PIXEL_UNPACK_BUFFER, map.offset, unswizzled_size_bytes); @@ -727,6 +728,7 @@ void Image::DownloadMemory(ImageBufferMap& map, const bool is_rescaled = True(flags & ImageFlagBits::Rescaled); if (is_rescaled) { ScaleDown(); + scale_backup.Release(); } glBindBuffer(GL_PIXEL_PACK_BUFFER, map.buffer); glPixelStorei(GL_PACK_ALIGNMENT, 1); @@ -881,17 +883,11 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b } } -bool Image::Scale(bool scale_src, bool scale_dst) { - if (!runtime->is_rescaling_on) { - return false; - } - if (gl_format == 0 && gl_type == 0) { - // compressed textures - return false; - } - if (info.type == ImageType::Linear) { - UNIMPLEMENTED(); - return false; +bool Image::Scale() { + if (scale_backup.handle) { + // This was a texture which was scaled previously, no need to repeat scaling + std::swap(texture, scale_backup); + return true; } const GLenum attachment = [this] { switch (GetFormatType(info.format)) { @@ -924,41 +920,36 @@ bool Image::Scale(bool scale_src, bool scale_dst) { const auto& resolution = runtime->resolution; const u32 up = resolution.up_scale; const u32 down = resolution.down_shift; + const auto scale = [&](u32 value) { return std::max((value * up) >> down, 1U); }; - const auto scale_up = [&](u32 value) { return std::max((value * up) >> down, 1U); }; - const u32 scaled_width = scale_up(info.size.width); - const u32 scaled_height = is_2d ? scale_up(info.size.height) : info.size.height; + const u32 scaled_width = scale(info.size.width); + const u32 scaled_height = is_2d ? scale(info.size.height) : info.size.height; const u32 original_width = info.size.width; const u32 original_height = info.size.height; - const u32 src_width = scale_src ? scaled_width : original_width; - const u32 src_height = scale_src ? scaled_height : original_height; - const u32 dst_width = scale_dst ? scaled_width : original_width; - const u32 dst_height = scale_dst ? scaled_height : original_height; - auto dst_info = info; - dst_info.size.width = dst_width; - dst_info.size.height = dst_height; - auto dst_texture = MakeImage(dst_info, gl_internal_format); + dst_info.size.width = scaled_width; + dst_info.size.height = scaled_height; + scale_backup = MakeImage(dst_info, gl_internal_format); const GLuint read_fbo = runtime->rescale_read_fbo.handle; const GLuint draw_fbo = runtime->rescale_draw_fbo.handle; for (s32 layer = 0; layer < info.resources.layers; ++layer) { for (s32 level = 0; level < info.resources.levels; ++level) { - const u32 src_level_width = std::max(1u, src_width >> level); - const u32 src_level_height = std::max(1u, src_height >> level); - const u32 dst_level_width = std::max(1u, dst_width >> level); - const u32 dst_level_height = std::max(1u, dst_height >> level); + const u32 src_level_width = std::max(1u, original_width >> level); + const u32 src_level_height = std::max(1u, original_height >> level); + const u32 dst_level_width = std::max(1u, scaled_width >> level); + const u32 dst_level_height = std::max(1u, scaled_height >> level); glNamedFramebufferTextureLayer(read_fbo, attachment, texture.handle, level, layer); - glNamedFramebufferTextureLayer(draw_fbo, attachment, dst_texture.handle, level, layer); + glNamedFramebufferTextureLayer(draw_fbo, attachment, scale_backup.handle, level, layer); glBlitNamedFramebuffer(read_fbo, draw_fbo, 0, 0, src_level_width, src_level_height, 0, 0, dst_level_width, dst_level_height, mask, filter); glNamedFramebufferTextureLayer(read_fbo, attachment, 0, level, layer); glNamedFramebufferTextureLayer(draw_fbo, attachment, 0, level, layer); } } - texture = std::move(dst_texture); + std::swap(texture, scale_backup); return true; } @@ -966,16 +957,32 @@ bool Image::ScaleUp() { if (True(flags & ImageFlagBits::Rescaled)) { return false; } + if (!runtime->is_rescaling_on) { + return false; + } + if (gl_format == 0 && gl_type == 0) { + // compressed textures + return false; + } + if (info.type == ImageType::Linear) { + UNIMPLEMENTED(); + return false; + } flags |= ImageFlagBits::Rescaled; - return Scale(false, true); + return Scale(); } bool Image::ScaleDown() { if (False(flags & ImageFlagBits::Rescaled)) { return false; } + if (!scale_backup.handle) { + LOG_ERROR(Render_OpenGL, "Downscaling an upscaled texture that didn't backup original"); + return false; + } flags &= ~ImageFlagBits::Rescaled; - return Scale(true, false); + std::swap(texture, scale_backup); + return true; } ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewInfo& info, diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 28c91b368..f4dcc6f9b 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -203,9 +203,10 @@ private: void CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t buffer_offset); - bool Scale(bool scale_src, bool scale_dst); + bool Scale(); OGLTexture texture; + OGLTexture scale_backup; OGLTextureView store_view; GLenum gl_internal_format = GL_NONE; GLenum gl_format = GL_NONE;