mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 20:28:32 +09:00
[Refactor] (Espryt): answer a readback through the reverse channel and bump the mutation epoch after it, never before
This commit is contained in:
@@ -497,7 +497,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
for (SizeT i = 0; i < bindingPointCnt; ++i) {
|
||||
const auto& obj =
|
||||
MGB_CTX->GetBufferBindingPoint(BufferTarget::ShaderStorage, i).GetBoundObject();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a (D-D): announced on the reverse channel on the handle arm, poked into
|
||||
// the object on the legacy one. MarkBufferGpuWritten is the one place that
|
||||
// decides, so the three announcement sites stay one line each.
|
||||
MarkBufferGpuWritten(obj);
|
||||
#else
|
||||
if (obj) obj->MarkGpuWritten();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,7 +548,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// conformance case reads the result back with glMapBufferRange or
|
||||
// glGetBufferSubData - which serve the frontend's CPU shadow until the buffer is
|
||||
// flagged (BufferObject::SyncGpuWrites), exactly as for a storage buffer.
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
MarkBufferGpuWritten(obj);
|
||||
#else
|
||||
obj->MarkGpuWritten();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2009,7 +2020,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
auto* textureBuffer =
|
||||
static_cast<MG_State::GLState::TextureObjectBuffer*>(imageBinding.Texture.get());
|
||||
const auto& bufferObject = textureBuffer->GetBufferBindingSlot().GetBoundObject();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
BufferImpl::MarkBufferGpuWritten(bufferObject);
|
||||
#else
|
||||
if (bufferObject) bufferObject->MarkGpuWritten();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2002,6 +2002,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// no longer reaches into the frontend's address space, it ANSWERS. In monolith
|
||||
// the client's implementation is one call away, so SyncGpuWrites' caller still
|
||||
// sees the reconciled shadow on return, exactly as before.
|
||||
//
|
||||
// THE ORDER FROM HERE IS A CORRECTNESS RULE, NOT A PREFERENCE
|
||||
// (ARCHITECTURE.md 8.2: "写回的 epoch bump 必须在任何后续读该 handle 的命令之前被
|
||||
// server 应用;反向通道需要与正向通道相同的有序保证"):
|
||||
// 1. writeback - the client's shadow takes the bytes,
|
||||
// 2. unmap - the read mapping goes away,
|
||||
// 3. serial stamp- syncedChangeSerial catches up with the record, so the next
|
||||
// draw does not re-upload the readback over itself,
|
||||
// 4. epoch bump - in Ops_H_ReadbackTracked, i.e. strictly AFTER 1-3, so a
|
||||
// draw-clean memo re-probed by the bump can never observe a
|
||||
// half-reconciled resource. The bump must NEVER move earlier.
|
||||
if (MG_Pipe::gMGPipeCallbacks.OnBufferWriteback != nullptr) {
|
||||
MG_Pipe::gMGPipeCallbacks.OnBufferWriteback(
|
||||
res, record.Offset,
|
||||
@@ -2230,6 +2241,33 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return MG_Pipe::MGPipeSlots().FindByLifetimeId(MG_Pipe::MGPipeKind::Buffer,
|
||||
bufferObject->GetLifetimeId());
|
||||
}
|
||||
|
||||
void MarkBufferGpuWritten(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject) {
|
||||
if (!bufferObject) return;
|
||||
if (!ResourceSubsystemEnabled()) {
|
||||
bufferObject->MarkGpuWritten();
|
||||
return;
|
||||
}
|
||||
const MG_Pipe::MGPipeHandle res = HandleOfBuffer(bufferObject.get());
|
||||
if (MG_Pipe::MGPipeHandleIsNull(res) || MG_Pipe::gMGPipeCallbacks.OnGpuWritten == nullptr) {
|
||||
// Deliberately NOT a fall-back to MarkGpuWritten: on this arm the resource
|
||||
// family is switched over, and quietly reaching into the frontend object again
|
||||
// would hide a missing handle or a missing reverse channel behind a picture
|
||||
// that still looks right - which is what the subsystem A/B exists to expose.
|
||||
MGLOG_E_ONCE("MGPipe: no reverse channel for the GPU-write announcement of buffer %u "
|
||||
"(handle %s, OnGpuWritten %s)",
|
||||
bufferObject->GetExternalIndex(),
|
||||
MG_Pipe::MGPipeHandleIsNull(res) ? "missing" : "present",
|
||||
MG_Pipe::gMGPipeCallbacks.OnGpuWritten == nullptr ? "unset" : "set");
|
||||
return;
|
||||
}
|
||||
// WHOLE RESOURCE, stated rather than implied: the extent is spelled as one range of
|
||||
// kMGPipeWholeBuffer rather than as "zero ranges", because a zero count is the
|
||||
// shape a fully NARROWED announcement will legitimately have once P8/P9 build the
|
||||
// client's conservative set, and the two must not be the same record.
|
||||
const MG_Pipe::MGPRange whole{0, MG_Pipe::kMGPipeWholeBuffer};
|
||||
MG_Pipe::gMGPipeCallbacks.OnGpuWritten(res, 1, &whole);
|
||||
}
|
||||
#endif
|
||||
|
||||
// See the declaration: re-mints of a live resource's driver id. Written only on
|
||||
|
||||
@@ -720,6 +720,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Bool IsBufferDrawCleanByHandle(MG_Pipe::MGPipeHandle res, const GLESBufferResource* resource);
|
||||
GLESBufferResource* EnsureBufferResourceForHandle(
|
||||
const SharedPtr<MG_State::GLState::BufferObject>& bufferObject, MG_Pipe::MGPipeHandle res);
|
||||
|
||||
// P3a (D-D): "the GPU wrote through this resource", announced on the reverse channel
|
||||
// instead of poked into the frontend object. ARCHITECTURE.md calls OnGpuWritten a
|
||||
// NARROWING channel - the client builds its pending set conservatively at each
|
||||
// draw/dispatch emission point and this callback only ever takes entries out of it -
|
||||
// so in P3a, where the client's conservative set is exactly what the three
|
||||
// MarkGpuWritten sites marked, the announced set is the whole resource and the
|
||||
// observable behaviour is identical. P8/P9 narrow it; the channel is what they need.
|
||||
//
|
||||
// The legacy arm keeps calling BufferObject::MarkGpuWritten directly, and the pull
|
||||
// build never sees this function at all (G1).
|
||||
void MarkBufferGpuWritten(const SharedPtr<MG_State::GLState::BufferObject>& bufferObject);
|
||||
#endif
|
||||
|
||||
// Registered as the frontend's BufferBackendOps at backend init and on
|
||||
|
||||
Reference in New Issue
Block a user