aboutsummaryrefslogtreecommitdiff
path: root/src/video_core/engines
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-31 00:27:40 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-31 00:28:00 -0400
commitb096fbea66468bc30c7608a7c1ef2a6bb15cafee (patch)
treef9865d4f7d917439beb7d00d4794239237fe1b90 /src/video_core/engines
parent1b7c637c615d01ab23673b7297a3d6d6e8174f2a (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/video_core/engines')
-rw-r--r--src/video_core/engines/sw_blitter/blitter.cpp49
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;
}