mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[MG_Backend, MG_Pipe, MG_Impl] (P7): D-K2's dependency rule has one statement, and every reader reads it
P3b/P4b wave 2-D package D3, slice 2 - D2's two loose ends, now in-partition because D1 has
landed on feat/disaggregated and MG_Backend/DirectGLES/ is free.
THE STALE PROSE, in the header of the file that implements the refusal.
MG_Backend/DirectGLES/Managers.h's resolver block said "THREE OF THEM CARRY A DEPENDENCY"
(there are six rows; bits 8 and 13 were the two it did not know about) and listed
"10 without 11" among the mirror pairs that are FINE - when 10-without-11 is precisely D-K2's
fourth row (ID-14/ID-15), refused twenty lines below by ResolveTextureResourceSubsystemArm and
withheld by the client. MGPipe.h lost the identical pair of defects with R-5; this copy was
left behind because the file belonged to a package in flight. It does not restate the rows
again: the file that states them is the file the code reads.
BOTH READERS NOW READ MG_Pipe/SubsystemDeps.def. More than the two one-line changes D2
estimated, because the rule had six statements and the estimate counted two:
PipeFill.cpp P4aFamilyDependencyBits its own four-row kMGPipeP4aFamilyDependencies[]
-> MGPipeSubsystemRequires(); table deleted
PipeFill.cpp P5eFamilyIsLive hand-coded (pushMask & bit 7) == 0
-> MGPipeSubsystemDependenciesAreSet(bit 13, mask)
Managers.cpp PipeSubsystemDependencyMissing took a literal dependency BIT per call site
-> takes the FAMILY and asks the table
Managers.cpp the four resolvers five calls, five hand-written sentences
-> four calls, one per family, naming only the family
Managers.cpp ResolveVertexInputSubsystemArm hand-rolled bitSet && !resourcesBitSet
-> the table
DirectGLES.cpp ResolveBufferBindingSubsystemArm the same hand-rolled pair -> the table
MGPipe.h gains one accessor, MGPipeSubsystemDependencyWhy(), so a reader that refuses prints
the ROW'S OWN sentence instead of a copy of it. The .def has carried a Why column since R-5
and nothing read it; its "WHO READS IT" section is rewritten because "THEY ARE NOT SWITCHED
OVER IN THIS COMMIT" is no longer true of anything.
THE CLIENT'S ARGUMENT IS MASKED TO kMGPipeP4aFamilySubsystems, and that mask is the whole
difference between a rewrite and a behaviour change. The .def carries SIX rows; the table
deleted from PipeFill.cpp carried FOUR, and that predicate is wants()'s fourth conjunct for
P4a's families only. Reading all six unmasked makes the CLIENT withhold bit 8's vertex-input
emissions at a mask with bit 7 clear, which is P3a's own rule and not this gate's - caught,
not reasoned about, by TextureEmitTest's
EveryDKTwoDependencyRowGatesItsOwnFamilyAndTheMirrorPairsStayLive going red on exactly that
assertion ("bit 8 alone, with bit 7 clear: P3a's own rule, which this table must not touch").
Bit 13 is not narrowed there either; it asks the table for itself in P5eFamilyIsLive, because
bit 13's conjunct is bit 13's own. The ROWS come from one place; WHO each gate speaks for is
still each gate's.
ONE BEHAVIOUR IMPROVEMENT FALLS OUT rather than being designed in: the texture family is the
only row with two required bits and used to be two guarded calls, so a mask missing bit 11 but
carrying bit 7 was reported with the bit-7 sentence. One call now computes required & ~mask
from the row, so the refusal names whichever bit is actually missing.
WHAT THIS COSTS, said out loud. SubsystemDepsTest used to compare two COPIES of the rule; it
now compares two READERS of one table and cannot catch a typo in a row. It is kept and the
.def says why: both sides still fold in reasons of their own - the server's own family bit and
D-C3's wire-caps refusal, the client's consumer and wired conjuncts - and those can still
disagree at a mask. The compile-time half of D2's red-once (drop the fourth row from the .def
-> MGPipe.h:225/:230 fail) is untouched and is now the load-bearing one.
SubsystemDepsTest 5/5, TextureEmit's D-K2 case green, unit lane 2418/2418.
G1: .text 0xa52203, nm --defined-only 30570 symbols, 0 added / 0 removed, -D 0/0. Every line
is inside #if MOBILEGL_PIPE_PUSH or #if MOBILEGL_BUILD_DISAGGREGATED, and MGPipe.h's new
accessor is inline constexpr and unreferenced in the pull build.
This commit is contained in:
@@ -691,24 +691,29 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// family bit, so an operator can put the whole binding-point family back on the
|
||||
// frontend walk with one cleared bit.
|
||||
//
|
||||
// BIT 13 REQUIRES BIT 7, refused here rather than half-run, in
|
||||
// ResolveVertexInputSubsystemArm's exact shape and for its exact reason: every
|
||||
// MGPBufferRange::Res is resolved through the resource slot table and only bit 7 puts
|
||||
// twins there, so the pair would produce a walk in which every point logged once and
|
||||
// `continue`d WITHOUT unbinding - every draw then reading through whatever the driver
|
||||
// last had at that point.
|
||||
// THE BINDING-POINT FAMILY'S DEPENDENCY ROW IS READ FROM MG_Pipe/SubsystemDeps.def
|
||||
// (P3b/P4b R-5, switched over by wave 2-D package D3), refused here rather than half-run,
|
||||
// in ResolveVertexInputSubsystemArm's exact shape. The hand-rolled
|
||||
// `bitSet && !resourcesBitSet` this used to be was the sixth statement of D-K2's rule -
|
||||
// the .def's own "WHO READS IT" section names this function, and now it does. The reason
|
||||
// is the table's and is printed from it.
|
||||
Bool ResolveBufferBindingSubsystemArm() {
|
||||
if (MG_Config::Transport == MG_Config::TransportMode::Monolith) return false;
|
||||
const Bool bitSet =
|
||||
(MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemBufferBindings) != 0;
|
||||
const Bool resourcesBitSet =
|
||||
(MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemResources) != 0;
|
||||
if (bitSet && !resourcesBitSet) {
|
||||
const Uint64 mask = MG_Config::Features.PipePush;
|
||||
const Bool bitSet = (mask & MG_Pipe::kMGPipeSubsystemBufferBindings) != 0;
|
||||
if (bitSet &&
|
||||
!MG_Pipe::MGPipeSubsystemDependenciesAreSet(MG_Pipe::kMGPipeSubsystemBufferBindings, mask)) {
|
||||
const Uint64 required =
|
||||
MG_Pipe::MGPipeSubsystemRequires(MG_Pipe::kMGPipeSubsystemBufferBindings);
|
||||
MGLOG_E("MGPipe: kMGPipeSubsystemBufferBindings (bit 13) is set but "
|
||||
"kMGPipeSubsystemResources (bit 7) is clear; every MGPBufferRange::Res "
|
||||
"resolves through the resource slot table, which only bit 7 populates - "
|
||||
"REFUSING bit 13 and running the legacy binding-point walk. Set bit 7 as "
|
||||
"well, or clear both");
|
||||
"MOBILEGL_PIPE_PUSH=0x%llx does not carry every bit "
|
||||
"MG_Pipe/SubsystemDeps.def says it requires (requires 0x%llx, missing "
|
||||
"0x%llx): %s - REFUSING bit 13 and running the legacy binding-point walk. "
|
||||
"Set every bit of the row, or clear bit 13",
|
||||
static_cast<unsigned long long>(mask),
|
||||
static_cast<unsigned long long>(required),
|
||||
static_cast<unsigned long long>(required & ~mask),
|
||||
MG_Pipe::MGPipeSubsystemDependencyWhy(MG_Pipe::kMGPipeSubsystemBufferBindings));
|
||||
return false;
|
||||
}
|
||||
MGLOG_D("MGPipe: Espryt binding-point family runs the %s arm",
|
||||
|
||||
@@ -2952,24 +2952,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
|
||||
Bool ResolveVertexInputSubsystemArm() {
|
||||
const Bool bitSet = (MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemVertexInput) != 0;
|
||||
const Bool resourcesBitSet =
|
||||
(MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemResources) != 0;
|
||||
// BIT 8 REQUIRES BIT 7, and it is refused here rather than half-run. The vertex-input
|
||||
// handle arm resolves every attribute's driver buffer id through
|
||||
// FindBufferResourceForHandle, i.e. out of the resource SLOT TABLE - and only bit 7
|
||||
// puts twins in that table (with bit 7 clear EnsureBufferResource takes the legacy
|
||||
// arm and parks the twin on PipeResource::m_backend instead). The pair therefore
|
||||
// produced a walk in which every BindAttributeBufferByHandle logged once and
|
||||
// `continue`d WITHOUT disabling the array, so every draw fetched through whatever
|
||||
// pointer the driver VAO last held. The mirror pair (bit 7 set, bit 8 clear) is fine:
|
||||
// the legacy VAO walk calls BindAttributeBuffer -> EnsureBufferResource, which
|
||||
// dispatches to the handle arm by itself.
|
||||
if (bitSet && !resourcesBitSet) {
|
||||
MGLOG_E("MGPipe: kMGPipeSubsystemVertexInput (bit 8) is set but kMGPipeSubsystemResources "
|
||||
"(bit 7) is clear; the vertex-input handle arm resolves attribute buffer ids "
|
||||
"through the resource slot table, which only bit 7 populates - REFUSING bit 8 and "
|
||||
"running the legacy vertex-input arm. Set bit 7 as well, or clear both");
|
||||
const Uint64 mask = MG_Config::Features.PipePush;
|
||||
const Bool bitSet = (mask & MG_Pipe::kMGPipeSubsystemVertexInput) != 0;
|
||||
// The vertex-input family's row, READ FROM MG_Pipe/SubsystemDeps.def (P3b/P4b R-5,
|
||||
// switched over by wave 2-D package D3) rather than restated as the hand-rolled
|
||||
// `bitSet && !resourcesBitSet` this function used to carry - one of the six statements
|
||||
// of D-K2's rule that R-5 found with nothing comparing them. The table's own sentence
|
||||
// is what the refusal prints. The mirror pair (bit 7 set, bit 8 clear) is fine - the
|
||||
// legacy VAO walk calls BindAttributeBuffer -> EnsureBufferResource, which dispatches
|
||||
// to the handle arm by itself - and lives with the other mirror pairs in MGPipe.h.
|
||||
if (bitSet && !MG_Pipe::MGPipeSubsystemDependenciesAreSet(MG_Pipe::kMGPipeSubsystemVertexInput, mask)) {
|
||||
MGLOG_E("MGPipe: kMGPipeSubsystemVertexInput (bit 8) is set but MOBILEGL_PIPE_PUSH="
|
||||
"0x%llx does not carry every bit MG_Pipe/SubsystemDeps.def says it requires "
|
||||
"(requires 0x%llx, missing 0x%llx): %s - REFUSING bit 8 and running the "
|
||||
"legacy vertex-input arm. Set every bit of the row, or clear bit 8",
|
||||
static_cast<unsigned long long>(mask),
|
||||
static_cast<unsigned long long>(
|
||||
MG_Pipe::MGPipeSubsystemRequires(MG_Pipe::kMGPipeSubsystemVertexInput)),
|
||||
static_cast<unsigned long long>(
|
||||
MG_Pipe::MGPipeSubsystemRequires(MG_Pipe::kMGPipeSubsystemVertexInput) & ~mask),
|
||||
MG_Pipe::MGPipeSubsystemDependencyWhy(MG_Pipe::kMGPipeSubsystemVertexInput));
|
||||
return false;
|
||||
}
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
@@ -4228,14 +4230,32 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Fatal{PipeLegacyMemosDisabled, ...} rather than running the very arm the operator asked
|
||||
// to have taken away and handing back a result measured on it.
|
||||
namespace {
|
||||
// Shared by the three dependent families, so the refusal reads the same way three times
|
||||
// and a future fourth cannot invent a different wording. Returns true when the
|
||||
// dependency is missing, having said so once.
|
||||
Bool PipeSubsystemDependencyMissing(Uint64 mask, Uint64 dependencyBit, const char* what) {
|
||||
if ((mask & dependencyBit) != 0) return false;
|
||||
MGLOG_E("MGPipe: %s - REFUSING the dependent bit and running the legacy arm. "
|
||||
"Set both bits, or clear both",
|
||||
what);
|
||||
// Shared by the dependent families, so the refusal reads the same way every time and a
|
||||
// future family cannot invent a different wording. Returns true when the dependency is
|
||||
// missing, having said so once.
|
||||
//
|
||||
// P3b/P4b wave 2-D package D3: THE ROWS ARE READ FROM MG_Pipe/SubsystemDeps.def AND ARE
|
||||
// NO LONGER RESTATED HERE. This function used to take a single dependency BIT written out
|
||||
// at each call site - the server's own copy of the rule, one of the six statements R-5
|
||||
// found and two of which had drifted - and a family with two required bits needed two
|
||||
// guarded calls with two hand-written sentences. It now takes the FAMILY and asks
|
||||
// MGPipeSubsystemDependenciesAreSet, so the set of required bits, the subset that is
|
||||
// actually missing and the reason all come from the table; `what` is only the family's
|
||||
// own name. The client's gate reads the same rows
|
||||
// (MG_Impl/Pipe/PipeFill.cpp P4aFamilyDependencyBits), which is what makes
|
||||
// MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp's comparison of the two a comparison
|
||||
// of two readers rather than of two copies.
|
||||
Bool PipeSubsystemDependencyMissing(Uint64 mask, Uint64 family, const char* what) {
|
||||
if (MG_Pipe::MGPipeSubsystemDependenciesAreSet(family, mask)) return false;
|
||||
const Uint64 required = MG_Pipe::MGPipeSubsystemRequires(family);
|
||||
MGLOG_E("MGPipe: %s is set but MOBILEGL_PIPE_PUSH=0x%llx does not carry every bit "
|
||||
"MG_Pipe/SubsystemDeps.def says it requires (requires 0x%llx, missing 0x%llx): "
|
||||
"%s - REFUSING the dependent bit and running the legacy arm. Set every bit of "
|
||||
"the row, or clear the family's own",
|
||||
what, static_cast<unsigned long long>(mask),
|
||||
static_cast<unsigned long long>(required),
|
||||
static_cast<unsigned long long>(required & ~mask),
|
||||
MG_Pipe::MGPipeSubsystemDependencyWhy(family));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4344,17 +4364,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const Bool bitSet = (mask & MG_Pipe::kMGPipeSubsystemFramebuffer) != 0;
|
||||
Bool refused = false;
|
||||
if (bitSet) {
|
||||
// BIT 9 REQUIRES BIT 10. Every MGPSurface::Res in the record names a Texture or a
|
||||
// Renderbuffer handle, and only bit 10 puts twins in those two slot tables; without
|
||||
// it every attachment lookup would miss and the walk would leave the driver
|
||||
// framebuffer holding whatever the last owner attached. The mirror pair (bit 10 set,
|
||||
// bit 9 clear) is FINE: the legacy FBO sync reaches the texture twin through
|
||||
// SyncTextureObjectToBackend, which dispatches to the handle arm by itself.
|
||||
refused = PipeSubsystemDependencyMissing(
|
||||
mask, MG_Pipe::kMGPipeSubsystemTextureResources,
|
||||
"kMGPipeSubsystemFramebuffer (bit 9) is set but kMGPipeSubsystemTextureResources "
|
||||
"(bit 10) is clear; MGPSurface::Res names a Texture or Renderbuffer handle and "
|
||||
"only bit 10 populates those slot tables");
|
||||
// The framebuffer family's row, from MG_Pipe/SubsystemDeps.def. The mirror pair (bit
|
||||
// 10 set, bit 9 clear) is FINE - the legacy FBO sync reaches the texture twin through
|
||||
// SyncTextureObjectToBackend, which dispatches to the handle arm by itself - and that
|
||||
// is stated with the other mirror pairs in MGPipe.h, beside the table it is the
|
||||
// complement of, rather than here.
|
||||
refused = PipeSubsystemDependencyMissing(mask, MG_Pipe::kMGPipeSubsystemFramebuffer,
|
||||
"kMGPipeSubsystemFramebuffer (bit 9)");
|
||||
// D-C3: the wire array is Color[8] and this is the driver's RAW ES cap, which is
|
||||
// NOT clamped to 8 on the GLES path (ValidateColorAttachmentInRange rejects at or
|
||||
// above it, and BackendObject_DirectGLES publishes it verbatim). Every campaign
|
||||
@@ -4403,42 +4419,19 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const Bool bitSet = (mask & MG_Pipe::kMGPipeSubsystemTextureResources) != 0;
|
||||
Bool refused = false;
|
||||
if (bitSet) {
|
||||
// BIT 10 REQUIRES BIT 7. A buffer texture's MGPResourceDesc::BufferForTexBuffer
|
||||
// names a Buffer handle and only bit 7 puts twins in the resource slot table, so
|
||||
// with bit 7 clear every glTexBuffer would resolve to no storage at all. The mirror
|
||||
// pair (bit 7 set, bit 10 clear) is FINE and is P3a's shipped configuration.
|
||||
refused = PipeSubsystemDependencyMissing(
|
||||
mask, MG_Pipe::kMGPipeSubsystemResources,
|
||||
"kMGPipeSubsystemTextureResources (bit 10) is set but kMGPipeSubsystemResources "
|
||||
"(bit 7) is clear; a buffer texture's BufferForTexBuffer names a Buffer handle "
|
||||
"and only bit 7 populates the resource slot table");
|
||||
// BIT 10 REQUIRES BIT 11 - D-K2's FOURTH ROW (ID-14/ID-15), and it is the exact
|
||||
// mirror of ResolveVertexInputSubsystemArm's bit-8-requires-bit-7 refusal above:
|
||||
// the same "the handle arm resolves through a slot table only the other bit
|
||||
// populates" shape, refused here rather than half-run, with the legacy arm as the
|
||||
// fall-back. MGPTextureParams::BuiltinSampler is a SamplerCso HANDLE and only bit 11
|
||||
// mints sampler CSOs (contract c0b's four unconditional mints deliberately exclude
|
||||
// it), so with bit 11 clear every set_texture_params would carry a null there - and
|
||||
// the applier's verdict for a null BuiltinSampler is Fatal{ProtocolCorruption}, not
|
||||
// a decline. The brief's original sentence "bit 10 without 11 is fine" is WITHDRAWN
|
||||
// for P4a as built; package F pins this arm at 0x5ff.
|
||||
// The texture family's row, from MG_Pipe/SubsystemDeps.def. It is the ONLY row with
|
||||
// two required bits, and it used to be TWO guarded calls here with the pair of
|
||||
// sentences written out by hand - bit 7 for a buffer texture's BufferForTexBuffer,
|
||||
// and bit 11, D-K2's FOURTH ROW (ID-14/ID-15), for MGPTextureParams::BuiltinSampler.
|
||||
// One call now asks the table for both, and the refusal names whichever of the two is
|
||||
// actually missing instead of always naming the first. Package F pins this arm at
|
||||
// 0x5ff and CMakeLists.txt's refusal lane at 0x7ff; both are rows of the table now.
|
||||
//
|
||||
// THE TWO MIRROR PAIRS THAT STAY FINE, said out loud because an unreachable branch
|
||||
// that says something different is how the reachable one drifts:
|
||||
// - bit 7 set, bit 10 clear: P3a's shipped configuration (above).
|
||||
// - bit 11 set, bit 10 clear: refused one function down, by the bit-11-requires-
|
||||
// bit-10 row, so the pair is symmetric and neither half can run alone. That
|
||||
// symmetry is the point: bits 10 and 11 are now ONE arm with two switches, and
|
||||
// the only two masks that reach the texture handle arm are "both set" and
|
||||
// "neither set".
|
||||
if (!refused) {
|
||||
refused = PipeSubsystemDependencyMissing(
|
||||
mask, MG_Pipe::kMGPipeSubsystemSamplers,
|
||||
"kMGPipeSubsystemTextureResources (bit 10) is set but kMGPipeSubsystemSamplers "
|
||||
"(bit 11) is clear; MGPTextureParams::BuiltinSampler is a SamplerCso handle, "
|
||||
"only bit 11 mints sampler CSOs, and the applier's verdict for a null one is "
|
||||
"Fatal{ProtocolCorruption}");
|
||||
}
|
||||
// The mirror pairs live in MGPipe.h with the rest. The one worth remembering at this
|
||||
// call site is that bits 10 and 11 are SYMMETRIC - each row names the other - so the
|
||||
// only two masks that reach the texture handle arm are "both set" and "neither set".
|
||||
refused = PipeSubsystemDependencyMissing(mask, MG_Pipe::kMGPipeSubsystemTextureResources,
|
||||
"kMGPipeSubsystemTextureResources (bit 10)");
|
||||
}
|
||||
const BufferImpl::PipeSubsystemArmVerdict verdict = BufferImpl::ClassifyPipeSubsystemArm(
|
||||
bitSet && !refused, MG_Config::Features.PipeLegacyMemos,
|
||||
@@ -4469,23 +4462,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
const Bool bitSet = (mask & MG_Pipe::kMGPipeSubsystemSamplers) != 0;
|
||||
Bool refused = false;
|
||||
if (bitSet) {
|
||||
// BIT 11 REQUIRES BIT 10, and this is the pair G12 drives at 0x9ff. Every
|
||||
// MGPBoundView::Texture and every MGPImageView::Res names a Texture handle, and
|
||||
// only bit 10 puts one in the slot table; without it every per-unit lookup would
|
||||
// miss and the walk would `continue` WITHOUT unbinding - i.e. every draw would
|
||||
// sample through whatever the unit last held, which is exactly the shape the
|
||||
// bit-8-without-bit-7 refusal exists to prevent one family over.
|
||||
//
|
||||
// THE MIRROR PAIR (bit 10 set, bit 11 clear) IS NOT FINE EITHER, and that is D-K2's
|
||||
// fourth row (ID-14/ID-15): it is refused by ResolveTextureResourceSubsystemArm
|
||||
// above, because MGPTextureParams::BuiltinSampler is a SamplerCso handle only bit 11
|
||||
// mints. So this dependency is SYMMETRIC - the two bits are one arm with two
|
||||
// switches - and this sentence used to claim the opposite.
|
||||
refused = PipeSubsystemDependencyMissing(
|
||||
mask, MG_Pipe::kMGPipeSubsystemTextureResources,
|
||||
"kMGPipeSubsystemSamplers (bit 11) is set but kMGPipeSubsystemTextureResources "
|
||||
"(bit 10) is clear; every MGPBoundView::Texture and MGPImageView::Res names a "
|
||||
"Texture handle and only bit 10 populates that slot table");
|
||||
// The sampler family's row, from MG_Pipe/SubsystemDeps.def, and this is the pair G12
|
||||
// drives at 0x9ff. Its mirror (bit 10 set, bit 11 clear) is NOT fine either - that is
|
||||
// D-K2's fourth row, refused by ResolveTextureResourceSubsystemArm above - so the
|
||||
// dependency is SYMMETRIC and the table carries both halves.
|
||||
refused = PipeSubsystemDependencyMissing(mask, MG_Pipe::kMGPipeSubsystemSamplers,
|
||||
"kMGPipeSubsystemSamplers (bit 11)");
|
||||
}
|
||||
const BufferImpl::PipeSubsystemArmVerdict verdict = BufferImpl::ClassifyPipeSubsystemArm(
|
||||
bitSet && !refused, MG_Config::Features.PipeLegacyMemos,
|
||||
|
||||
@@ -687,12 +687,24 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// BackendSamplerObject* rows;
|
||||
// programs - g_programTwinLookupMemo.
|
||||
//
|
||||
// THREE OF THEM CARRY A DEPENDENCY (MGPipe.h, D-K2) and it is diagnosed and REFUSED here
|
||||
// rather than half-run, the bit-8-requires-bit-7 shape ResolveVertexInputSubsystemArm
|
||||
// already ships: bit 11 requires bit 10, bit 9 requires bit 10, bit 10 requires bit 7. The
|
||||
// mirror pairs (10 without 11, 10 without 9, 7 without 10) are all FINE and are said so out
|
||||
// loud, because an unreachable branch that says something different is how the reachable
|
||||
// one drifts. Bit 12 depends on nothing: a ShaderCso handle names no texture and no buffer.
|
||||
// THE DEPENDENCY ROWS ARE IN MG_Pipe/SubsystemDeps.def, ONCE (P3b/P4b R-5), and the four
|
||||
// resolvers below READ them through MGPipeSubsystemDependenciesAreSet rather than carrying a
|
||||
// copy: a dependency the table declares is diagnosed and REFUSED here rather than half-run,
|
||||
// the bit-8-requires-bit-7 shape ResolveVertexInputSubsystemArm already ships.
|
||||
//
|
||||
// THIS COMMENT USED TO RESTATE THE ROWS AND WAS WRONG IN TWO WAYS THAT NOTHING COULD FAIL,
|
||||
// in the header of the file that IMPLEMENTS the refusal. It said "THREE OF THEM CARRY A
|
||||
// DEPENDENCY" when there are six rows (bits 8 and 13 were the two it did not know about),
|
||||
// and it listed "10 without 11" among the mirror pairs that are FINE - when 10-without-11 is
|
||||
// precisely D-K2's FOURTH row (ID-14/ID-15), refused twenty lines below by
|
||||
// ResolveTextureResourceSubsystemArm and withheld by the client at PipeFill.cpp's own gate.
|
||||
// MGPipe.h carried the identical pair of defects and lost them with the table; this copy was
|
||||
// left behind because Managers.h belonged to a package in flight. The rows are not restated
|
||||
// here again: the file that states them is the one the code reads.
|
||||
//
|
||||
// The mirror pairs that really ARE fine are stated in MGPipe.h beside the table, because an
|
||||
// absence is not a row - and because that is the one place where saying it cannot drift away
|
||||
// from the rows it is the complement of.
|
||||
//
|
||||
// ResolveFramebufferSubsystemArm additionally carries D-C3's bring-up refusal: the wire
|
||||
// array is MGPFramebufferState::Color[8] and GetDynamicParameters().MaxColorAttachments is
|
||||
|
||||
@@ -1474,79 +1474,44 @@ namespace MobileGL::MG_Pipe {
|
||||
// above: with a dependency unmet the client emits NOTHING for that family and the legacy
|
||||
// pull path runs untouched, on both sides of the boundary.
|
||||
//
|
||||
// THE TABLE IS WRITTEN ONCE, HERE, and every one of its rows is the client mirror of the
|
||||
// refusal Espryt already implements, bit for bit and non-transitively - the two must say
|
||||
// the SAME thing, because a client that withheld more than the server refuses would
|
||||
// leave the server's handle arm live with no records to read, and a client that withheld
|
||||
// less is the defect above.
|
||||
struct P4aFamilyDependencyRow {
|
||||
Uint64 Family; // exactly one bit, and it is one of kMGPipeP4aFamilySubsystems
|
||||
Uint64 Requires; // the bits MOBILEGL_PIPE_PUSH must ALSO carry for it to be live
|
||||
};
|
||||
|
||||
inline constexpr P4aFamilyDependencyRow kMGPipeP4aFamilyDependencies[] = {
|
||||
// BIT 9 REQUIRES BIT 10. Every MGPSurface::Res in a set_framebuffer_state record
|
||||
// names a Texture or a Renderbuffer handle, and only bit 10 populates those two slot
|
||||
// tables (Managers.cpp ResolveFramebufferSubsystemArm).
|
||||
{kMGPipeSubsystemFramebuffer, kMGPipeSubsystemTextureResources},
|
||||
|
||||
// BIT 10 REQUIRES BIT 7 - a buffer texture's MGPResourceDesc::BufferForTexBuffer
|
||||
// names a Buffer handle and only bit 7 puts twins in the resource slot table (D-D1,
|
||||
// ResolveTextureResourceSubsystemArm's first row) - AND BIT 11, which is D-K2's
|
||||
// FOURTH row (ID-14/ID-15): MGPTextureParams::BuiltinSampler is a SamplerCso HANDLE,
|
||||
// only bit 11 mints sampler CSOs (c0b's four unconditional mints deliberately
|
||||
// exclude it), and the applier's verdict for a null one is Fatal{ProtocolCorruption}
|
||||
// rather than a decline. The brief's original "bit 10 without 11 is fine" is
|
||||
// WITHDRAWN for P4a as built.
|
||||
{kMGPipeSubsystemTextureResources,
|
||||
kMGPipeSubsystemResources | kMGPipeSubsystemSamplers},
|
||||
|
||||
// BIT 11 REQUIRES BIT 10. Every MGPBoundView::Texture and every MGPImageView::Res
|
||||
// names a Texture handle and only bit 10 populates that slot table; without it every
|
||||
// per-unit lookup would miss and the walk would `continue` WITHOUT unbinding
|
||||
// (ResolveSamplerSubsystemArm). With the row above this is SYMMETRIC: bits 10 and 11
|
||||
// are one arm with two switches, and the only two masks that reach either handle arm
|
||||
// are "both set" and "neither set".
|
||||
{kMGPipeSubsystemSamplers, kMGPipeSubsystemTextureResources},
|
||||
|
||||
// BIT 12 DEPENDS ON NOTHING, and that is a ROW rather than an absence so the table
|
||||
// covers the four families exhaustively (the static_assert below): a ShaderCso handle
|
||||
// names no texture and no buffer, the archive rides beside the record as a companion
|
||||
// pointer, and the extra inputs the server specialises on are read from state the
|
||||
// backend already holds (ResolveProgramSubsystemArm).
|
||||
{kMGPipeSubsystemPrograms, 0},
|
||||
};
|
||||
|
||||
// THE MIRROR PAIRS THAT STAY FINE, said out loud rather than left as an absence, because
|
||||
// an unreachable branch that says something different is how the reachable one drifts
|
||||
// (Managers.cpp's own words at :2377-2381) - and because the table is only trustworthy if
|
||||
// what it does NOT contain was decided rather than forgotten:
|
||||
// - bit 10 set, bit 9 clear: FINE. The legacy FBO sync reaches the texture twin through
|
||||
// SyncTextureObjectToBackend, which dispatches to the handle arm by itself.
|
||||
// - bit 11 set, bit 9 clear: FINE, for the same reason - a sampler view names a texture,
|
||||
// never a framebuffer.
|
||||
// - bit 7 set, bit 10 clear: FINE, and it is P3a's shipped configuration.
|
||||
// - bit 12 set with any or none of 9/10/11: FINE, per the last row.
|
||||
// - bit 10 set, bit 11 clear (and its mirror) is NOT fine and is the row above; this is
|
||||
// the one sentence in the brief that P4a as built withdrew.
|
||||
// THE TABLE IS WRITTEN ONCE, IN MG_Pipe/SubsystemDeps.def, and every one of its rows is
|
||||
// the client mirror of the refusal Espryt already implements, bit for bit and
|
||||
// non-transitively - the two must say the SAME thing, because a client that withheld more
|
||||
// than the server refuses would leave the server's handle arm live with no records to
|
||||
// read, and a client that withheld less is the defect above.
|
||||
//
|
||||
// THIS FILE USED TO HOLD ITS OWN COPY of the four P4a rows (P3b/P4b R-5 found six
|
||||
// statements of one rule and two of them drifted). The rows moved to the .def with R-5
|
||||
// and this reader was left pointing at the copy deliberately, because PipeFill.cpp is the
|
||||
// contract package's file for the phase; wave 2-D package D3 switches it over.
|
||||
//
|
||||
// THE ARGUMENT IS MASKED TO kMGPipeP4aFamilySubsystems, AND THAT IS THE WHOLE DIFFERENCE
|
||||
// BETWEEN A REWRITE AND A BEHAVIOUR CHANGE. The .def carries SIX rows; the table deleted
|
||||
// from here carried FOUR, and this predicate is `wants()`'s fourth conjunct for P4a's
|
||||
// families only. Reading all six unmasked would make the CLIENT withhold bit 8's
|
||||
// vertex-input emissions at a mask with bit 7 clear - P3a's own rule, which this gate has
|
||||
// never narrowed and which TextureEmitTest's
|
||||
// EveryDKTwoDependencyRowGatesItsOwnFamilyAndTheMirrorPairsStayLive pins by name ("bit 8
|
||||
// alone, with bit 7 clear: P3a's own rule, which this table must not touch"). Bit 13 is
|
||||
// not narrowed here either; it asks the table for itself in P5eFamilyIsLive below,
|
||||
// because bit 13's conjunct is bit 13's own. So the ROWS now come from one place and WHO
|
||||
// each gate speaks for is still each gate's.
|
||||
//
|
||||
// The P4a-specific COVERAGE assertion stays for the same reason: a fifth P4a family
|
||||
// without a row in the .def has to be a compile error, not a silent "depends on nothing".
|
||||
constexpr Uint64 P4aFamilyDependencyBits(Uint64 subsystem) {
|
||||
Uint64 required = 0;
|
||||
for (const P4aFamilyDependencyRow& row : kMGPipeP4aFamilyDependencies) {
|
||||
if ((subsystem & row.Family) != 0) required |= row.Requires;
|
||||
}
|
||||
return required;
|
||||
return MGPipeSubsystemRequires(subsystem & kMGPipeP4aFamilySubsystems);
|
||||
}
|
||||
|
||||
// The table covers the four families this phase migrates and nothing else, so a fifth
|
||||
// family added to kMGPipeP4aFamilySubsystems without a row here does not silently inherit
|
||||
// "depends on nothing".
|
||||
constexpr Uint64 P4aFamilyDependencyTableCoverage() {
|
||||
Uint64 covered = 0;
|
||||
for (const P4aFamilyDependencyRow& row : kMGPipeP4aFamilyDependencies) covered |= row.Family;
|
||||
for (const MGPipeSubsystemDependencyRow& row : kMGPipeSubsystemDependencies) covered |= row.Family;
|
||||
return covered;
|
||||
}
|
||||
static_assert(P4aFamilyDependencyTableCoverage() == kMGPipeP4aFamilySubsystems,
|
||||
"every P4a family needs a D-K2 dependency row, even an empty one");
|
||||
static_assert((P4aFamilyDependencyTableCoverage() & kMGPipeP4aFamilySubsystems) ==
|
||||
kMGPipeP4aFamilySubsystems,
|
||||
"every P4a family needs a D-K2 dependency row in MG_Pipe/SubsystemDeps.def, "
|
||||
"even an empty one");
|
||||
static_assert(P4aFamilyDependencyBits(kMGPipeSubsystemFramebuffer) ==
|
||||
kMGPipeSubsystemTextureResources,
|
||||
"bit 9 requires bit 10");
|
||||
@@ -1602,14 +1567,18 @@ namespace MobileGL::MG_Pipe {
|
||||
// server whose four binding-point walks still read the frontend, so a record sent to it
|
||||
// would be stored and never looked at while the client latched its suppressor.
|
||||
//
|
||||
// AND BIT 13 REQUIRES BIT 7, for bit 11's reason one family over: every
|
||||
// MGPBufferRange::Res names a Buffer handle and only bit 7 puts one in the resource
|
||||
// slot table, so without it every EnsureBufferResourceForHandle on the server would
|
||||
// mint a twin with no record behind it. Withholding the whole family is the safe
|
||||
// direction - the legacy frontend walk runs untouched on both sides.
|
||||
// AND BIT 13'S OWN DEPENDENCY ROW IS READ FROM MG_Pipe/SubsystemDeps.def, exactly as
|
||||
// P4a's four are (P3b/P4b R-5, switched over by wave 2-D package D3). It used to be the
|
||||
// hand-coded `(pushMask & kMGPipeSubsystemResources) == 0` below - the sixth statement of
|
||||
// the rule, and the one that sat fifteen lines from the block stating the other three,
|
||||
// which is how "THREE OF THEM" survived two phases. Its reason is the table's: every
|
||||
// MGPBufferRange::Res names a Buffer handle and only bit 7 puts one in the resource slot
|
||||
// table, so without it every EnsureBufferResourceForHandle on the server would mint a
|
||||
// twin with no record behind it. Withholding the whole family is the safe direction - the
|
||||
// legacy frontend walk runs untouched on both sides.
|
||||
Bool P5eFamilyIsLive(Uint64 subsystem, Uint64 pushMask) {
|
||||
if ((subsystem & kMGPipeSubsystemBufferBindings) == 0) return true;
|
||||
if ((pushMask & kMGPipeSubsystemResources) == 0) return false;
|
||||
if (!MGPipeSubsystemDependenciesAreSet(kMGPipeSubsystemBufferBindings, pushMask)) return false;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
if (MG_Config::Transport != MG_Config::TransportMode::Monolith) {
|
||||
return MG_Remote::Client::CapsMirrorInstance().ServerConsumes(
|
||||
|
||||
@@ -222,6 +222,18 @@ namespace MobileGL::MG_Pipe {
|
||||
return (pushMask & required) == required;
|
||||
}
|
||||
|
||||
// The ROW'S OWN REASON, so a reader that refuses prints the table's sentence instead of a
|
||||
// copy of it (P3b/P4b wave 2-D package D3). Empty for a family whose row requires nothing,
|
||||
// which is the same answer as "there is nothing to explain": a reader only asks after
|
||||
// MGPipeSubsystemDependenciesAreSet has already said no, and that cannot happen for a row
|
||||
// that requires 0.
|
||||
inline constexpr const char* MGPipeSubsystemDependencyWhy(Uint64 subsystem) {
|
||||
for (const MGPipeSubsystemDependencyRow& row : kMGPipeSubsystemDependencies) {
|
||||
if ((subsystem & row.Family) != 0 && row.Requires != 0) return row.Why;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static_assert(MGPipeSubsystemRequires(kMGPipeSubsystemTextureResources) ==
|
||||
(kMGPipeSubsystemResources | kMGPipeSubsystemSamplers),
|
||||
"D-K2's fourth row (bit 10 requires bit 11) has gone missing again");
|
||||
|
||||
@@ -28,23 +28,34 @@
|
||||
// MG_Remote/FatalFamilies.def - no generator reads it - and it carries pure bit constants, so
|
||||
// including it from MGPipe.h keeps check_include_closure.py's value-header rule satisfied.
|
||||
//
|
||||
// WHO READS IT. MGPipe.h turns it into kMGPipeSubsystemDependencies[] and
|
||||
// MGPipeSubsystemRequires(). The two executable statements of the rule are:
|
||||
// WHO READS IT. MGPipe.h turns it into kMGPipeSubsystemDependencies[],
|
||||
// MGPipeSubsystemRequires(), MGPipeSubsystemDependenciesAreSet() and
|
||||
// MGPipeSubsystemDependencyWhy(). The two executable statements of the rule read those, and as
|
||||
// of wave 2-D package D3 they read NOTHING ELSE - every hand-written copy is gone:
|
||||
//
|
||||
// CLIENT dependency check MG_Impl/Pipe/PipeFill.cpp's kMGPipeP4aFamilyDependencies /
|
||||
// P4aFamilyDependenciesAreSet (bits 9-12), plus P5eFamilyIsLive's
|
||||
// hand-coded bit-13 row.
|
||||
// CLIENT dependency check MG_Impl/Pipe/PipeFill.cpp's P4aFamilyDependencyBits /
|
||||
// P4aFamilyDependenciesAreSet (bits 9-12) and P5eFamilyIsLive
|
||||
// (bit 13). The local kMGPipeP4aFamilyDependencies[] is deleted;
|
||||
// what stays is the P4a-specific COVERAGE static_assert, because
|
||||
// that gate answers for four of these six families and a fifth P4a
|
||||
// family without a row here must still be a compile error.
|
||||
// SERVER consumer gate MG_Backend/DirectGLES/Managers.cpp's four
|
||||
// Resolve<Family>SubsystemArm() over PipeSubsystemDependencyMissing
|
||||
// (bits 9-12), plus ResolveVertexInputSubsystemArm (bit 8) and
|
||||
// DirectGLES.cpp's ResolveBufferBindingSubsystemArm (bit 13).
|
||||
// Resolve<Family>SubsystemArm() over PipeSubsystemDependencyMissing,
|
||||
// which now takes the FAMILY rather than a literal bit (bits 9-12),
|
||||
// plus ResolveVertexInputSubsystemArm (bit 8) and DirectGLES.cpp's
|
||||
// ResolveBufferBindingSubsystemArm (bit 13). The texture family's
|
||||
// two guarded calls collapse into one, and the refusal names
|
||||
// whichever required bit is actually missing instead of always the
|
||||
// first, because the missing set is computed from the row.
|
||||
//
|
||||
// THEY ARE NOT SWITCHED OVER IN THIS COMMIT, deliberately: PipeFill.cpp is the contract
|
||||
// package's file for the whole phase (TextureEmit.h states that rule) and Managers.cpp belongs
|
||||
// to wave 2-D package D1 while it is in flight. The anti-drift property does not wait for that,
|
||||
// because MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp drives BOTH readers at every
|
||||
// The rows moved here one commit before the readers did (R-5 landed with PipeFill.cpp and
|
||||
// Managers.cpp belonging to packages in flight), and the anti-drift property never waited for
|
||||
// that: MG_Test/Backend/DirectGLES/SubsystemDepsTest.cpp drives BOTH readers at every
|
||||
// interesting mask and compares them against these rows - a change to either side alone reds.
|
||||
// Switching the two readers to read this table is two one-line changes for the integrator.
|
||||
// It is now a comparison of two READERS rather than of two copies, which is strictly weaker as
|
||||
// a drift detector and strictly stronger as a guarantee; it is kept because the two sides still
|
||||
// fold in reasons of their own (the server's own family bit, D-C3's wire-caps refusal, the
|
||||
// client's consumer and wired conjuncts) and those can still disagree.
|
||||
//
|
||||
// THE ROWS ARE NOT TRANSITIVE, and that is load-bearing rather than an oversight: each reader
|
||||
// tests the required BITS against MOBILEGL_PIPE_PUSH alone, never the other family's liveness,
|
||||
|
||||
Reference in New Issue
Block a user