System: Improve texture recycling when changing rewind/runahead settings
Fix suprious failures when changing rewind settings when low on VRAM.
This commit is contained in:
parent
8605722cdf
commit
a08acdb93a
|
@ -332,21 +332,32 @@ bool GPUBackend::AllocateMemorySaveStates(std::span<System::MemorySaveState> sta
|
|||
for (size_t i = 0; i < states.size(); i++)
|
||||
g_gpu_device->RecycleTexture(std::move(states[i].vram_texture));
|
||||
|
||||
// Maximize potential for texture reuse by flushing the current command buffer.
|
||||
g_gpu_device->WaitForGPUIdle();
|
||||
|
||||
for (size_t i = 0; i < states.size(); i++)
|
||||
{
|
||||
if (!backend->AllocateMemorySaveState(states[i], error))
|
||||
{
|
||||
// Free anything that was allocated.
|
||||
for (size_t j = 0; j <= i; i++)
|
||||
// Try flushing the pool.
|
||||
WARNING_LOG("Failed to allocate memory save state texture, trying flushing pool.");
|
||||
g_gpu_device->PurgeTexturePool();
|
||||
g_gpu_device->WaitForGPUIdle();
|
||||
if (!backend->AllocateMemorySaveState(states[i], error))
|
||||
{
|
||||
states[j].state_data.deallocate();
|
||||
states[j].vram_texture.reset();
|
||||
result = false;
|
||||
return;
|
||||
// Free anything that was allocated.
|
||||
for (size_t j = 0; j <= i; i++)
|
||||
{
|
||||
states[j].state_data.deallocate();
|
||||
states[j].vram_texture.reset();
|
||||
result = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
backend->RestoreDeviceContext();
|
||||
result = true;
|
||||
},
|
||||
true, false);
|
||||
|
|
|
@ -59,7 +59,7 @@ static void HotkeyModifyResolutionScale(s32 increment)
|
|||
|
||||
if (System::IsValid())
|
||||
{
|
||||
System::ClearMemorySaveStates(true);
|
||||
System::ClearMemorySaveStates(true, false);
|
||||
GPUThread::UpdateSettings(true, false);
|
||||
}
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ DEFINE_HOTKEY("TogglePGXP", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOO
|
|||
[](s32 pressed) {
|
||||
if (!pressed && System::IsValid())
|
||||
{
|
||||
System::ClearMemorySaveStates(true);
|
||||
System::ClearMemorySaveStates(true, true);
|
||||
|
||||
g_settings.gpu_pgxp_enable = !g_settings.gpu_pgxp_enable;
|
||||
GPUThread::UpdateSettings(true, false);
|
||||
|
@ -451,7 +451,7 @@ DEFINE_HOTKEY("TogglePGXPDepth", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
|||
if (!g_settings.gpu_pgxp_enable)
|
||||
return;
|
||||
|
||||
System::ClearMemorySaveStates(true);
|
||||
System::ClearMemorySaveStates(true, true);
|
||||
|
||||
g_settings.gpu_pgxp_depth_buffer = !g_settings.gpu_pgxp_depth_buffer;
|
||||
GPUThread::UpdateSettings(true, false);
|
||||
|
@ -471,7 +471,7 @@ DEFINE_HOTKEY("TogglePGXPCPU", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_
|
|||
if (!g_settings.gpu_pgxp_enable)
|
||||
return;
|
||||
|
||||
System::ClearMemorySaveStates(true);
|
||||
System::ClearMemorySaveStates(true, true);
|
||||
|
||||
// GPU thread is unchanged
|
||||
g_settings.gpu_pgxp_cpu = !g_settings.gpu_pgxp_cpu;
|
||||
|
|
|
@ -1167,7 +1167,7 @@ DiscRegion System::GetRegionForPsf(const char* path)
|
|||
|
||||
void System::RecreateGPU(GPURenderer renderer)
|
||||
{
|
||||
FreeMemoryStateTextures();
|
||||
FreeMemoryStateStorage(false);
|
||||
StopMediaCapture();
|
||||
|
||||
Error error;
|
||||
|
@ -1177,7 +1177,7 @@ void System::RecreateGPU(GPURenderer renderer)
|
|||
Panic("Failed to switch renderer.");
|
||||
}
|
||||
|
||||
ClearMemorySaveStates(true);
|
||||
ClearMemorySaveStates(true, false);
|
||||
}
|
||||
|
||||
void System::LoadSettings(bool display_osd_messages)
|
||||
|
@ -1954,7 +1954,7 @@ void System::DestroySystem()
|
|||
if (g_settings.inhibit_screensaver)
|
||||
PlatformMisc::ResumeScreensaver();
|
||||
|
||||
FreeMemoryStateStorage();
|
||||
FreeMemoryStateStorage(false);
|
||||
|
||||
Cheats::UnloadAll();
|
||||
PCDrv::Shutdown();
|
||||
|
@ -2495,13 +2495,13 @@ System::MemorySaveState& System::PopMemoryState()
|
|||
return s_state.memory_save_states[s_state.memory_save_state_front];
|
||||
}
|
||||
|
||||
bool System::AllocateMemoryStates(size_t state_count)
|
||||
bool System::AllocateMemoryStates(size_t state_count, bool recycle_old_textures)
|
||||
{
|
||||
DEV_LOG("Allocating {} memory save state slots", state_count);
|
||||
|
||||
if (state_count != s_state.memory_save_states.size())
|
||||
{
|
||||
FreeMemoryStateStorage();
|
||||
FreeMemoryStateStorage(recycle_old_textures);
|
||||
s_state.memory_save_states.resize(state_count);
|
||||
}
|
||||
|
||||
|
@ -2522,7 +2522,7 @@ bool System::AllocateMemoryStates(size_t state_count)
|
|||
ERROR_LOG("Failed to allocate {} memory save states: {}", s_state.memory_save_states.size(),
|
||||
error.GetDescription());
|
||||
ERROR_LOG("Disabling runahead/rewind.");
|
||||
FreeMemoryStateStorage();
|
||||
FreeMemoryStateStorage(false);
|
||||
s_state.runahead_frames = 0;
|
||||
s_state.memory_save_state_front = 0;
|
||||
s_state.memory_save_state_count = 0;
|
||||
|
@ -2536,48 +2536,16 @@ bool System::AllocateMemoryStates(size_t state_count)
|
|||
return true;
|
||||
}
|
||||
|
||||
void System::ClearMemorySaveStates(bool reallocate_resources)
|
||||
void System::ClearMemorySaveStates(bool reallocate_resources, bool recycle_textures)
|
||||
{
|
||||
s_state.memory_save_state_front = 0;
|
||||
s_state.memory_save_state_count = 0;
|
||||
|
||||
if (reallocate_resources && !s_state.memory_save_states.empty())
|
||||
AllocateMemoryStates(s_state.memory_save_states.size());
|
||||
AllocateMemoryStates(s_state.memory_save_states.size(), recycle_textures);
|
||||
}
|
||||
|
||||
void System::FreeMemoryStateTextures()
|
||||
{
|
||||
// TODO: use non-copyable function, that way we don't need to store raw pointers
|
||||
std::vector<GPUTexture*> textures;
|
||||
bool gpu_thread_synced = false;
|
||||
|
||||
for (MemorySaveState& mss : s_state.memory_save_states)
|
||||
{
|
||||
if ((mss.vram_texture || !mss.gpu_state_data.empty()) && !gpu_thread_synced)
|
||||
{
|
||||
gpu_thread_synced = true;
|
||||
GPUThread::SyncGPUThread(true);
|
||||
}
|
||||
|
||||
if (mss.vram_texture)
|
||||
{
|
||||
if (textures.empty())
|
||||
textures.reserve(s_state.memory_save_states.size());
|
||||
|
||||
textures.push_back(mss.vram_texture.release());
|
||||
}
|
||||
}
|
||||
|
||||
if (!textures.empty())
|
||||
{
|
||||
GPUThread::RunOnThread([textures = std::move(textures)]() mutable {
|
||||
for (GPUTexture* texture : textures)
|
||||
g_gpu_device->RecycleTexture(std::unique_ptr<GPUTexture>(texture));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void System::FreeMemoryStateStorage()
|
||||
void System::FreeMemoryStateStorage(bool recycle_textures)
|
||||
{
|
||||
// TODO: use non-copyable function, that way we don't need to store raw pointers
|
||||
std::vector<GPUTexture*> textures;
|
||||
|
@ -2607,9 +2575,14 @@ void System::FreeMemoryStateStorage()
|
|||
|
||||
if (!textures.empty())
|
||||
{
|
||||
GPUThread::RunOnThread([textures = std::move(textures)]() mutable {
|
||||
GPUThread::RunOnThread([textures = std::move(textures), recycle_textures]() mutable {
|
||||
for (GPUTexture* texture : textures)
|
||||
g_gpu_device->RecycleTexture(std::unique_ptr<GPUTexture>(texture));
|
||||
{
|
||||
if (recycle_textures)
|
||||
g_gpu_device->RecycleTexture(std::unique_ptr<GPUTexture>(texture));
|
||||
else
|
||||
delete texture;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2919,7 +2892,7 @@ bool System::LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bo
|
|||
if (g_settings.HasAnyPerGameMemoryCards())
|
||||
UpdatePerGameMemoryCards();
|
||||
|
||||
ClearMemorySaveStates(false);
|
||||
ClearMemorySaveStates(false, false);
|
||||
|
||||
// Updating game/loading settings can turn on hardcore mode. Catch this.
|
||||
Achievements::DisableHardcoreMode();
|
||||
|
@ -4005,7 +3978,7 @@ bool System::InsertMedia(const char* path)
|
|||
if (IsGPUDumpPath(path)) [[unlikely]]
|
||||
return ChangeGPUDump(path);
|
||||
|
||||
ClearMemorySaveStates(true);
|
||||
ClearMemorySaveStates(true, true);
|
||||
|
||||
Error error;
|
||||
std::unique_ptr<CDImage> image = CDImage::Open(path, g_settings.cdrom_load_image_patches, &error);
|
||||
|
@ -4044,7 +4017,7 @@ bool System::InsertMedia(const char* path)
|
|||
|
||||
void System::RemoveMedia()
|
||||
{
|
||||
ClearMemorySaveStates(true);
|
||||
ClearMemorySaveStates(true, true);
|
||||
CDROM::RemoveMedia(false);
|
||||
}
|
||||
|
||||
|
@ -4254,7 +4227,7 @@ bool System::SwitchMediaSubImage(u32 index)
|
|||
if (!CDROM::HasMedia())
|
||||
return false;
|
||||
|
||||
ClearMemorySaveStates(true);
|
||||
ClearMemorySaveStates(true, true);
|
||||
|
||||
std::unique_ptr<CDImage> image = CDROM::RemoveMedia(true);
|
||||
Assert(image);
|
||||
|
@ -4308,7 +4281,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
{
|
||||
if (IsValid())
|
||||
{
|
||||
ClearMemorySaveStates(false);
|
||||
ClearMemorySaveStates(false, false);
|
||||
|
||||
if (g_settings.cpu_overclock_active != old_settings.cpu_overclock_active ||
|
||||
(g_settings.cpu_overclock_active &&
|
||||
|
@ -4448,7 +4421,8 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
GPUThread::UpdateSettings(true, false);
|
||||
|
||||
// NOTE: Must come after the GPU thread settings update, otherwise it allocs the wrong size textures.
|
||||
ClearMemorySaveStates(true);
|
||||
const bool use_existing_textures = (g_settings.gpu_resolution_scale == old_settings.gpu_resolution_scale);
|
||||
ClearMemorySaveStates(true, use_existing_textures);
|
||||
|
||||
if (IsPaused())
|
||||
GPUThread::PresentCurrentFrame();
|
||||
|
@ -4884,7 +4858,8 @@ void System::CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u64
|
|||
|
||||
void System::UpdateMemorySaveStateSettings()
|
||||
{
|
||||
FreeMemoryStateStorage();
|
||||
const bool any_memory_states_active = (g_settings.IsRunaheadEnabled() || g_settings.rewind_enable);
|
||||
FreeMemoryStateStorage(any_memory_states_active);
|
||||
|
||||
if (IsReplayingGPUDump()) [[unlikely]]
|
||||
{
|
||||
|
@ -4926,7 +4901,7 @@ void System::UpdateMemorySaveStateSettings()
|
|||
|
||||
// allocate storage for memory save states
|
||||
if (num_slots > 0)
|
||||
AllocateMemoryStates(num_slots);
|
||||
AllocateMemoryStates(num_slots, true);
|
||||
|
||||
// reenter execution loop, don't want to try to save a state now if runahead was turned off
|
||||
InterruptExecution();
|
||||
|
@ -5024,7 +4999,7 @@ bool System::DoRunahead()
|
|||
s_state.runahead_replay_frames = s_state.memory_save_state_count;
|
||||
|
||||
// and throw away all the states, forcing us to catch up below
|
||||
ClearMemorySaveStates(false);
|
||||
ClearMemorySaveStates(false, false);
|
||||
|
||||
// run the frames with no audio
|
||||
SPU::SetAudioOutputMuted(true);
|
||||
|
|
|
@ -418,7 +418,7 @@ void RequestDisplaySize(float scale = 0.0f);
|
|||
// Memory Save States (Rewind and Runahead)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CalculateRewindMemoryUsage(u32 num_saves, u32 resolution_scale, u64* ram_usage, u64* vram_usage);
|
||||
void ClearMemorySaveStates(bool reallocate_resources);
|
||||
void ClearMemorySaveStates(bool reallocate_resources, bool recycle_textures);
|
||||
void SetRunaheadReplayFlag();
|
||||
|
||||
/// Shared socket multiplexer, used by PINE/GDB/etc.
|
||||
|
|
|
@ -26,9 +26,8 @@ struct MemorySaveState
|
|||
MemorySaveState& AllocateMemoryState();
|
||||
MemorySaveState& GetFirstMemoryState();
|
||||
MemorySaveState& PopMemoryState();
|
||||
bool AllocateMemoryStates(size_t state_count);
|
||||
void FreeMemoryStateTextures();
|
||||
void FreeMemoryStateStorage();
|
||||
bool AllocateMemoryStates(size_t state_count, bool recycle_old_textures);
|
||||
void FreeMemoryStateStorage(bool recycle_texture);
|
||||
void LoadMemoryState(MemorySaveState& mss, bool update_display);
|
||||
void SaveMemoryState(MemorySaveState& mss);
|
||||
|
||||
|
|
Loading…
Reference in New Issue