mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[Fix] (MG_Remote, GLImpl): gate the transform-feedback reconciliation on the transport like every other new site, and give the unwritten writeback wait a named Fatal instead of an empty body
This commit is contained in:
@@ -1324,7 +1324,13 @@ namespace MobileGL::MG_Impl::GLImpl {
|
|||||||
// fence introduces. Under split it pays the reconciliation itself, which is the
|
// fence introduces. Under split it pays the reconciliation itself, which is the
|
||||||
// same cost the fence used to charge every caller - here charged only to the
|
// same cost the fence used to charge every caller - here charged only to the
|
||||||
// capture shapes that actually need reordering.
|
// capture shapes that actually need reordering.
|
||||||
buffer->SyncGpuWrites();
|
//
|
||||||
|
// TRANSPORT-GATED LIKE EVERY OTHER NEW SITE (D-J). Without the test this fires in
|
||||||
|
// a build-split lane running MOBILEGL_TRANSPORT=monolith on Magma - whose
|
||||||
|
// BeginXfbCaptureForDraw does mark the capture targets - where the fence at the
|
||||||
|
// caller still runs, so the readback it emits is pure new work on the monolith
|
||||||
|
// path and integration-gpu cannot see it.
|
||||||
|
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) buffer->SyncGpuWrites();
|
||||||
#endif
|
#endif
|
||||||
const Range1D range = bindingPoint.GetRange();
|
const Range1D range = bindingPoint.GetRange();
|
||||||
const Uint8* mapped = buffer->MappedData();
|
const Uint8* mapped = buffer->MappedData();
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
#include <MG_State/GLState/Core.h>
|
#include <MG_State/GLState/Core.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
|
#include <MG_State/GLState/TextureState/TextureObjectBuffer.h>
|
||||||
#include <MG_State/GLState/TextureState/TextureState.h>
|
#include <MG_State/GLState/TextureState/TextureState.h>
|
||||||
|
#include <MG_Util/Debug/Log.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace MobileGL::MG_Remote::Client {
|
namespace MobileGL::MG_Remote::Client {
|
||||||
|
|
||||||
@@ -167,16 +170,31 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AwaitBufferWriteback(BufferObject& buffer) {
|
void AwaitBufferWriteback(BufferObject& buffer) {
|
||||||
(void)buffer;
|
|
||||||
// THE WAIT IS THE BARRIER'S WAIT (R-3). The reply-slot id IS the record's seq, so
|
// THE WAIT IS THE BARRIER'S WAIT (R-3). The reply-slot id IS the record's seq, so
|
||||||
// "appliedSeq reached my readback" and "my answer is back" are one condition, and
|
// "appliedSeq reached my readback" and "my answer is back" are one condition, and
|
||||||
// ClientSession::EmitAndWait has already paid for it by the time the emitter returns.
|
// ClientSession::EmitAndWait is what pays for it. With no session - a build-split lane
|
||||||
// With no session - a build-split lane running monolith, and every unit case - the
|
// running monolith, and every unit case - the emission WAS the application,
|
||||||
// emission WAS the application, synchronously, so the writeback has already landed
|
// synchronously, so the writeback has already landed and there is nothing to wait for.
|
||||||
// and there is nothing to wait for. Spelling that as "return" rather than as a loop
|
// Spelling that as "return" rather than as a loop is deliberate: a loop here would be
|
||||||
// is deliberate: a loop here would be a hang in exactly that configuration, which is
|
// a hang in exactly that configuration, which is the configuration every gate lane
|
||||||
// the configuration every gate lane runs.
|
// runs.
|
||||||
if (ClientSession::Active() == nullptr) return;
|
if (ClientSession::Active() == nullptr) return;
|
||||||
|
|
||||||
|
// AND THE OTHER ARM IS A NAMED FATAL, NOT AN EMPTY BODY. A session exists, so the
|
||||||
|
// apply side is no longer synchronous, and if the flag is still set the shadow this
|
||||||
|
// caller is about to read is STALE - which is the whole failure the third state was
|
||||||
|
// introduced to stop. An empty body here would make that failure silent and would let
|
||||||
|
// s1/c1 land a session without noticing that nobody ever wrote the wait; a stub that
|
||||||
|
// aborts by name is the house shape for exactly this (EmitTables.cpp's
|
||||||
|
// UnmigratedVerbFatal), and it is what gives the hole a red spelling before the
|
||||||
|
// transport arrives.
|
||||||
|
if (!buffer.HasOutstandingGpuWrite()) return;
|
||||||
|
MGLOG_F("MGPipe: Fatal{UnimplementedWritebackWait} - a ClientSession is active and buffer %u "
|
||||||
|
"still has an outstanding GPU write after its readback was emitted. The wait is "
|
||||||
|
"ClientSession::EmitAndWait's (R-3: the reply slot id IS the record seq); P5 package "
|
||||||
|
"b1 landed the third state and s1/c1 own the wait itself.",
|
||||||
|
buffer.GetExternalIndex());
|
||||||
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MobileGL::MG_Remote::Client
|
} // namespace MobileGL::MG_Remote::Client
|
||||||
|
|||||||
@@ -41,6 +41,13 @@
|
|||||||
// ~0ull) and marks the capture targets, for the same reason: the wait exists only so that
|
// ~0ull) and marks the capture targets, for the same reason: the wait exists only so that
|
||||||
// a later MapBuffer sees real results, which is precisely what the flag is for.
|
// a later MapBuffer sees real results, which is precisely what the flag is for.
|
||||||
//
|
//
|
||||||
|
// WHAT NO ROW COVERS, WRITTEN DOWN SO THE NEXT READER DOES NOT HAVE TO ASK. The set is built
|
||||||
|
// from the APPLICATION's bindings, so it says nothing about a backend's own scratch buffers -
|
||||||
|
// Espryt's converted-vertex-stream and primitive-restart substitution buffers, Magma's UBO
|
||||||
|
// ring. None of those has a MarkGpuWritten today either, so the client set is no NARROWER than
|
||||||
|
// monolith's and this is not a regression; it is a standing hole in both, and it stays one
|
||||||
|
// until the phase that migrates the backend's own allocations.
|
||||||
|
//
|
||||||
// GATED ON THE TRANSPORT, like everything else in this package: on the monolith path the six
|
// GATED ON THE TRANSPORT, like everything else in this package: on the monolith path the six
|
||||||
// backend sites still run and a second marker would be new behaviour (D-J), and rows 4 and 5
|
// backend sites still run and a second marker would be new behaviour (D-J), and rows 4 and 5
|
||||||
// would remove a stall monolith is entitled to keep.
|
// would remove a stall monolith is entitled to keep.
|
||||||
|
|||||||
@@ -123,9 +123,22 @@ namespace MobileGL::MG_Remote::Client {
|
|||||||
// parses them today is that the negative control needs a spelling before the thing
|
// parses them today is that the negative control needs a spelling before the thing
|
||||||
// it controls exists. Falling back would make `MOBILEGL_IPC_ADOPT_TIER=0` look like
|
// it controls exists. Falling back would make `MOBILEGL_IPC_ADOPT_TIER=0` look like
|
||||||
// a working T0 run and silently produce pmap bytes it must not produce.
|
// a working T0 run and silently produce pmap bytes it must not produce.
|
||||||
MGLOG_F("MGPipe: MOBILEGL_IPC_ADOPT_TIER=%u names an adoption tier P11 implements and P5 "
|
// 0 and 1 are the two CONTRACT §5 promises - a real cross-process shared mapping and a
|
||||||
"does not; P5 runs at T2 (emulate) only.",
|
// server-side staging map - and they name P11. Anything else is not a tier at all, and
|
||||||
static_cast<unsigned>(tier));
|
// saying "P11 implements it" of a 7 would be a lie the operator then repeats. Both die
|
||||||
|
// here rather than at parse, which is late: the abort lands at the first
|
||||||
|
// map_persistent, so a mis-set run gets through EGL bring-up and a frame of setup
|
||||||
|
// first. Moving it to the parse means a knob-validity rule in ConfigLoader, which is
|
||||||
|
// c0's file; filed for the integrator rather than taken here.
|
||||||
|
if (tier <= 1) {
|
||||||
|
MGLOG_F("MGPipe: MOBILEGL_IPC_ADOPT_TIER=%u names adoption tier T%u, which P11 implements "
|
||||||
|
"and P5 does not; P5 runs at T2 (emulate) only.",
|
||||||
|
static_cast<unsigned>(tier), static_cast<unsigned>(tier));
|
||||||
|
} else {
|
||||||
|
MGLOG_F("MGPipe: MOBILEGL_IPC_ADOPT_TIER=%u is not an adoption tier; the only values are 0 "
|
||||||
|
"and 1 (P11) and 2 (emulate, the P5 default).",
|
||||||
|
static_cast<unsigned>(tier));
|
||||||
|
}
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user