5.7 KiB
Package sb — set_shader_buffers: the binding-point tables cross the wire (P5e wave 2)
Read in this order, all of it: PACKAGE-PREAMBLE-P5E.md, INTEGRATOR-DECISIONS-P5E.md (ID-89,
ID-93 are yours), BRIEF-P5E.md (§0, §1, §2 "sb", §5, §6 rulings 3, 10, 11), CONTRACT-P5E.md
§5.6 (and §2.1 for the barriered predicate's XFB input), your scout report scout-S5.md (all of it),
and the binding-point / XFB rows of kimi-audit.md (rows 111-124) — report per row: retired / left
barriered / not found. Notes: //wsl.localhost/Arch/home/swung/w7/notes/p5e/.
Your slug is sb; your tree is ~/w7/p5e-sb (branch p5e/sb, based on the landed id head, built).
c0e has already landed the row's WaitClass, subsystem bit 13, the three suppressor slots, the
applier field declarations (BoundShaderBuffers[3], Start/Count/WritableMask[3],
ShaderBuffersSerial) and MGPipeApplySetShaderBuffers's declaration with an asserting body — you
write the bodies.
What "done" means for this family
set_shader_buffers (MGPShaderBuffers, opcode 38, kCtxState, catalogued since P5 and never
emitted) is EMITTED for the first time: one record per class (Uniform=0, ShaderStorage=1,
AtomicCounter=2), the window is the touched high-water mark per target, capacity 84 on the wire,
the backend clamps to the driver's limit. On the server, SyncBufferBindingPoints,
SyncAtomicCounterBuffers, MarkShaderStorageBuffersGpuWritten and the point half of the UBO loop
in BindCurrentProgramWithResources read the applier's arrays instead of
MGB_CTX->GetBufferBindingPoint(...), resolving every buffer with
EnsureBufferResourceForHandle(nullptr, handle). The backend's GPU-write marks (which reach into
client objects) are deleted under a transport — the client's own MarkGpuWritesForDraw already
covers them (verify, and say so).
Scope
Client: MG_State/GLState/BufferState/BufferState.h (bind-point generations, push-only),
MG_Impl/GLImpl/Buffer/GL_Buffer.cpp (the bumps at every bind-point mutator, including the named
XFB binding), MG_Impl/Pipe/Tracker.h (bits 15/16/17 shutters), new
MG_Impl/Pipe/ShaderBufferEmit.h, MG_Impl/Pipe/PipeFill.cpp (SubsystemForEmitter row, the
pairing asserts, the validate order, the reset list, the kMGPipeMaxBufferBindingPoints/84 pin).
Wire/apply: MG_Pipe/PipeApply.{h,cpp} (MGPipeApplySetShaderBuffers), MG_Pipe/PipeRoute.{h,cpp}
MG_Remote/Client/WireTables.cpp(route rows),MG_Remote/Server/PipeApplier.cpp(OnSetShaderBuffersonly). Backend:DirectGLES.cppSyncBufferBindingPoints→SyncBufferBindingPointsByRecord,MarkShaderStorageBuffersGpuWritten,SyncAtomicCounterBuffers, their call lines, and the POINT half of the UBO loop (theGetUniformBlockBindingline above it is pg's — do not touch it; coordinate through the report). Gates:scripts/gen_pipe_dirty_surface.pyDirtySurface.defrows. Tests:TrackerTest.cpp, newShaderBufferEmitTest.cpp,PipeCatalogueTest.cpp(invert the "not emitted" pins).
Rulings that bind you
- ID-104 (found by c0e after the brief was written, and it is a WIRE change you own):
MGPShaderBuffers::WritableMaskis aUint32while the window capacity is 84 points, so the mask can only describe the first 32. Widen the field so the mask covers the declared window (Uint32 WritableMask[3], orUint64+Uint32— your choice, say why); do NOT narrow the window, which would change what applications can bind. The POD grows; that is fine (opcode 80 already moved the ABI fingerprint this phase) — pin the new size inPipeCatalogueTest. This is a named exemption to the file-ownership rule: you editMG_Pipe/MGPipeTypes.h(c0e's file) in the same commit as the emitter, and nobody else touches that struct. - ID-106:
MG_Backend/Init.cpp'sConsumedSubsystemsFordoes NOT yet carry bit 13 — c0e deliberately withheld it (no emitter existed, and withholding is the safe direction). You add it in the same commit that setsShaderBufferEmit.h's wired constant, or the client's R-8 liveness gate withholds the whole family and your emission never runs. - ID-89 / rulings 10, 11: high-water window (
TouchedBufferBindingPointCountper target), 84 on the wire, backend clamps; three suppressor slots (one per class). kMGPipeWholeBufferas the wire token for a base binding needs its contract row — c0e landed the table-0 row; make the emitter use it so aglBufferDatabetween emission and apply cannot bind a stale extent.- XFB stays lockstep (contract §5.7): the XFB capture points are NOT part of your emission unless your scout's design says they are — if you emit them, the barriered predicate must keep XFB draws barriered regardless.
Red-once (execute, revert, quote)
- Revert the handle walk under a live wire →
Fatal{UnmigratedPipeInput, "GetBufferBindingPoint@DrawVbo"}understrictonSsboArrayDynamicIndexScenario/StorageBufferRegrowScenario/AtomicCounterScenario. TrackerTest:glBindBufferBase(UNIFORM,1,A); Update(); glBindBufferBase(UNIFORM,1,B); Update()must set bit 15 on the second update — red against today's tracker.GetBufferBindingPointCount'srspnon-zero before your change, 0 after, onAtomicCounterScenario.- Delete the backend marks and show
ProducerMarkCount(ShaderStorageBinding)still non-zero whileSsboArrayLengthScenario's readback sees the writes.
Gate
build, unit, isplit, gens (the dirty-surface generator must stay green — you are adding
mutators), one on the four SSBO/atomic scenarios and the three XFB ones, strict (record the
markers that disappeared). Also run the subsystem A/B with bit 13 cleared and confirm it reproduces
today's picture — that is the arm that proves the emission is what the server consumes.