mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Docs] (MG_Backend, MG_Backend/DirectGLES, MG_Impl/Pipe, MG_IntegrationTest/Scenarios, MG_State/GLState, MG_Test/Buffer, MG_Test/Util, MG_Util/Metrics): correct comments about retired switches and moved code
This commit is contained in:
@@ -23,9 +23,9 @@ namespace MobileGL::MG_Backend {
|
||||
//
|
||||
// IT MUST RUN FIRST, BEFORE ANYTHING ELSE IN DestroyImpl. ARCHITECTURE.md §14's order is
|
||||
// publish -> the server drains and acks -> stop the apply thread (Kill, then join) -> close
|
||||
// the transport -> the client drains the compile pool -> MobileGL::Destroy() -> release the
|
||||
// sync/query handles; DestroyImpl IS MobileGL::Destroy, so everything before that arrow has
|
||||
// to happen at its top. Two consequences are load-bearing rather than tidy:
|
||||
// the transport -> the client drains the compile pool -> MobileGL::Destroy(); DestroyImpl IS
|
||||
// MobileGL::Destroy, so everything before that last arrow has to happen at its top. Two
|
||||
// consequences are load-bearing rather than tidy:
|
||||
//
|
||||
// * the apply thread is JOINED before PipeStats::Shutdown() dumps, so nothing is writing
|
||||
// a counter while the final line is produced;
|
||||
@@ -33,11 +33,8 @@ namespace MobileGL::MG_Backend {
|
||||
// BackendObject - which is NOT that global (table 3) - is destroyed on the thread that
|
||||
// owns the context, by ServerLoop::Stop, rather than on the app thread.
|
||||
//
|
||||
// The sync/query registries stay where they are, drained at MobileGL/Init.cpp:62 and :67
|
||||
// BEFORE pActiveBackendObject.reset(). ARCHITECTURE.md §14 originally put them after
|
||||
// MobileGL::Destroy(); the two are only reconcilable if a split sync handle is
|
||||
// client-minted and needs no backend call, which is P10's. CONTRACT-P5 4 flags this as a
|
||||
// KNOWN OPEN ITEM and asks v1 to record which way it went: P5 keeps today's order.
|
||||
// The sync/query registries stay where they are: DestroyImpl drains them with
|
||||
// DestroyAllSyncObjects and DestroyAllQueryObjects before pActiveBackendObject.reset().
|
||||
void ShutdownSplitRoles();
|
||||
|
||||
// F1 (P7 wave 2). Init()'s SPLIT ARM, run BEFORE MG_State::Init() rather than after it.
|
||||
|
||||
@@ -1987,13 +1987,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
|
||||
// ---- P4a's handle arm (D-B3). Three server-owned serials that REPLACE, on their
|
||||
// own arm, the six frontend-version memos above; the legacy members stay beside
|
||||
// them under MOBILEGL_PIPE_LEGACY_MEMOS because ARCHITECTURE.md §9.6 keeps the
|
||||
// pre-handle arm compiled through P3a/P4a, and because clearing the family's bit
|
||||
// has to run the pre-handle arm rather than a half-migrated one.
|
||||
//
|
||||
// Inside the guard, so the PULL build's BackendTextureObject is byte-for-byte the
|
||||
// pre-P4a object and G1's admitted-resize set stays empty (D-P).
|
||||
// own arm, the six frontend-version memos above; the legacy members still sit beside
|
||||
// them, but the MOBILEGL_PIPE_LEGACY_MEMOS switch and the pre-handle arm it compiled
|
||||
// are retired (ARCHITECTURE.md §9.6): clearing the family's bit is a named startup refusal.
|
||||
//
|
||||
// 0 is never a real serial - the applier's counters start at 1 and only ever
|
||||
// advance, including across a make-current (PipeApply.cpp's three-way argument) -
|
||||
@@ -3042,7 +3038,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint32 m_syncedLinkVersion = ~0u;
|
||||
Uint32 m_syncedImageUnitVersion = ~0u;
|
||||
// P4a's replacement for the two above on the handle arm; see GetSyncedShaderCsoSerial.
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedShaderCsoSerial = 0;
|
||||
Uint64 m_syncedBindingsSerial = 0;
|
||||
// Image units addressed by the program's FORMAT-LESS image uniforms, and the digest
|
||||
@@ -3218,15 +3213,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
SamplerParameters m_cacheSamplerParameters;
|
||||
Uint16 m_syncedSamplerVersion = 0;
|
||||
// P4a (D-B3): the SamplerCso record's Serial at the last completed sync. It replaces
|
||||
// m_syncedSamplerVersion, which stays beside it because the pre-handle arm compiles
|
||||
// under MOBILEGL_PIPE_LEGACY_MEMOS through P3a/P4a (ARCHITECTURE.md §9.6).
|
||||
// m_syncedSamplerVersion, which is still declared beside it but no longer read: the
|
||||
// pre-handle arm and its MOBILEGL_PIPE_LEGACY_MEMOS switch are retired (ARCHITECTURE.md §9.6).
|
||||
//
|
||||
// The two are not interchangeable and that is the point: the frontend version is per
|
||||
// OBJECT, while the serial is per CONTENT-ADDRESSED CSO, and two frontend samplers
|
||||
// with identical parameters share one CSO and therefore one serial - so under the
|
||||
// handle arm the second of them costs no driver call at all.
|
||||
//
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedSamplerSerial = 0;
|
||||
};
|
||||
|
||||
@@ -3362,8 +3355,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// on an ALREADY-ATTACHED renderbuffer moved nothing the framebuffer bit could see.
|
||||
// The client now emits resource_respecify straight from those three mutators, the
|
||||
// applier bumps this serial, and one compare here sees it.
|
||||
//
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedResourceSerial = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
// WHY IT HAS TO MOVE SIDES. `BufferObject::SyncGpuWrites` (BufferObject.cpp:369) runs
|
||||
// synchronously, on the application's thread, the moment the application calls glMapBuffer or
|
||||
// glGetBufferSubData. It has to answer "did the GPU write this buffer since I last read it?"
|
||||
// - and today all six producers of that answer are BACKEND-side (DirectGLES.cpp:570, :618,
|
||||
// :2603, UniformManager.cpp:1075, :1231, VulkanRenderer::BeginXfbCaptureForDraw), i.e. on the server's side
|
||||
// of a split. Asking the server is a round trip the design forbids in steady state, so the
|
||||
// - and the six backend sites that rows 0-3 below mirror are all on the server's side of a split
|
||||
// (DirectGLES.cpp's SyncBufferBindingPointsByRecord, SyncAtomicCounterBuffers and
|
||||
// MarkWritableImageBufferTexturesGpuWritten; UniformManager.cpp's ResolveStorageTexelBufferDescriptor
|
||||
// and ResolveStorageBufferDescriptor; WireDraw.inc's BeginWireXfbCaptureForDraw). Asking the server
|
||||
// is a round trip the design forbids in steady state, so the
|
||||
// client must build the set itself, from state it already owns: the SSBO and atomic-counter
|
||||
// binding points, the image units whose Access is not GL_READ_ONLY, and the transform-feedback
|
||||
// capture targets.
|
||||
@@ -73,22 +75,22 @@ namespace MobileGL::MG_Record {
|
||||
// otherwise invisible, because an over-approximating set fails SILENTLY in the direction
|
||||
// that matters.
|
||||
enum class GpuWriteProducer : Uint8 {
|
||||
// DirectGLES.cpp:570 (MarkShaderStorageBuffersGpuWritten) and
|
||||
// UniformManager.cpp:1231 (ResolveStorageBufferDescriptor): every SSBO binding point,
|
||||
// DirectGLES.cpp's SyncBufferBindingPointsByRecord (shader-storage class) and
|
||||
// UniformManager.cpp's ResolveStorageBufferDescriptor: every SSBO binding point,
|
||||
// unconditional, once the points are bound and the draw or dispatch is going out.
|
||||
ShaderStorageBinding = 0,
|
||||
// DirectGLES.cpp:618 (SyncAtomicCounterBuffers): every bound atomic counter. The
|
||||
// DirectGLES.cpp's SyncAtomicCounterBuffers: every bound atomic counter. The
|
||||
// point of a counter is that the shader increments it and every conformance case
|
||||
// reads the increment back with glMapBufferRange or glGetBufferSubData.
|
||||
AtomicCounterBinding,
|
||||
// DirectGLES.cpp:2603 (MarkWritableImageBufferTexturesGpuWritten) and
|
||||
// UniformManager.cpp:1075 (ResolveStorageTexelBufferDescriptor): a buffer texture on
|
||||
// DirectGLES.cpp's MarkWritableImageBufferTexturesGpuWritten and
|
||||
// UniformManager.cpp's ResolveStorageTexelBufferDescriptor: a buffer texture on
|
||||
// an image unit, ONLY when Access != GL_READ_ONLY. Marking a read-only binding would
|
||||
// make the next map wait on - and then re-read - a dispatch that could not have
|
||||
// changed a byte of it.
|
||||
WritableImageBufferTexture,
|
||||
// VulkanRenderer.cpp (BeginXfbCaptureForDraw): the capture targets, because
|
||||
// "the capture is a GPU write like any shader's".
|
||||
// WireDraw.inc's BeginWireXfbCaptureForDraw, which VulkanRenderer::BeginXfbCaptureForDraw
|
||||
// calls: the capture targets, because the capture is a GPU write like any shader's.
|
||||
TransformFeedbackCapture,
|
||||
// P5, new: glReadPixels into a bound GL_PIXEL_PACK_BUFFER.
|
||||
ReadPixelsPackBuffer,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
// changes what the three above assert:
|
||||
//
|
||||
// * AnAdoptionCostsExactlyOneMapPersistentRoundtrip counts the acquisition.
|
||||
// ARCHITECTURE.md §12 prices the adopted store at one round trip per STORAGE
|
||||
// An adopted store costs one map_persistent round trip per STORAGE
|
||||
// DEFINITION; `map-persistent-roundtrips` counts every map_persistent
|
||||
// emission, mint or decline (D-B2), so one definition plus a frame of draws
|
||||
// must publish exactly one. It reads the library's summary line, so it needs
|
||||
|
||||
@@ -101,8 +101,8 @@ namespace MGITest {
|
||||
// path because the fix was not yet in this branch's history and the workload reproduced
|
||||
// as a hard SIGSEGV in the vertex fetch; that detour is what ID-9 supersedes.
|
||||
//
|
||||
// The COUNT is unaffected by the change: two storage definitions either way, which is
|
||||
// what ARCHITECTURE.md §12 prices.
|
||||
// The COUNT is unaffected by the change: two storage definitions either way, and an
|
||||
// adopted store costs one map_persistent round trip per storage definition.
|
||||
constexpr int kDefinitionsInTheWindow = 2;
|
||||
constexpr int kDrawsPerDefinition = 3;
|
||||
constexpr int kInset = 2;
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
// The assertion is deliberately on the WHOLE grown range, so a partial write names the byte the
|
||||
// stale extent stopped at.
|
||||
//
|
||||
// P3a ADDS THE COST OF THAT REGROWTH (gate G10). ARCHITECTURE.md §12 prices a persistently mapped
|
||||
// store at "one round trip per STORAGE DEFINITION, not one per store" - and, emphatically, not one
|
||||
// P3a ADDS THE COST OF THAT REGROWTH (gate G10). An adopted store costs one map_persistent round trip
|
||||
// per STORAGE DEFINITION (BufferObject::TryAdoptLargeStorage runs on each one) - and, emphatically, not one
|
||||
// per draw. `map-persistent-roundtrips` (`mpr=` in the summary line) counts every map_persistent
|
||||
// EMISSION, mint or decline (D-B2), so the claim is directly countable: N definitions of an
|
||||
// adopted store must publish exactly N, whatever the workload does between them. A regression that
|
||||
|
||||
@@ -37,11 +37,12 @@
|
||||
// NEGATIVE CONTROL and means "push nothing" - not "one unlimited block" - so
|
||||
// PersistentCoherentMapScenario must go red under it.
|
||||
//
|
||||
// PHASE 1 IS CONSERVATIVE, AND SAYS SO. The whole mapped span is pushed, by block, at every
|
||||
// validate point; no dirty bits, no memcmp. Phase 2 (MOBILEGL_IPC_SHADOW_SHM, P6+) makes it
|
||||
// precise, and ARCHITECTURE.md §12 grants it the right to be pulled forward if Phase 1 is
|
||||
// unacceptable on the Create/Flywheel fixtures - the one place in the plan where a
|
||||
// measurement may reorder phases.
|
||||
// Only changed blocks ship. At each validate point a member pushes just the blocks written
|
||||
// since its last push. A map the mprotect write-fault tracker holds (MOBILEGL_PIPE_PERSISTENT_MPROTECT;
|
||||
// Linux and Android) has its pages protected read-only after each push, and a write fault marks
|
||||
// its page dirty; any other map compares each block's hash with the one the last push saw
|
||||
// (MOBILEGL_IPC_PERSISTENT_HASH_SUPPRESS; 0 restores the whole-span push). ARCHITECTURE.md §12
|
||||
// describes this dirty-page tracking and hash suppression.
|
||||
//
|
||||
// ORDERING IS THE CORRECTNESS PROPERTY, NOT THE GRANULARITY. In monolith the push is a memcpy
|
||||
// on the same thread as the draw that follows it, so the bytes the application wrote before
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace {
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
|
||||
// Row 0 - DirectGLES.cpp:570 / UniformManager.cpp:1231.
|
||||
// Row 0 - SyncBufferBindingPointsByRecord (DirectGLES.cpp) / ResolveStorageBufferDescriptor (UniformManager.cpp).
|
||||
TEST_F(SplitBufferSet, Row0EverySsboBindingPointIsMarkedByADraw) {
|
||||
auto ssbo = MakeBuffer(11u, 256);
|
||||
MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::ShaderStorage, 0).Bind(ssbo);
|
||||
@@ -153,7 +153,7 @@ TEST_F(SplitBufferSet, Row0EverySsboBindingPointIsMarkedByADraw) {
|
||||
"behind the shadow glMapBuffer and glGetBufferSubData read";
|
||||
}
|
||||
|
||||
// Row 1 - DirectGLES.cpp:618. The point of a counter is that the shader increments it.
|
||||
// Row 1 - SyncAtomicCounterBuffers (DirectGLES.cpp). The point of a counter is that the shader increments it.
|
||||
TEST_F(SplitBufferSet, Row1EveryBoundAtomicCounterIsMarkedByADraw) {
|
||||
auto counter = MakeBuffer(12u, 64);
|
||||
MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::AtomicCounter, 0).Bind(counter);
|
||||
@@ -246,9 +246,9 @@ TEST_F(SplitBufferSet, Row2TheSweepIsBoundedByTheImageUnitHighWaterMark) {
|
||||
binding = MG_State::GLState::ImageTextureBinding{};
|
||||
}
|
||||
|
||||
// Row 3 - VulkanRenderer::BeginXfbCaptureForDraw() in VulkanRenderer.cpp. With no capture
|
||||
// active there is nothing to mark, and that gate is the half worth pinning: a mark taken with no
|
||||
// active capture would mark whatever the binding points happened to hold from a previous one.
|
||||
// Row 3 - BeginWireXfbCaptureForDraw() in WireDraw.inc, which VulkanRenderer::BeginXfbCaptureForDraw()
|
||||
// calls. With no capture active there is nothing to mark, and that gate is the half worth pinning: a mark
|
||||
// taken with no active capture would mark whatever the binding points happened to hold from a previous one.
|
||||
TEST_F(SplitBufferSet, Row3TransformFeedbackTargetsAreOnlyMarkedWhileACaptureIsActive) {
|
||||
auto target = MakeBuffer(15u, 256);
|
||||
MG_State::pGLContext->GetBufferBindingPoint(BufferTarget::TransformFeedback, 0).Bind(target);
|
||||
|
||||
@@ -385,8 +385,9 @@ namespace {
|
||||
EXPECT_EQ(line.find("wrec/f=47.00"), String::npos) << line;
|
||||
}
|
||||
|
||||
// THE STAGED-BLOB DISTRIBUTION, which is the optional deliverable MEASUREMENTS.md §6.3 says
|
||||
// has never existed. It shares the draw-payload histogram's edges - bucket 0 is "0 bytes",
|
||||
// THE STAGED-BLOB DISTRIBUTION, the optional deliverable: before this histogram the per-blob
|
||||
// byte distribution after chunking had never been measured. It shares the draw-payload
|
||||
// histogram's edges - bucket 0 is "0 bytes",
|
||||
// bucket n>0 is [2^(n-1), 2^n) - so the two are read the same way, and it is a COUNT per
|
||||
// bucket rather than a byte sum: the shape is the deliverable and the bytes have their own
|
||||
// counter in `seg`.
|
||||
|
||||
@@ -777,8 +777,8 @@ namespace MobileGL::MG_Util::PipeStats {
|
||||
// P6 gate 8's two per-frame numbers have their JSON homes where every other ByteClass and
|
||||
// CallClass already does - the `bytes` and `calls` blocks above, under their long names
|
||||
// (stage-segment-bytes, wire-records) - so there is nothing to add for them here. The
|
||||
// staged-blob DISTRIBUTION does need one: it is the deliverable MEASUREMENTS.md §6.3 says
|
||||
// has never been measured, and like the draw-payload histogram above it is a run-total
|
||||
// staged-blob DISTRIBUTION does need one: it is the per-blob distribution after chunking,
|
||||
// first measured through this dump, and like the draw-payload histogram above it is a run-total
|
||||
// distribution, which is exactly what Tracy cannot plot and this dump exists to carry.
|
||||
// Bucket 0 is "0 bytes" and bucket n>0 is [2^(n-1), 2^n): the same edges PayloadBucketOf
|
||||
// gives both histograms, so the two are read the same way.
|
||||
|
||||
@@ -421,9 +421,9 @@ namespace MobileGL::MG_Util::PipeStats {
|
||||
// populations: the one above is the command payload of a draw (plan section 4.5.7, sizing
|
||||
// SEG_CMD), this one is how big the blobs a workload stages into SEG_STAGE actually are.
|
||||
//
|
||||
// IT EXISTS FOR CONTRACT-P6.md §9 item 8, and MEASUREMENTS.md §6.3 says in as many words why:
|
||||
// IT EXISTS FOR CONTRACT-P6.md §9 item 8, for this reason:
|
||||
// the chunking work landed (1e7c372e buffer walks, 9469d48e texture slabs) and every
|
||||
// `maxrec` number the file carries predates it, so "the per-blob byte distribution after
|
||||
// `maxrec` number then on record predated it, so "the per-blob byte distribution after
|
||||
// chunking" had no measurement at all. A per-frame AVERAGE cannot answer it either: an
|
||||
// average of 8 MiB is the same number whether one blob of 8 MiB was staged or two of 4 MiB
|
||||
// that the budget should have cut to one. The bucket edges are PayloadBucketOf's, shared so
|
||||
|
||||
Reference in New Issue
Block a user