mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 00:28:31 +09:00
[Fix] (DirectGLES/Managers): under an active transport the server staged copy is the only base - liveHostBase no longer falls back to the client object (M-2); the pool-reuse and whole-store respecify readers go through RequireCoverage (M-3); a twin surviving DropAll has its freed hostBytes nulled (m-5)
This commit is contained in:
@@ -2926,6 +2926,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// fallback for the drains that have NO object (the readback flush), and it is
|
||||
// nulled at both of those events.
|
||||
const auto liveHostBase = [&resource, &bufferObject]() -> const Uint8* {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// M-2 / codex 3 / ID-52 item 3: under an ACTIVE TRANSPORT the server's staged
|
||||
// copy (resource->hostBytes, filled by MGL_SERVER_STAGED_ADOPT in Ops_H_SubData /
|
||||
// Ops_H_FlushRange) is the ONLY authoritative base. Preferring the frontend
|
||||
// object's MappedData() here - which under inproc is always non-null, same process
|
||||
// - meant every reduced-path drain read the CLIENT's shadow and NEVER the server's,
|
||||
// so a corrupt staged upload rendered the frontend's correct bytes and the R-2.5
|
||||
// 0xDD audit could not reach a draw. R-2 / table 3: honest inproc is inproc that
|
||||
// does not read the client object's memory. Under monolith nothing changes.
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
return resource->hostBytes;
|
||||
}
|
||||
#endif
|
||||
if (bufferObject) return bufferObject->MappedData();
|
||||
return resource->hostBytes;
|
||||
};
|
||||
@@ -2942,6 +2955,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
resource->persistentMapped = false;
|
||||
resource->persistentPtr = nullptr;
|
||||
resource->immutableStorage = false;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// m-5 / codex 5: OnBackendContextDestroyed ran MGL_SERVER_STAGED_DROP_ALL(), which
|
||||
// frees every server shadow but does NOT null the hostBytes that name them - so a
|
||||
// twin that SURVIVES a context loss (this is the block that repairs it) still
|
||||
// carries a base into the freed allocation. The two other drop sites pair the drop
|
||||
// with something that makes the base unreachable (Ops_H_Destroy retires the twin;
|
||||
// the map-persistent site nulls hostBytes on the next line); DropAll did neither.
|
||||
// Null it here, at the one place a surviving twin is re-armed, so no freed base
|
||||
// reaches glBufferData/glBufferSubData before the next content record refills it.
|
||||
resource->hostBytes = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// An immutable store nothing maps any more, retired here on the thread that can.
|
||||
@@ -2977,6 +3001,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
resource->storageInitialized = true;
|
||||
resource->pendingRespecify = false;
|
||||
BindBufferId(TempBufferTarget, reused);
|
||||
// M-3 / codex 4: this is a WHOLE-STORE upload from the base, and under split
|
||||
// the base is the server shadow (M-2), whose zero-filled bytes past the staged
|
||||
// coverage are not the application's - uploading them is the silent data loss
|
||||
// the M-6 ruling forbids. RequireCoverage is a no-op for the legacy arm's
|
||||
// MappedData() and for a non-copying store; under split it Fatals by name on a
|
||||
// sparse shadow rather than seeding the driver with zeroes.
|
||||
MGL_SERVER_STAGED_REQUIRE(*resource, liveHostBase(), 0, poolSize,
|
||||
"pool_reuse_whole_store");
|
||||
g_GLESFuncs.glBufferSubData(TempBufferTarget, 0, (GLsizeiptr)poolSize, liveHostBase());
|
||||
if (MG_Util::PipeStats::Enabled()) {
|
||||
MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer,
|
||||
@@ -3050,8 +3082,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const Bool shadowHasContent =
|
||||
bufferObject ? bufferObject->HasDefinedContent() : (record->Desc.HasDefinedContent != 0);
|
||||
const void* initialData = shadowHasContent ? hostBase : nullptr;
|
||||
// M-3 / codex 4: a RespecifyStorageWith(..., initialData != nullptr) is a WHOLE-STORE
|
||||
// [0, size) upload from the base, so it owes the same coverage the pending-range drain
|
||||
// below owes - the two respecify arms were the readers M-6's "never widened" rule did
|
||||
// not reach. No-op for the legacy arm's MappedData() and for a non-copying store; a
|
||||
// Fatal{StageSnapshotTooNarrow, "respecify_whole_store"} under split when the shadow's
|
||||
// coverage does not span the store, instead of uploading its zero-fill as content.
|
||||
const auto requireWholeStoreCoverage = [&]() {
|
||||
if (initialData != nullptr) {
|
||||
MGL_SERVER_STAGED_REQUIRE(*resource, static_cast<const Uint8*>(initialData), 0,
|
||||
size, "respecify_whole_store");
|
||||
}
|
||||
};
|
||||
|
||||
if (resource->pendingRespecify || !resource->storageInitialized || resource->storageSize != size) {
|
||||
requireWholeStoreCoverage();
|
||||
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
||||
} else if (!resource->pendingRanges.empty()) {
|
||||
// Same rule as Ops_H_Readback's, at the draw-time drain: with no frontend object
|
||||
@@ -3062,6 +3107,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
} else if (resource->syncedChangeSerial != serial) {
|
||||
// Mutations this backend could not track (the table was unregistered between
|
||||
// contexts); re-upload everything.
|
||||
requireWholeStoreCoverage();
|
||||
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
||||
}
|
||||
return resource;
|
||||
@@ -3113,6 +3159,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
resource->persistentMapped = false;
|
||||
resource->persistentPtr = nullptr;
|
||||
resource->immutableStorage = false;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// m-5 / codex 5: mirror the handle arm - DropAll freed the shadow this base named
|
||||
// on context loss, so a surviving twin repaired here must not carry it forward.
|
||||
resource->hostBytes = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
// An immutable store nothing maps any more: a respecification of a buffer that
|
||||
|
||||
Reference in New Issue
Block a user