[Fix] (MG_State, DirectGLES): read a shader-written storage buffer back before mapping it

Buffer contents live in a CPU shadow that every read - MapBuffer, MapBufferRange,
GetBufferSubData, CopyBufferSubData - resolves against, and backend transfer ops only
ever push the shadow outwards. Two paths already knew the GPU can write a buffer on
its own and mirrored the result back by hand (ReadPixels into a pixel-pack buffer,
the transform feedback capture at EndTransformFeedback); a shader storage buffer
written by a draw or a dispatch had no such path at all, so the map handed the
application the bytes from before the dispatch.

Nothing exercised it until now because GL 3.3 has no compute stage. Every
KHR-GL40.texture_gather case ends by dispatching a compute shader that writes its
sampled texel into an SSBO and comparing the mapped result, and all 71 read back the
zero-filled shadow.

Adds the missing direction as a backend op: BufferObject::MarkGpuWritten flags a
buffer the GPU may have moved ahead of the shadow, SyncGpuWrites pulls it back at
every read point, and DirectGLES implements the readback with a plain read map of the
ES buffer. The flag is raised where the storage-buffer points are bound for the
upcoming draw or dispatch, which is the last moment the set of exposed buffers is
known, and cleared by the readback - so a buffer nothing writes costs one bool test
per map. Backends that cannot read their storage back leave the op null and keep
today's behaviour; a GPU-resident (coherent persistent) buffer needs nothing, since
its reads already resolve against the memory the shader wrote.

Drops the texture_gather failures from 71/75 to 25/75 with no crashes left.
This commit is contained in:
BZLZHH
2026-08-04 09:40:53 -04:00
parent 41e45f7d48
commit 9bf23d7ffd
5 changed files with 85 additions and 0 deletions
@@ -878,6 +878,7 @@ namespace MobileGL::MG_Impl::GLImpl {
return;
}
bufferObject->SyncGpuWrites();
bufferObject->DownloadSubData(data, static_cast<SizeT>(offset), static_cast<SizeT>(size));
}