diff --git a/MobileGL/MG_Backend/MGPipe/PipeInputs.h b/MobileGL/MG_Backend/MGPipe/PipeInputs.h index 5f143642..6e237de1 100644 --- a/MobileGL/MG_Backend/MGPipe/PipeInputs.h +++ b/MobileGL/MG_Backend/MGPipe/PipeInputs.h @@ -560,6 +560,12 @@ namespace MobileGL::MG_Pipe { // i.e. it is a lookup or a reverse-channel write, not a state read; there is no value // the filler could copy and no verb whose fill could make it stale. Phase C replaces // them with handle tables and callbacks. + // They carry no MGP_INPUT_CHECK / MGP_INPUT_VERIFY_READ (the declared exception to + // P1 brief D4's "every accessor body"): a forward is a live call, not a stored value, + // and InvalidateCompileEnv is reached from backend initialisation before any verb has + // filled, where a check would be Fatal{...@} on every start. Their sticky stamp + // is therefore consulted by no accessor; the tests pin it through + // MGPipeInputFieldIsFresh directly. SizeT GetBufferBindingPointCount(BufferTarget target) const; const SharedPtr& GetProgramObject(Uint index); const SharedPtr& GetTextureObject(Uint index); diff --git a/MobileGL/MG_Impl/Pipe/PipeFill.cpp b/MobileGL/MG_Impl/Pipe/PipeFill.cpp index 551678cc..9768d672 100644 --- a/MobileGL/MG_Impl/Pipe/PipeFill.cpp +++ b/MobileGL/MG_Impl/Pipe/PipeFill.cpp @@ -61,8 +61,11 @@ namespace MobileGL::MG_Pipe { dst.m_boundVertexArray = ctx.GetBoundVertexArray(); break; case F::GetBufferBindingSlot: - // Every global target has a slot; the others (Index) stay null and a read - // of one is the poison Fatal in the accessor. + // Every global target has a slot; Index stays null - GLContext resolves it + // through the bound VAO's element-buffer slot (Core.cpp), a derivation no + // FillPoints.def row can copy - and a read of it is the poison Fatal in the + // accessor. No backend reads it today (every slot read is DrawIndirect, + // DispatchIndirect, Parameter or PixelPack). for (const auto target : GlobalBufferTargets) { dst.m_bufferBindingSlot[static_cast(target)] = &ctx.GetBufferBindingSlot(target); } @@ -440,7 +443,14 @@ namespace MobileGL::MG_Pipe { if (ctx == nullptr) return; // The whole field is re-read and compared - a superset of "the same indices", so a // divergence in an index the backend did not ask for is still a divergence between - // the boundary value and the live value. The indices only decorate the report. + // the boundary value and the live value. The indices only decorate the report. The + // cost is per backend read (GetRenderStateParameters re-copies and compares the whole + // struct; GetProgramForDraw re-joins the pending link), inside the verify budget and + // to be kept in mind when reading the verify lane's wall time. + // InHook: the re-read calls the same GLContext accessor the filler calls, and + // GetProgramForDraw's join can re-enter a backend and with it another gPipeInputs + // accessor; that inner read is a plain load rather than a second hook, so the hook + // never recurses (and never reports the inner read against a half-copied scratch). g_verify.InHook = true; MGPipeFillAccess::CopyField(g_readScratch, *ctx, field); const Bool equal = MGPipeInputsFieldEqual(field, self, g_readScratch);