mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-17 08:38:30 +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
|
// fallback for the drains that have NO object (the readback flush), and it is
|
||||||
// nulled at both of those events.
|
// nulled at both of those events.
|
||||||
const auto liveHostBase = [&resource, &bufferObject]() -> const Uint8* {
|
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();
|
if (bufferObject) return bufferObject->MappedData();
|
||||||
return resource->hostBytes;
|
return resource->hostBytes;
|
||||||
};
|
};
|
||||||
@@ -2942,6 +2955,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
resource->persistentMapped = false;
|
resource->persistentMapped = false;
|
||||||
resource->persistentPtr = nullptr;
|
resource->persistentPtr = nullptr;
|
||||||
resource->immutableStorage = false;
|
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.
|
// 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->storageInitialized = true;
|
||||||
resource->pendingRespecify = false;
|
resource->pendingRespecify = false;
|
||||||
BindBufferId(TempBufferTarget, reused);
|
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());
|
g_GLESFuncs.glBufferSubData(TempBufferTarget, 0, (GLsizeiptr)poolSize, liveHostBase());
|
||||||
if (MG_Util::PipeStats::Enabled()) {
|
if (MG_Util::PipeStats::Enabled()) {
|
||||||
MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer,
|
MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer,
|
||||||
@@ -3050,8 +3082,21 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
const Bool shadowHasContent =
|
const Bool shadowHasContent =
|
||||||
bufferObject ? bufferObject->HasDefinedContent() : (record->Desc.HasDefinedContent != 0);
|
bufferObject ? bufferObject->HasDefinedContent() : (record->Desc.HasDefinedContent != 0);
|
||||||
const void* initialData = shadowHasContent ? hostBase : nullptr;
|
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) {
|
if (resource->pendingRespecify || !resource->storageInitialized || resource->storageSize != size) {
|
||||||
|
requireWholeStoreCoverage();
|
||||||
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
||||||
} else if (!resource->pendingRanges.empty()) {
|
} else if (!resource->pendingRanges.empty()) {
|
||||||
// Same rule as Ops_H_Readback's, at the draw-time drain: with no frontend object
|
// 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) {
|
} else if (resource->syncedChangeSerial != serial) {
|
||||||
// Mutations this backend could not track (the table was unregistered between
|
// Mutations this backend could not track (the table was unregistered between
|
||||||
// contexts); re-upload everything.
|
// contexts); re-upload everything.
|
||||||
|
requireWholeStoreCoverage();
|
||||||
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
RespecifyStorageWith(*resource, size, usage, initialData, serial);
|
||||||
}
|
}
|
||||||
return resource;
|
return resource;
|
||||||
@@ -3113,6 +3159,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
|||||||
resource->persistentMapped = false;
|
resource->persistentMapped = false;
|
||||||
resource->persistentPtr = nullptr;
|
resource->persistentPtr = nullptr;
|
||||||
resource->immutableStorage = false;
|
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
|
// An immutable store nothing maps any more: a respecification of a buffer that
|
||||||
|
|||||||
Reference in New Issue
Block a user