[Feat] (Pipe): push pixel-pack, patch and vertex-attribute-default state as their own calls, the last one behind the set-hash suppressor

- set_pixel_pack_state on NEW_PIXEL_PACK, set_patch_state on NEW_PATCH_STATE,
  set_vertex_attrib_defaults on NEW_VERTEX_ATTRIB_DEFAULTS, each gated on its own runtime
  subsystem bit so the bitmask stays a per-subsystem A/B.
- MG_Impl/Pipe/SetHashSuppressor.h: seven slots, one per kVarTail set_*, with
  SetVertexAttribDefaults the one P2 wires. 0 is reserved for "never emitted" and a computed 0
  is remapped to 1, so the first emission always goes out. The other six are the carrier for
  the ~175 lines of backend debounce that move in P3b/P4b; landing the mechanism now means the
  shape is pinned by a test rather than by a plan.
- The var-tail carries only the attributes that differ from the tracker's mirror, underneath
  the set-hash suppression of the whole resolved set - the two suppressors answer different
  questions and both are cheap.

Two rows of Coverage.def's emitted list CANNOT yet retire their pull, and each says why in the
code rather than being silently absent:

- GetPixelStoreParameters is BOTH halves of the pixel store and set_pixel_pack_state
  deliberately carries only PACK, so the unpack half has no carrier at all. The field keeps
  being pulled and the verify comparator keeps proving it.
- GetCurrentVertexAttribute's three views are not bit-identical - GLContext CONVERTS between
  them - while MGPipeApplySetVertexAttribDefaults memcpys one Data[4] into all three and
  ignores MGPAttribValue::ValueClass, which the wire type carries precisely so it does not
  have to. Until that applier reads ValueClass the carrier cannot reproduce the frontend
  value. The call is still emitted, so the wire shape, the payload bytes and the suppressor
  are all real; the residual fill runs after emission, so the mirror ends up correct either
  way.

Both are contract-side defects in files this package does not own; they are reported to the
integrator with the exact fix rather than worked around here.
This commit is contained in:
2026-09-07 23:18:09 -04:00
parent aa64c91052
commit dcfa5ad311
3 changed files with 208 additions and 1 deletions
+10
View File
@@ -311,6 +311,7 @@ namespace MobileGL::MG_Pipe {
m_pack = PixelStoreParameters{};
m_patch = PatchTrio{};
m_staged = RenderStateParameters{};
m_stagedAttribs = AttribDefaults{};
m_context = nullptr;
m_lastDirty = 0;
m_primed = false;
@@ -352,6 +353,14 @@ namespace MobileGL::MG_Pipe {
RenderStateParameters& Staged() { return m_staged; }
const RenderStateParameters& Staged() const { return m_staged; }
// The same mirror for the 32 glVertexAttrib* defaults: set_vertex_attrib_defaults
// names only the attributes that differ from it, which is the var-tail's own
// suppressor underneath D11's set-hash one.
using AttribDefaults = Array<MG_State::GLState::CurrentVertexAttributeValue,
MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>;
AttribDefaults& StagedAttribDefaults() { return m_stagedAttribs; }
const AttribDefaults& StagedAttribDefaults() const { return m_stagedAttribs; }
private:
static constexpr SizeT Index(MGPipeDirty bit) { return static_cast<SizeT>(bit); }
@@ -372,6 +381,7 @@ namespace MobileGL::MG_Pipe {
PatchTrio m_patch{};
RenderStateParameters m_staged{};
AttribDefaults m_stagedAttribs{};
const void* m_context = nullptr;
Uint32 m_lastDirty = 0;