diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 00:27:40 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-31 00:28:00 -0400 |
| commit | b096fbea66468bc30c7608a7c1ef2a6bb15cafee (patch) | |
| tree | f9865d4f7d917439beb7d00d4794239237fe1b90 /src | |
| parent | 1b7c637c615d01ab23673b7297a3d6d6e8174f2a (diff) | |
video_core: free software blit buffers grown for huge surfaces
The blitter's scratch buffers kept the size of the largest surface it
ever handled (three 64 MiB buffers in Mario Kart World) for the whole
session. Free those over 16 MiB after the blit; the usual sizes stay.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/sw_blitter/blitter.cpp | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/src/video_core/engines/sw_blitter/blitter.cpp b/src/video_core/engines/sw_blitter/blitter.cpp index e08204f223..5f066254e9 100644 --- a/src/video_core/engines/sw_blitter/blitter.cpp +++ b/src/video_core/engines/sw_blitter/blitter.cpp @@ -6,6 +6,7 @@ #include <vector> #include "common/alignment.h" +#include "common/literals.h" #include "common/scratch_buffer.h" #include "video_core/engines/sw_blitter/blitter.h" #include "video_core/engines/sw_blitter/converter.h" @@ -24,6 +25,7 @@ using VideoCore::Surface::PixelFormatFromRenderTargetFormat; namespace Tegra::Engines::Blitter { using namespace Texture; +using namespace Common::Literals; namespace { @@ -174,6 +176,22 @@ struct SoftwareBlitEngine::BlitEngineImpl { Common::ScratchBuffer<u8> dst_buffer; Common::ScratchBuffer<f32> intermediate_src; Common::ScratchBuffer<f32> intermediate_dst; + + // Buffers grown for one huge surface (64-256 MiB) are freed after the blit rather than kept + // for the rest of the session; the usual sizes stay. + void ReleaseLargeBuffers() { + constexpr size_t LargeCapacity = 16_MiB; + for (auto* const buffer : {&tmp_buffer, &src_buffer, &dst_buffer}) { + if (buffer->capacity() > LargeCapacity) { + buffer->release(); + } + } + for (auto* const buffer : {&intermediate_src, &intermediate_dst}) { + if (buffer->capacity() * sizeof(f32) > LargeCapacity) { + buffer->release(); + } + } + } ConverterFactory converter_factory; }; @@ -268,20 +286,23 @@ bool SoftwareBlitEngine::Blit(Fermi2D::Surface& src, Fermi2D::Surface& dst, const size_t dst_size = get_surface_size(dst, dst_bytes_per_pixel); const SubSurface dst_part = CoveredRows(dst, dst_bytes_per_pixel, config.dst_x0, config.dst_y0, dst_extent_x, dst_extent_y, dst_size); - Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::SafeReadWrite> - tmp_buffer2(memory_manager, dst.Address() + dst_part.offset, dst_part.size, - &impl->tmp_buffer); - - if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { - SwizzleSubrect(tmp_buffer2, impl->dst_buffer, dst_bytes_per_pixel, dst.width, - dst_part.height, dst.depth, config.dst_x0, dst_part.origin_y, dst_extent_x, - dst_extent_y, dst.block_height, dst.block_depth, - dst_extent_x * dst_bytes_per_pixel); - } else { - ProcessPitchLinear<true>(impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y, - dst.pitch, config.dst_x0, dst_part.origin_y, - static_cast<size_t>(dst_bytes_per_pixel)); - } + { + Tegra::Memory::GpuGuestMemoryScoped<u8, Tegra::Memory::GuestMemoryFlags::SafeReadWrite> + tmp_buffer2(memory_manager, dst.Address() + dst_part.offset, dst_part.size, + &impl->tmp_buffer); + + if (dst.linear == Fermi2D::MemoryLayout::BlockLinear) { + SwizzleSubrect(tmp_buffer2, impl->dst_buffer, dst_bytes_per_pixel, dst.width, + dst_part.height, dst.depth, config.dst_x0, dst_part.origin_y, + dst_extent_x, dst_extent_y, dst.block_height, dst.block_depth, + dst_extent_x * dst_bytes_per_pixel); + } else { + ProcessPitchLinear<true>(impl->dst_buffer, tmp_buffer2, dst_extent_x, dst_extent_y, + dst.pitch, config.dst_x0, dst_part.origin_y, + static_cast<size_t>(dst_bytes_per_pixel)); + } + } // tmp_buffer2 writes the destination back here + impl->ReleaseLargeBuffers(); return true; } |
