mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
The software rasterizer has a recovery path for running out of code space: SetupDraw returns false, the caller resets the cache and asks again. It has never been able to run. ReserveMemory only had a pxAssert, which is compiled out of a release build, so it always handed back a pointer. GetDefaultFunction has no other way to fail, so SetupDraw could not return false, so ResetCodeCache never ran. What happens instead is that the bump pointer walks off the end of the reserve, and since the software renderer sits last in the code arena, that is the end of the arena. It would not have worked if it had run, either. Clear emptied the codegen map and rewound the pointer but left the active map holding pointers into memory about to be handed out again, so the next lookup would have jumped into whatever replaced it. So: ReserveMemory reports full, Clear drops the active map along with the codegen map, and a null is deliberately not cached on the way out. That last one matters more than it looks. The active map is consulted before anything else, so an entry cached during the failure would have survived the reset that was supposed to fix it and gone on answering null for that selector for the rest of the run. Nothing here is iOS specific. It reads the same on every platform, we are just the ones with a reason to have been looking.
42 lines
965 B
C++
42 lines
965 B
C++
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
|
// SPDX-License-Identifier: GPL-3.0+
|
|
|
|
#include "GS/Renderers/Common/GSFunctionMap.h"
|
|
#include "Memory.h"
|
|
|
|
namespace GSCodeReserve
|
|
{
|
|
static u8* s_memory_base;
|
|
static u8* s_memory_end;
|
|
static u8* s_memory_ptr;
|
|
}
|
|
|
|
void GSCodeReserve::ResetMemory()
|
|
{
|
|
s_memory_base = SysMemory::GetSWRec();
|
|
s_memory_end = SysMemory::GetSWRecEnd();
|
|
s_memory_ptr = s_memory_base;
|
|
}
|
|
|
|
size_t GSCodeReserve::GetMemoryUsed()
|
|
{
|
|
return s_memory_ptr - s_memory_base;
|
|
}
|
|
|
|
u8* GSCodeReserve::ReserveMemory(size_t size)
|
|
{
|
|
// Null means full, and the caller resets the cache and asks again. This
|
|
// used to be an assert, so a release build walked off the end of the
|
|
// reserve instead, which is the end of the whole code arena.
|
|
if ((s_memory_ptr + size) > s_memory_end)
|
|
return nullptr;
|
|
|
|
return s_memory_ptr;
|
|
}
|
|
|
|
void GSCodeReserve::CommitMemory(size_t size)
|
|
{
|
|
pxAssert((s_memory_ptr + size) <= s_memory_end);
|
|
s_memory_ptr += size;
|
|
}
|