GLRenderManager is documented as "emu thread records, render thread executes",
but GL has to record device object creation as init steps rather than just doing
it, and InitGPU() runs on the ExecLoader thread - GPU_GLES's constructor builds
DrawEngineGLES, whose InitDeviceObjects() reaches initSteps_ through
CreatePushBuffer and CreateInputLayout. The emu thread is still drawing the
loading screen into the same FastVec until the loader thread is joined, so two
concurrent push_uninitialized() can both reallocate, and one writes its step into
a freed buffer - losing a shader or buffer creation, or scribbling an owned
pointer into freed memory.
frameData_[].activePushBuffers is genuinely three-threaded too: inserted into by
whoever creates a push buffer, erased on the render thread via GLDeleter, and
walked on the render thread each frame.
A mutex each, uncontended in practice. Note this makes the existing access safe
rather than fixing the layering - Vulkan avoids the problem by creating objects
directly and deferring the rest to FinishInitOnMainThread, which GPU_GLES has
never had. Moving GL's device object creation there would be the better fix.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
Reported by Joseph on Discord.
Sometimes, things could align perfectly so allocations happend exactly
at the end of a pushbuffer. At the same time, we allow our vertex decoder to write an extra few
bytes if it needs to for speed. Unfortunately I missed this interaction,
resulting in some uncommon crashes that were especially common with
heavy-geometry things like modified GTA LCS with PS2 assets, for
example.
The problem was reported with Vulkan, but our OpenGL backend had the
same issue too.
It doesn't try to insert or fetch missing things itself, re-fetching is up to the caller.
This will be required for handling the many achievement icons.
Saving/loading the cache to a single file on disk is implemented but not
hooked up yet. It works without it, though of course will have to
re-fetch things on the next startup.
Accessed from the in-game dev menu just like the Vulkan frame profiler.
With this we can easily see that actually submitting the GL commands is often the bottleneck on old
devices like a Galaxy S3.
Turns out the VR work bloated it a bit, which can't be good.
Think it's fine to allocate these view matrices on the heap to get them
out of the way, there won't be that crazy many per frame usually.