- MGP_NOTE_AGGREGATE(Aggregate) next to MGP_NOTE_MUTATION in MG_Pipe/PipeMutation.h, ((void)0)
in the pull build for the same reason and with the same shape. It answers a DIFFERENT
question from MGP_NOTE_MUTATION - "did any object of this class move since the tracker last
looked", not "did a backend move a frontend value inside its own verb" - which is why it is a
second macro rather than an overload.
- The counters are members of the owning MG_State container (VertexArrayState,
FramebufferState, TextureState x2, BufferState) and are reached through a push-only GLContext
facade, because the bump points sit on OBJECTS and an object has no back-pointer to the state
that owns it. That is the free-function form P2 brief D4 allows, and it costs a global load on
a path that has just written object state.
- A SIXTH aggregate, VertexAttribDefault on GLContext, which D4 does not list. Its bit
(NEW_VERTEX_ATTRIB_DEFAULTS) is specified there with a ContentHash over all 32
CurrentVertexAttributeValues, and hashing 768 bytes on every draw does not fit inside the T1
ceiling the same brief pins. The hash still decides whether to EMIT (D11's set-hash
suppressor); the generation decides whether to hash at all.
- 30 bump points: 3 VertexArrayObject config-version sites, 3 FramebufferObject object-version
sites (one of them inside MOBILEGL_DEFINE_FRAMEBUFFER_DEFAULT_SETTER, so the statement
carries its own line continuation), 5 texture content-version sites, 12 texture
params-version sites, SamplerObject::BumpVersion as the sampler choke point, 7 BufferObject
change-serial sites and the 3 glVertexAttrib* defaults.
- Every counter is deliberately COARSER than the state it guards: over-firing costs one extra
push, under-firing renders stale, and under-firing is the direction ARCHITECTURE.md 13.2
names as the dangerous one and the P1 verify comparator cannot see for object-class state.
- TrackerTest: each bump point moves ITS aggregate and no other, plus a null-context note.
- G1: the pull build is 0 added / 0 removed / 0 renamed and the four resized symbols are the
contract commit's own, unchanged by this commit.
- The verify lane aborted eight integration entries and two retrace cases with
Fatal{PipeVerifyDiffer, "GetSamplingResolutionGeneration@DrawArrays",
where=read}, always one line after "ResolveSamplerDescriptor: using fallback
texture for unbound sampler". The backends write into frontend objects during
their own verb - Magma synthesises a fallback texture for an unbound sampler
and gives it a shape, materialises a queued clear, overrides a unit's sampler
filter - and every one of those writes moves a counter MGP_FILL already
copied, so the pushed block stops equalling the live context for the rest of
the verb. That is a real divergence, not a harness artefact: the pull build
reads the moved value and the push build reads the boundary one.
- Takes the findings' preferred option, push on mutation, over the volatile-in-
verb class: it keeps the comparator's invariant ("the pushed block equals the
live context at every read") literally true, keeps push semantics equal to
pull, and is the shape P2's tracker needs. The fallback would have had to skip
compare-at-read for the field, which is the one comparator arm that is real in
P1 - it would have blinded the gate on the very field that found the bug.
- MG_Pipe/PipeMutation.h declares MGP_NOTE_MUTATION(Field), a no-op that
includes nothing in the pull build; MG_Impl/Pipe/PipeFill.cpp defines the
notice next to the filler it shares CopyField with. The notice refreshes one
field's value when a context is live, a verb has been filled, and the field is
in that verb class's may-read mask; it never touches the poison stamp, so a
stamp MOBILEGL_PIPE_POISON_OMIT withheld stays withheld and a field the verb
never filled stays Fatal{UnmigratedPipeInput} rather than being healed.
- The enumeration behind the three hook sites: of the ~40 backend->frontend
write sites, only the texture family reaches a pushed value. Every path
through them funnels into TextureState::BumpSamplingResolutionGeneration
(SamplerObject::BumpVersion for the sampler setters,
TextureObjectBase::BumpShapeVersion for AllocateStorage / SetInternalFormat /
TruncateMipmapLevels / SetSamples / SetFixedSampleLocations),
BumpTextureBindGeneration (a default texture becoming defined, delete-unbind,
a unit's sampler object changing) or NoteUnitTouched (which also moves the
touched-unit high-water mark), so the notice sits on the counters rather than
on each writer and covers the whole family including writers added later.
The buffer, program and VAO writes reach no pushed field: their objects are
read back through O-class live references, not copied values.