mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 18:13:23 +09:00
[MG_Pipe, MG_Impl, MG_Remote, MG_State, MG_Test] (Disaggregated): P5e pg - the archive becomes server-owned and the bindings get a record
- MGPipeShaderCsoRecord gains Archive, a SharedPtr<const ProgramArchive> the create
ADOPTS under a transport. Before this the applier stored the descriptor and the two
companion pointers named the frontend's own LinkArtifacts/SpirvArtifacts, which
ProgramObject::Link() replaces in place - so every reflection read on the apply thread
was torn or stale by construction the moment the client runs ahead (gap G-A).
- MGPipeApplyCreateShaderState takes the archive as a fourth argument, undefaulted for
PipeRoute.h's stated reason: a caller that has one and forgets it would compile, and
the failure would be silent. Null on the monolith arm, which keeps its frontend arms
token for token (ruling 1 / ID-81).
- ProgramArtifactsCodec gains ProgramArchive and the FRAME. SpirvArtifacts carries no
stage list and MGPProgramDesc::StageMask cannot stand in for one: it is a bit set, and
GL lets two shader objects share a stage, so a list rebuilt from it can be shorter than
generatedSpirv - which the backend pairs with it by one running index.
- Codec completeness, as CONTRACT-P5E §5.5 asks: the skipped member is named
(LinkArtifacts::program, the live glslang TProgram) and proven unread by either backend
twin; the libc++ caveat at the size echo is read as what it is - a cross-toolchain
check, exact for an in-process split - and both verdicts are written where they were
asked for.
- set_program_bindings (opcode 80) lands end to end: EmitProgramBindings on the client,
the FIFTH ROUTE ESCAPE (three tails in three index spaces plus a parallel name array -
no generated row can express it, so op 80's gMGPipeContext slot stays null as
PipeCatalogueTest pins), the wire emitter, the decoder arm that resolves and
NUL-checks every name span, and the applier body that copies the names into the record
(rule C) and advances BindingsSerial.
- The record is emitted AFTER create_shader_state, not before as the draft note said: a
re-issued create clears all three tails because they index into the archive it just
replaced, so bindings published ahead of it are wiped by the create that follows.
- MGPProgramDesc::LinkStatus is filled, and ID-88 is VERIFIED rather than assumed:
ProgramObject::Link()'s prologue bumps m_linkVersion and assigns m_artifacts = {} -
"the complete not-linked state" - before the body runs, and every ProgramLinkTask
failure arm leaves linkStatus false. A failed relink therefore reports unlinked, the
re-issue carries LinkStatus = 0, and nothing needs an object_death.
- ID-87's measurement gets its instrument: the archive's byte count is added to
PipeStats' CsoBlobBytes where the bytes actually exist, one sample per link.
This commit is contained in:
@@ -42,6 +42,26 @@
|
||||
// * and `LinkArtifacts::program` is NEVER visited. It is the live glslang TProgram, it is
|
||||
// null for every archived instance by construction, and VisitFields deliberately omits it
|
||||
// (57 of the 58 members). Decode leaves it null.
|
||||
//
|
||||
// P5e (pg), CONTRACT-P5E §5.5 "codec completeness": THE SKIPPED MEMBER IS NAMED, AND IT IS
|
||||
// `LinkArtifacts::program`. The contract asks this package either to carry it or to prove the
|
||||
// twin never reads it, and the proof is a closed grep rather than an argument: every read of
|
||||
// that member in the tree is inside `ProgramLinkTask.cpp` (`DoReflection`, which is the only
|
||||
// code that may dereference it at all) and the three sites that `reset()` it -
|
||||
// `ProgramLinkTask.cpp:678,764,877` and `ProgramObject::ResetLinkArtifacts`. `MG_Backend/`
|
||||
// contains NO read of it, in either backend; `ProgramTranslationCache` asserts it is null at
|
||||
// insert. So the archive answers every reflection question the program twin asks, and the one
|
||||
// member it does not carry is one no twin has ever asked for. It could not be carried in any
|
||||
// case: it points into a glslang arena that no archived instance owns.
|
||||
//
|
||||
// AND THE OTHER HALF OF THAT CONTRACT LINE - `ProgramArtifactsCodec.cpp`'s libc++ caveat - is
|
||||
// about the STRUCT-SIZE ECHO, not about a member: under a toolchain whose `MGL_LINKARTIFACTS_SIZE`
|
||||
// is not pinned yet (the NDK's libc++ branch of `ProgramArtifacts.h`, inert until the integrator
|
||||
// fills it in) the echo word is 0. That is SAFE FOR P5e AND NOT A GAP: the echo compares what
|
||||
// this build wrote against what this build expects, so a round trip within one build is exact,
|
||||
// and P5e is an in-process split where the writer and the reader ARE one build. It becomes a
|
||||
// real check the day a client and a server built by different toolchains share a wire, which is
|
||||
// P6's boundary and P6's problem - stated here so it cannot be discovered instead.
|
||||
namespace MobileGL::MG_State::GLState {
|
||||
|
||||
// Bumped whenever the byte format changes in a way a previous reader would misread. A
|
||||
@@ -60,6 +80,45 @@ namespace MobileGL::MG_State::GLState {
|
||||
Bool DecodeProgramArtifacts(const Uint8* bytes, SizeT size, LinkArtifacts& link,
|
||||
SpirvArtifacts& spirv);
|
||||
|
||||
// ---- P5e (pg): the archive as the SERVER OWNS it -------------------------------------
|
||||
//
|
||||
// WHAT THE TWO STRUCTS ABOVE DO NOT CARRY, and why a package that makes the server answer
|
||||
// every reflection question out of them had to notice: THE STAGE OF EACH MODULE.
|
||||
// `SpirvArtifacts::generatedSpirv` is one module per SHADER OBJECT the link consumed, in
|
||||
// snapshot order, and the stage of each lives in `ProgramObject::m_linkedShaderSnapshot` -
|
||||
// GL-thread state, not an artifact. `MGPProgramDesc::StageMask` cannot stand in for it: it
|
||||
// is a bit SET, and GL lets two shader objects of the same stage be attached to one
|
||||
// program, so a list rebuilt from the mask would be shorter than `generatedSpirv` and the
|
||||
// backend's "linked stages and modules must agree" refusal would fire on a perfectly good
|
||||
// program.
|
||||
//
|
||||
// So the frame is [stage count][stage words][the codec's own bytes], written and read by
|
||||
// this package on both sides, and `ProgramArchive` is what a decode produces: the record's
|
||||
// OWN copy, with the lifetime of the record rather than of the staged run that carried it
|
||||
// (rule C). Stages travel as Uint32 rather than as `ShaderStage` so this header keeps its
|
||||
// include closure - `ProgramArtifacts.h` beside it may not reach `ShaderStage.h`.
|
||||
struct ProgramArchive {
|
||||
LinkArtifacts Link;
|
||||
SpirvArtifacts Spirv;
|
||||
// ShaderStage, one per Spirv.generatedSpirv entry, at the same index.
|
||||
Vector<Uint32> LinkedStages;
|
||||
};
|
||||
|
||||
// The bound a decode refuses past: six is what MGPProgramDesc::Spirv[] can name and what
|
||||
// ProgramEmit.h's own truncation counter already watches, doubled so that a program this
|
||||
// stack can build is never refused here for a reason the emitter did not already count.
|
||||
inline constexpr SizeT kProgramArchiveMaxStages = 12;
|
||||
|
||||
// Appends the framed archive to `out` (not cleared, so a caller may frame it further).
|
||||
// `linkedStages` must be index-aligned with `spirv.generatedSpirv`.
|
||||
void EncodeProgramArchive(const LinkArtifacts& link, const SpirvArtifacts& spirv,
|
||||
const Vector<Uint32>& linkedStages, Vector<Uint8>& out);
|
||||
|
||||
// Replaces `out` with what `bytes` describes. Same refusal terms as
|
||||
// DecodeProgramArtifacts, plus: a stage count past kProgramArchiveMaxStages, and a stage
|
||||
// count that does not match the decoded module count.
|
||||
Bool DecodeProgramArchive(const Uint8* bytes, SizeT size, ProgramArchive& out);
|
||||
|
||||
// How many fields a type's VisitFields table actually visits. The codec walks exactly that
|
||||
// table, so this is what pins "the codec did not quietly grow an arm of its own" - most of
|
||||
// all for LinkArtifacts, whose 58th member is the live TProgram the table omits. It is a
|
||||
|
||||
Reference in New Issue
Block a user