mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Refactor] (P13 W3b): strip the push/legacy-memo guards from both backends
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -284,7 +284,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
using NativeContextKeyResolver = Bool (*)(Uint64* outSessionKey, Uint64* outContextToken);
|
||||
void SetNativeContextKeyResolver(NativeContextKeyResolver resolver);
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---------------------------------------------------------------------------------
|
||||
// P14 S6 (docs/Disaggregated/design/11-state-ownership.md): THE TWIN TABLES' KEY, AND ITS
|
||||
// SHAPE IS S4's, ONE LEVEL DOWN. A twin is a DRIVER object, so it lives in one native
|
||||
@@ -323,7 +322,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// The calling thread's key. Answers false for {0, 0} - the process-wide group - which is
|
||||
// also the answer when no probe has ever been installed.
|
||||
Bool CurrentTwinKey(TwinKey* outKey);
|
||||
#endif
|
||||
|
||||
// Builds the native context for `contextToken` under the calling thread's session. A
|
||||
// `shareGroupToken` whose group already has a live native context in this session hands that
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,6 @@
|
||||
// the monolith arm is not a split-arm fallback: it is the arm the pull, verify and push
|
||||
// builds run, so the declaration below compiles in every flavor (see ClientFetchPlan.h).
|
||||
#include <MG_Impl/Pipe/ClientFetchPlan.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a: the vertex-input payload views the handle arm of the VAO twin consumes.
|
||||
#include <MG_Pipe/MGPipeTypes.h>
|
||||
// P4a: the RECORDS the five re-keyed twins read instead of the frontend object. The readers
|
||||
@@ -31,7 +30,6 @@
|
||||
// so a forward declaration would not do. Push-only, like everything else P4a adds to this
|
||||
// header, so the pull build's include graph is unchanged (D-P).
|
||||
#include <MG_Pipe/PipeApply.h>
|
||||
#endif
|
||||
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
String EmulateBaseInstanceInVertexShader(String source, GLenum shaderType);
|
||||
@@ -309,11 +307,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// registry through the TwinRegistry alias instead, which swallows the kind in the pull
|
||||
// build. (An alias template may have a parameter it does not use, and an alias emits no
|
||||
// symbol of its own, so the pull build's mangled names are unchanged.)
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
#define MGB_TWIN_KIND_PARAM , MG_Pipe::MGPipeKind kKind
|
||||
#else
|
||||
#define MGB_TWIN_KIND_PARAM
|
||||
#endif
|
||||
|
||||
template <typename StateObject, typename BackendObject MGB_TWIN_KIND_PARAM>
|
||||
class StateBackendObjectRegistry {
|
||||
@@ -334,14 +328,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
using BackendMap = UnorderedMap<StateObject*, Entry>;
|
||||
using iterator = typename BackendMap::iterator;
|
||||
using const_iterator = typename BackendMap::const_iterator;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
using SlotTable = BackendSlotTable<StateObject, BackendObject, kKind>;
|
||||
// P14 S6: the ONE bucket of this kind the calling thread is in. Every handle-keyed entry
|
||||
// below resolves through it, so the six twin registries answer per {session, share
|
||||
// group} without a single call site naming a bucket.
|
||||
using SlotTables = SlotTableRegistry<StateObject, BackendObject, kKind>;
|
||||
using TwinKey = DirectGLES::TwinKey;
|
||||
#endif
|
||||
|
||||
BackendPtr& GetOrCreate(const StatePtr& stateObj) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
@@ -351,7 +343,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
MOBILEGL_ASSERT(stateObj != nullptr, "State object must not be null");
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (EsprytSlotTablesEnabled()) {
|
||||
// The slot table arms the teardown sentinel itself, at its own first
|
||||
// insertion (D13; SlotTables.h) - so a table used outside a registry arms
|
||||
@@ -359,7 +350,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// driver id a guarded destructor exists for.
|
||||
return m_slotTables.ForCallingThread().GetOrCreate(stateObj);
|
||||
}
|
||||
#endif
|
||||
// Twin creation is the moment a driver-owned id starts needing a guarded
|
||||
// destructor; cold path, so the once-guard costs nothing per draw. It is armed
|
||||
// here, at the first insertion - a destructor hook on the table itself is wrong
|
||||
@@ -414,11 +404,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// legacy raw-pointer registry on a transport apply thread.
|
||||
MG_Pipe::MGPipeRefuseFrontendKeyedRegistryFromApplyThread("Registry.Find(StateObject*)");
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (EsprytSlotTablesEnabled()) {
|
||||
return m_slotTables.ForCallingThread().Find(stateObj);
|
||||
}
|
||||
#endif
|
||||
const auto entryIt = m_entries.find(stateObj);
|
||||
if (entryIt == m_entries.end()) {
|
||||
return nullptr;
|
||||
@@ -449,7 +437,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
iterator end() { return m_entries.end(); }
|
||||
const_iterator end() const { return m_entries.end(); }
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The {slot, gen} this object's twin is keyed on, or the null handle. This is what a
|
||||
// backend memo stores instead of a raw pointer, a GL name or a bare lifetime id.
|
||||
MG_Pipe::MGPipeHandle HandleOf(const StateObject* stateObj) const {
|
||||
@@ -646,7 +633,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
void ForEachBucket(Fn&& fn) const {
|
||||
if (EsprytSlotTablesEnabled()) m_slotTables.ForEachBucket(fn);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The seven DirectGLES.cpp call sites drive the LEGACY arm and nothing else. On the
|
||||
// handle arm death is announced by the frontend object's destructor
|
||||
@@ -656,30 +642,18 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// without deleting the legacy arm's own collector while that arm is still compiled
|
||||
// beside it.
|
||||
void CollectGarbageIfNeeded() {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (EsprytSlotTablesEnabled()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
++m_gcTick;
|
||||
if (m_gcTick < kGCInterval) {
|
||||
return;
|
||||
}
|
||||
CollectGarbage();
|
||||
m_gcTick = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Pre-P2 API, kept for the legacy arm. On the handle arm there is nothing it could
|
||||
// collect: a twin leaves with its object's death notice, and a notice dropped during
|
||||
// process teardown is a deliberate leak (SlotTables.h), not garbage awaiting a call.
|
||||
void CollectGarbageNow() {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (EsprytSlotTablesEnabled()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CollectGarbage();
|
||||
}
|
||||
|
||||
@@ -715,7 +689,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint32 m_gcTick = 0;
|
||||
Uint32 m_creationTick = 0;
|
||||
Bool m_isCollecting = false;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P14 S6: the ONE bucket per {session, share group}, hidden behind the same member names
|
||||
// the single table had, so every handle-keyed call site above and every caller below is
|
||||
// unchanged. See SlotTables.h's SlotTableRegistry for the resolution chain.
|
||||
@@ -724,7 +697,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// never populated: the two entries that could write it are the handle-keyed ones, which
|
||||
// return early on that arm.
|
||||
SlotTable m_legacyEmptyTable;
|
||||
#endif
|
||||
};
|
||||
|
||||
#undef MGB_TWIN_KIND_PARAM
|
||||
@@ -732,15 +704,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// One spelling for the twin registry at every declaration and definition site. In the push
|
||||
// build the kind is the registry's third template argument; in the pull build the alias
|
||||
// drops it, so the mangled name is the pre-P2 two-argument one.
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
template <typename StateObject, typename BackendObject, MG_Pipe::MGPipeKind kKind>
|
||||
using TwinRegistry = StateBackendObjectRegistry<StateObject, BackendObject, kKind>;
|
||||
#else
|
||||
template <typename StateObject, typename BackendObject, MG_Pipe::MGPipeKind kKind>
|
||||
using TwinRegistry = StateBackendObjectRegistry<StateObject, BackendObject>;
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P4a (D-K3): one arm resolver per family, beside BufferImpl's two ----
|
||||
//
|
||||
// Four bits and therefore four resolvers, for P3a's reason one level out: a framebuffer
|
||||
@@ -813,7 +779,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (pg), CONTRACT-P5E.md §5.8 / ruling 1 (ID-81): THE HANDLE ARM'S SELECTOR for the
|
||||
// program family. Transport AND the family bit, in that order and both required:
|
||||
//
|
||||
@@ -831,7 +796,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
inline Bool ProgramHandleArm() {
|
||||
return MG_Config::Transport != MG_Config::TransportMode::Monolith && ProgramSubsystemEnabled();
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---- P4a: what the twins read INSTEAD of the frontend object ----
|
||||
//
|
||||
@@ -934,7 +898,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// server-side MarkStorageDirty sites are enumerated at the definition.
|
||||
Bool RearmPipeTextureLevelUpload(MG_Pipe::MGPipeHandle res, Uint16 packedTarget, Uint16 level,
|
||||
const MG_Pipe::MGPBox& wholeLevel);
|
||||
#endif
|
||||
|
||||
namespace BufferImpl {
|
||||
const GLenum TempBufferTarget = GL_ARRAY_BUFFER;
|
||||
@@ -1086,7 +1049,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// no map, and a respecification then has to retire the id rather than hand it
|
||||
// to glBufferData, which the driver would silently refuse.
|
||||
Bool immutableStorage = false;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a: the client's shadow base as the last content-carrying resource call left
|
||||
// it. The handle-shaped ops carry `shadow + offset` beside their record, so the
|
||||
// base is recovered by subtracting the record's own offset once, here.
|
||||
@@ -1109,7 +1071,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// the legacy arm did; this member exists for the drains that have no object, which
|
||||
// in P3a is the readback flush and the fp64 narrowing.
|
||||
const Uint8* hostBytes = nullptr;
|
||||
#endif
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P11 B2 (T0): the client's AHardwareBuffer this store IS - imported with
|
||||
// glBufferStorageExternalEXT, so `id` is immutable, persistentMapped and
|
||||
@@ -1127,7 +1088,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#endif
|
||||
};
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a (D-A4): the SEVENTH Espryt slot table, and the first one keyed by a handle the
|
||||
// CALL carried rather than one this backend minted off a frontend object's lifetime
|
||||
// id. That is what discharges, for this kind, the debt SlotTables.h records against
|
||||
@@ -1329,7 +1289,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// CLEAN to every question except the one under test - a case that cannot go red for
|
||||
// that question otherwise. Push-only, like the rest of this block.
|
||||
Uint CurrentBufferContextGeneration();
|
||||
#endif
|
||||
|
||||
// P5e (vi), CONTRACT-P5E §5.1 + §5.8 (ruling 1 / ID-81): THE ARM SELECTOR for this
|
||||
// family, and it is a conjunction on purpose.
|
||||
@@ -1552,7 +1511,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendVertexArrayObject();
|
||||
~BackendVertexArrayObject();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// PUBLIC AS OF P5e (vi), and the move is the point rather than a convenience: with
|
||||
// a live transport there is no frontend VAO on this side to hand to the overload
|
||||
// above, so VertexArrayImpl::SyncCurrentVAOFromRecords calls this ENTRY directly
|
||||
@@ -1561,7 +1519,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// overload, not defaulted to null") is what this obeys. The body is unchanged and
|
||||
// was already record-only - it is this family's existence proof (scout S1 §2).
|
||||
void SyncToBackendFromApplier();
|
||||
#endif
|
||||
void SyncClientSideAttributesForDrawArrays(
|
||||
const SharedPtr<MG_State::GLState::VertexArrayObject>& stateVAOObject, GLint first, GLsizei count,
|
||||
Uint32 fetchBaseInstance = 0);
|
||||
@@ -1635,13 +1592,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// DIAGNOSTICS only - that arm's repair re-ensures by `handle`, never by
|
||||
// walking back into a frontend attribute slot.
|
||||
Uint8 attribIndex = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a re-key: the entry's identity on the handle arm. A {slot, gen} cannot
|
||||
// be reproduced by a recycled heap address, so the clean probe compares
|
||||
// this instead of the raw frontend pointer and never has to ask the
|
||||
// allocator for it again mid-draw.
|
||||
MG_Pipe::MGPipeHandle handle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
};
|
||||
Bool valid = false;
|
||||
Uint32 configVersion = 0;
|
||||
@@ -1649,7 +1604,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Array<Entry, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS> entries;
|
||||
MG_State::GLState::BufferObject* iboFrontend = nullptr;
|
||||
BufferImpl::GLESBufferResource* iboResource = nullptr;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P3a re-key of the memo's validity key: on the handle arm the frontend VAO's
|
||||
// wrapping configuration version is replaced by the bound vertex-elements CSO
|
||||
// (identity AND its server-owned content serial) plus the vertex-buffer set's
|
||||
@@ -1672,7 +1626,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// the store behind an unchanged {slot, gen} re-emits set_index_buffer and
|
||||
// this is what re-opens the ensure.
|
||||
Uint64 iboSerial = 0;
|
||||
#endif
|
||||
// Buffer-mutation epoch (BufferImpl::CurrentBufferMutationEpoch) at which
|
||||
// the LAST probe pass found every entry / the IBO clean; 0 = not stamped
|
||||
// (epochs start at 1). While a stamp matches the pre-pass epoch read, the
|
||||
@@ -1696,7 +1649,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint32 configVersion = 0;
|
||||
Uint32 activeMask = 0;
|
||||
Uint32 pendingMask = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (vi), CONTRACT-P5E §5.1: the record arm's half of the key. It replaces
|
||||
// the frontend VAO's configuration version with the bound vertex-elements CSO's
|
||||
// identity and its server-owned content serial, and the substitution is
|
||||
@@ -1707,7 +1659,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// is a different {slot, gen} rather than another value of the same counter.
|
||||
MG_Pipe::MGPipeHandle elementsHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
Uint64 elementsSerial = 0;
|
||||
#endif
|
||||
};
|
||||
PendingAttribValueMask& GetPendingAttribValueMaskMemo() { return m_pendingAttribValueMask; }
|
||||
|
||||
@@ -1720,12 +1671,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// dropping it. Returns false when the stream cannot be built, in which case the
|
||||
// caller must DISABLE the array - leaving a 64-bit array enabled with no pointer is
|
||||
// what the Adreno driver turns into a SIGSEGV at the next draw.
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
Bool SyncFloat64AttributeAsFloat32(Uint attribIndex, const MG_State::GLState::VertexAttribute& attrib,
|
||||
Uint32 fetchBaseInstance);
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The handle arm of the whole vertex-elements half. Everything it needs arrives in
|
||||
// the applier's records - the bound CSO's two views, the vertex-buffer set, the
|
||||
// index buffer and the resolved fetch base instance - so it takes no argument at
|
||||
@@ -1737,27 +1683,17 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Bool SyncFloat64AttributeAsFloat32ByHandle(Uint attribIndex, const MGPVertexAttribWire& attrib,
|
||||
const MG_Pipe::MGPVertexBuffer& binding,
|
||||
Uint32 fetchBaseInstance);
|
||||
#endif
|
||||
|
||||
// What the converted float32 stream in m_convertedAttributeBufferIds[i] was built
|
||||
// from. A hit skips the CPU conversion and the re-upload; the buffer's change serial
|
||||
// is part of the key, so a glBufferSubData into the source invalidates it.
|
||||
struct ConvertedFloat64Stream {
|
||||
Bool valid = false;
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// The pre-handle pin: a FRONTEND lifetime id, i.e. the key
|
||||
// ARCHITECTURE.md 9.5 lists for deletion as "ConvertedVertexStreamKey's
|
||||
// sourcePin". Kept compiled for the legacy arm (and therefore present in
|
||||
// every pull build, which is what keeps sizeof(this) still).
|
||||
Uint64 sourceLifetimeId = 0;
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// What replaces it: the source buffer's {slot, gen}. It is the SAME identity
|
||||
// the rest of the backend now keys on, it cannot be reproduced by a recycled
|
||||
// frontend address, and it costs the walk no allocator probe - the handle is
|
||||
// already in the vertex-buffer entry that named the source.
|
||||
MG_Pipe::MGPipeHandle sourceHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
// On the handle arm this is the applier's server-owned Serial rather than the
|
||||
// frontend change serial; both answer the same question - "have the source
|
||||
// bytes moved since the conversion" - and neither is trusted for a
|
||||
@@ -1784,29 +1720,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// version early-out in SyncToBackend must not be trusted while it is set.
|
||||
Bool m_hasConvertedFloat64Attribute = false;
|
||||
Bool m_isInitialized = false;
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// ---- the pre-handle memo set (ARCHITECTURE.md 9.6) -------------------------
|
||||
// Retired by P3a on the handle arm and kept compiled here so the A/B is real: a
|
||||
// cleared subsystem bit runs THESE, not a re-keyed twin wearing their names. A
|
||||
// pull build forces MOBILEGL_PIPE_LEGACY_MEMOS ON, so sizeof(this) does not move
|
||||
// and no symbol resizes (G1).
|
||||
Uint16 m_syncedIndexBufferVersion = 0;
|
||||
// Identity of the buffer the version above was stamped against. Raw and never
|
||||
// dereferenced: the slot version is a wrapping Uint16 (see the ResolvedDrawBuffers
|
||||
// IBO memo and the packed_pixels postmortem at BindCurrentFBO), so the version
|
||||
// alone would read a wrapped-back count with a different buffer bound as clean.
|
||||
const MG_State::GLState::BufferObject* m_syncedIndexBufferObject = nullptr;
|
||||
// Aggregate gate over the per-attribute walk below: the frontend bumps its config
|
||||
// version on every per-attribute version bump (the three Bump*Version functions are
|
||||
// its only writers), so an unchanged config version proves every per-attribute
|
||||
// compare in SyncToBackend would come up clean. The index-buffer slot has its own
|
||||
// version and is NOT covered. The Bool (not a sentinel value) marks "never synced".
|
||||
Bool m_hasSyncedConfigVersion = false;
|
||||
Uint32 m_syncedConfigVersion = 0;
|
||||
Array<MG_State::GLState::VertexAttributeVersion, MG_State::GLState::VertexArrayObject::MAX_VERTEX_ATTRIBS>
|
||||
m_syncedAttributeVersions;
|
||||
#endif // MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- what replaces them on the handle arm (D-G4) ---------------------------
|
||||
// The bound vertex-elements CSO this twin last emitted, and the applier's
|
||||
// server-owned content serial for it. Together they replace
|
||||
@@ -1826,7 +1739,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// one monotone Uint64, no wrap, nothing to patch. This is the Track H re-key
|
||||
// ARCHITECTURE.md 9.5 counts.
|
||||
Uint64 m_syncedIndexSerial = 0;
|
||||
#endif
|
||||
// Byte shift currently baked into the instanced arrays' offsets by the baseInstance
|
||||
// emulation (see SetPendingFetchBaseInstance). It is draw state, not VAO state, so it
|
||||
// is deliberately NOT covered by the config version: the frontend never bumps for it.
|
||||
@@ -1843,7 +1755,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
extern TwinRegistry<MG_State::GLState::VertexArrayObject, BackendVertexArrayObject, MG_Pipe::MGPipeKind::VertexElementsCso>
|
||||
g_backendVertexArrayObjects;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (id), CONTRACT-P5E §4.1 / §4.2: THE VAO TWIN, RESOLVED BY THE HANDLE THE RECORD
|
||||
// CARRIED - `MGPipeApplierState::BoundVertexElements` at a draw, never
|
||||
// `Find(vao.get())`. One of the three resolvers the identity package lands so the
|
||||
@@ -1859,7 +1770,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// to know. Null, loudly, for a handle with no record or a generation behind the live
|
||||
// twin's; null silently for the null handle.
|
||||
BackendVertexArrayObject* ResolveVaoTwin(MG_Pipe::MGPipeHandle elements);
|
||||
#endif
|
||||
|
||||
// Shadowed glBindVertexArray: every backend VAO bind goes through here so a
|
||||
// draw's second bind of the same VAO (SyncToBackend, then PrepareForDraw's
|
||||
@@ -1882,22 +1792,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// The three declarations below and the three scopes in DirectGLES.cpp are the legacy
|
||||
// arm's, kept compiled because a cleared subsystem bit has to run a real pre-handle
|
||||
// path and because removing them would delete two symbols from the PULL build (G1).
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// Must be set BEFORE PrepareForDraw so the VAO sync sees it, and cleared after the draw
|
||||
// so the next one refetches from element 0; ScopedFetchBaseInstance does both.
|
||||
void SetPendingFetchBaseInstance(Uint32 baseInstance);
|
||||
Uint32 GetPendingFetchBaseInstance();
|
||||
|
||||
class ScopedFetchBaseInstance {
|
||||
public:
|
||||
explicit ScopedFetchBaseInstance(Uint32 baseInstance) { SetPendingFetchBaseInstance(baseInstance); }
|
||||
~ScopedFetchBaseInstance() { SetPendingFetchBaseInstance(0); }
|
||||
ScopedFetchBaseInstance(const ScopedFetchBaseInstance&) = delete;
|
||||
ScopedFetchBaseInstance& operator=(const ScopedFetchBaseInstance&) = delete;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The server-owned half of the same decision, and the reason the client never
|
||||
// pre-shifts an offset: emulation ownership is the server's (ARCHITECTURE.md 5.7).
|
||||
// True when the driver applies baseInstance to the vertex fetch itself, in which case
|
||||
@@ -1920,7 +1815,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// declaration would make that a merge conflict; a declaration with a quiet body would
|
||||
// make it a null twin and a blank draw.
|
||||
BackendVertexArrayObject* ResolveVaoTwin(MG_Pipe::MGPipeHandle vertexElements);
|
||||
#endif
|
||||
} // namespace VertexArrayImpl
|
||||
|
||||
namespace TextureImpl {
|
||||
@@ -2049,14 +1943,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendTextureObject(const BackendTextureObject&) = delete;
|
||||
BackendTextureObject& operator=(const BackendTextureObject&) = delete;
|
||||
void SyncMipmapsToBackend(const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e SEAM (declared by c0e, bodied by tx2): the same storage sync keyed on the
|
||||
// texture HANDLE, reading the applier's resource record and the server's staged
|
||||
// store instead of the frontend object's levels and pending uploads. fb's
|
||||
// attachment sync and the image sweep both call it, which is why it is declared
|
||||
// once here rather than twice in two packages' worktrees.
|
||||
void SyncMipmapsToBackendByHandle(MG_Pipe::MGPipeHandle texture);
|
||||
#endif
|
||||
// The storage half of the sync for a texture created by glTextureView. Instead of
|
||||
// allocating storage and replaying uploads, it makes this object's ES name BE a view
|
||||
// of the storage texture's ES name (EXT/OES_texture_view), which is what gives the
|
||||
@@ -2093,7 +1985,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// re-mint allocates fresh storage and only replays what the shadow still calls dirty.
|
||||
void RequireImageBindableStorage(
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& stateTextureObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Server-owned promotion: preserve an already image-bindable native
|
||||
// allocation, or capture the old native contents, merge pending
|
||||
// upload regions and re-arm the server's whole-level replay set.
|
||||
@@ -2104,7 +1995,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// level when the store covers it (notes/p9/W2-REMINT.md).
|
||||
void RequireImageBindableStorageByHandle(MG_Pipe::MGPipeHandle res,
|
||||
const MG_Pipe::MGPipeResourceRecord& record);
|
||||
#endif
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// SHARED IMAGES (MGPipeResourceRecord::SharedImageId). True when this call settled the
|
||||
// storage - the ES name's level 0 IS the image (glEGLImageTargetTexture2DOES), or the
|
||||
@@ -2174,7 +2064,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return t->GetStorageType() == TextureStorageType::Mipmap;
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (tx2), CONTRACT-P5E §5.2. THE SAME AGGREGATE GATE WITH NO FRONTEND OBJECT IN
|
||||
// IT, and it is EXACTLY the conjunction of the three handle-arm prologues' own
|
||||
// early-outs - the relation IsDrawSyncClean states above for the frontend versions,
|
||||
@@ -2205,7 +2094,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// and TextureShutterSerial are what the caller's keys already carry.
|
||||
Bool IsDrawSyncCleanByRecord(MG_Pipe::MGPipeHandle res,
|
||||
const MG_Pipe::MGPipeResourceRecord& record) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void RecreateBackendTexture();
|
||||
@@ -2328,7 +2216,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// single-level texture with a mipmapping filter), and an incomplete texture samples
|
||||
// (0, 0, 0, 1) rather than its contents.
|
||||
Bool m_forceSamplerResync = false;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P4a's handle arm: the two prologues that decide WHETHER there is work and
|
||||
// WHERE the values come from. Both answer null for "nothing to do", which covers
|
||||
// three cases the caller treats identically and the callee names individually in
|
||||
@@ -2413,7 +2300,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Pipe::MGPipeHandle PushedSyncHandle() const { return m_pushedSyncHandle; }
|
||||
|
||||
private:
|
||||
#endif
|
||||
};
|
||||
|
||||
void ActivateTextureUnit(Uint unit);
|
||||
@@ -2421,7 +2307,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
extern TwinRegistry<MG_State::GLState::ITextureObject, BackendTextureObject, MG_Pipe::MGPipeKind::Texture>
|
||||
g_backendTextureObjects;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (id), CONTRACT-P5E §4.1 / §4.2: THE TEXTURE TWIN BY HANDLE - the handle a record
|
||||
// carried (`BoundSamplerViews[u].Texture`, `BoundShaderImages[u].Res`, a framebuffer
|
||||
// record's `MGPSurface::Res`, `VerbMipRes`, `VerbCopyTexDst`, `MGPCopyImage`'s two
|
||||
@@ -2435,7 +2320,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// table's answer is an array element and only a GetOrCreate that GROWS the table moves
|
||||
// it, which this function has already done by the time it returns.
|
||||
BackendTextureObject* ResolveTextureTwin(MG_Pipe::MGPipeHandle res);
|
||||
#endif
|
||||
SharedPtr<BackendTextureObject>& SyncTextureObjectToBackend(
|
||||
const SharedPtr<MG_State::GLState::ITextureObject>& textureObject,
|
||||
Bool imageBindableStorageRequired = false);
|
||||
@@ -2444,7 +2328,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// a writable image binding, a copy, blit or mipmap generation into it. A view writes its
|
||||
// storage texture's image, so the storage texture is the one marked.
|
||||
void NoteDriverSideTextureWrite(const SharedPtr<MG_State::GLState::ITextureObject>& textureObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P5e SEAM (MG_Remote/CONTRACT-P5E.md §4.2, §5.2; declared by c0e, bodied by
|
||||
// id/tx2) --------------------------------------------------------------------------
|
||||
//
|
||||
@@ -2472,7 +2355,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// glCopyImageSubData passes: it tries FollowCopyImageInStagedStore first and marks the store
|
||||
// itself when that fails.
|
||||
void NoteDriverSideTextureWriteByHandle(MG_Pipe::MGPipeHandle texture, Bool storeFollowsTheWrite = false);
|
||||
#endif
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P8-E (notes/p8/E.md): make glCopyImageSubData's texel-block move in the server's staged
|
||||
// store too (StagedTextureStore::FollowCopy), so the destination level's bytes stay its
|
||||
@@ -2514,7 +2396,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendFramebufferObject& operator=(const BackendFramebufferObject&) = delete;
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject,
|
||||
FramebufferTarget asTarget);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e SEAM (MG_Remote/CONTRACT-P5E.md §5.4; declared by c0e, bodied by fb): the same
|
||||
// sync keyed on the framebuffer HANDLE. The record's eleven surfaces ARE the point
|
||||
// set - the emitter refuses a point at or above the wire width - so the attachment
|
||||
@@ -2522,18 +2403,15 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// handle is the argument. An OVERLOAD rather than a changed signature, so the
|
||||
// monolith arm and the pull build see no token move.
|
||||
void SyncToBackendByHandle(MG_Pipe::MGPipeHandle fbo, FramebufferTarget asTarget);
|
||||
#endif
|
||||
// Apply only this FBO's read buffer (glReadBuffer) to the backend. Split out so it can
|
||||
// still run when SyncCurrentFBO skips the READ-target sync because the same GL FBO is
|
||||
// bound as both draw and read (otherwise glReadBuffer changes would be silently dropped).
|
||||
void SyncReadBufferToBackend(const SharedPtr<MG_State::GLState::FramebufferObject>& stateFBOObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (fb, §5.4): the same read-buffer push keyed on the handle, for the one path
|
||||
// that applies a read buffer without doing the rest of the sync - SyncCurrentFBO's
|
||||
// "one object is bound to BOTH bindings" skip, where the DRAW pass already did the
|
||||
// attachment work and only glReadBuffer is READ-target-specific.
|
||||
void SyncReadBufferToBackendByHandle(MG_Pipe::MGPipeHandle fbo);
|
||||
#endif
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P5c (hd, CONTRACT-P5C §3.2): the framebuffer handle the CURRENT sync is keyed on.
|
||||
// A caller applying a record sets it before SyncToBackend / SyncReadBufferToBackend,
|
||||
@@ -2602,7 +2480,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// texture id", which no client-side version can answer; dropping it would
|
||||
// reintroduce exactly the class of bug commit d7655247 fixed on the buffer side.
|
||||
Uint64 m_syncedBackendIdGeneration = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a (D-C4): MGPFramebufferState::ContentHash as of this twin's last sync on the
|
||||
// OBJECT arm (SyncToBackend), PER TARGET IT WAS SYNCED AS, and it is the second of
|
||||
// the hash's two jobs - "the server's render-pass memo key, and the CLIENT's emission
|
||||
@@ -2647,13 +2524,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// place and the object form is visibly the half that only finds the handle.
|
||||
// glNameForDiag is 0 on the handle arm, which reads as "the record did not say".
|
||||
void ApplyReadBufferFromRecord(const MG_Pipe::MGPFramebufferState& record, Uint glNameForDiag);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern TwinRegistry<MG_State::GLState::FramebufferObject, BackendFramebufferObject, MG_Pipe::MGPipeKind::Framebuffer>
|
||||
g_backendFramebufferObjects;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a (D-C2 as corrected by ID-19): the applier's record for THE FRAMEBUFFER OBJECT this
|
||||
// handle names, or null.
|
||||
//
|
||||
@@ -2706,7 +2581,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// them is how one of them ends up describing a point differently from the others.
|
||||
const MG_Pipe::MGPSurface* PushedSurfaceForAttachment(const MG_Pipe::MGPFramebufferState& record,
|
||||
FramebufferAttachmentType point);
|
||||
#endif
|
||||
// True when the read buffer names a fixed-point (norm/snorm) attachment that the
|
||||
// backend actually stores in a floating-point format. GL clamps a read from a
|
||||
// fixed-point colour buffer to [0,1] (GL_CLAMP_READ_COLOR defaults to
|
||||
@@ -2824,7 +2698,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// GL_FRAMEBUFFER binds both targets.
|
||||
void BindFramebufferId(GLenum fbTarget, Uint id);
|
||||
Uint CurrentFramebufferBinding(FramebufferTarget target);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// THE HANDLE ARM'S OWN FRAMEBUFFER MEMOS, AND THEY ARE PACKAGE E's STORAGE
|
||||
// (DirectGLES.cpp: g_fboSyncedSerials, g_fboRecordsTrusted). E's review MAJOR-4 handed
|
||||
// this to D because InvalidateFramebufferBindingCache is in THIS file and has three
|
||||
@@ -2843,7 +2716,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
#define MOBILEGL_ESPRYT_FBO_HANDLE_ARM_MEMOS_LINKED 0
|
||||
#if MOBILEGL_ESPRYT_FBO_HANDLE_ARM_MEMOS_LINKED
|
||||
void InvalidateFramebufferHandleArmMemos();
|
||||
#endif
|
||||
#endif
|
||||
void InvalidateFramebufferBindingCache();
|
||||
// A driver framebuffer id is about to be deleted: ES reverts every target that
|
||||
@@ -3001,7 +2873,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Defined further down, next to CollectImageFormatBakeInputs; only referenced here.
|
||||
struct ImageFormatBakeInputs;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P5e (pg), CONTRACT-P5E.md §5.5: THE ONE SOURCE A PROGRAM BUILD READS ----------
|
||||
//
|
||||
// WHY THIS TYPE EXISTS AT ALL. Building a driver program asks the frontend
|
||||
@@ -3164,9 +3035,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// the frontend object the body always read, spelled through the same name so the text
|
||||
// does not move (G1).
|
||||
using ProgramBuildSource = ProgramArchiveSource;
|
||||
#else
|
||||
using ProgramBuildSource = MG_State::GLState::ProgramObject;
|
||||
#endif
|
||||
|
||||
class BackendProgramObjectImpl {
|
||||
public:
|
||||
@@ -3227,14 +3095,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendProgramObjectImpl();
|
||||
~BackendProgramObjectImpl();
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::ProgramObject>& stateProgramObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (pg), CONTRACT-P5E.md §5.5: the same sync keyed on the ShaderCso HANDLE and
|
||||
// answered from the record - the archive the create carries and the three binding
|
||||
// tails set_program_bindings carries. It is an OVERLOAD beside the frontend one,
|
||||
// which stays as the monolith-glue half, so the pull build's mangled names do not
|
||||
// move (ruling 1 / ID-81: two overloads, not an #if inside one body).
|
||||
void SyncToBackendByHandle(MG_Pipe::MGPipeHandle cso);
|
||||
#endif
|
||||
void Use();
|
||||
void SetBaseInstance(Uint32 baseInstance) const;
|
||||
void SetBaseInstanceWordIndex(Int32 wordIndex) const;
|
||||
@@ -3323,7 +3189,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// stale as one built before a relink - while the sampler half, which really is
|
||||
// re-issued per draw, needs nothing of the sort.
|
||||
Uint32 GetSyncedImageUnitVersion() const { return m_syncedImageUnitVersion; }
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a (D-B3, D-H5): the ShaderCso record's Serial this backend program was built
|
||||
// from. It is what the draw path's nine-clause rebuild condition reads on the handle
|
||||
// arm INSTEAD OF the two frontend versions above - one server-owned counter that
|
||||
@@ -3345,7 +3210,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// every applied set_program_bindings, which is exactly when one can have changed.
|
||||
// 0 means "never stamped", a guaranteed miss, because applier serials start at 1.
|
||||
Uint64 GetSyncedBindingsSerial() const { return m_syncedBindingsSerial; }
|
||||
#endif
|
||||
// Whether the (unit, bound format) pairs this program's FORMAT-LESS image uniforms
|
||||
// resolve to are still the ones its ESSL was generated against.
|
||||
//
|
||||
@@ -3370,11 +3234,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Uint64 ComputeImageUnitFormatSignature() const;
|
||||
|
||||
private:
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The one body both public heads feed; see its definition for why it is a worker in
|
||||
// a push build and IS SyncToBackend in a pull build.
|
||||
void SyncToBackendFromSource(const ProgramBuildSource& src);
|
||||
#endif
|
||||
void CacheResourceLocations(const ProgramBuildSource& src);
|
||||
|
||||
// Builds, compiles and attaches the pass-through tessellation control stage GL 4.6
|
||||
@@ -3450,12 +3312,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BufferImpl::UboRingAllocation m_globalUboRingAllocation;
|
||||
Uint32 m_syncedLinkVersion = ~0u;
|
||||
Uint32 m_syncedImageUnitVersion = ~0u;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a's replacement for the two above on the handle arm; see GetSyncedShaderCsoSerial.
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedShaderCsoSerial = 0;
|
||||
Uint64 m_syncedBindingsSerial = 0;
|
||||
#endif
|
||||
// Image units addressed by the program's FORMAT-LESS image uniforms, and the digest
|
||||
// of the (unit, format) pairs the generated ESSL baked. Empty/0 for every program
|
||||
// that declares a format on all of its images, which is the overwhelming majority -
|
||||
@@ -3478,7 +3338,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
extern TwinRegistry<MG_State::GLState::ProgramObject, BackendProgramObjectImpl, MG_Pipe::MGPipeKind::ShaderCso>
|
||||
g_backendProgramObjects;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (id), CONTRACT-P5E §4.1 / §4.2: THE PROGRAM TWIN BY HANDLE - `st.DrawProgram` at
|
||||
// a draw, `st.DispatchProgram` at a dispatch, `st.BoundShaderCso` at a bind - never
|
||||
// `Find(currentProgram.get())` and never the raw-pointer stash. Same shape and the same
|
||||
@@ -3493,7 +3352,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// ordinary path, so the band is a prerequisite and not a follow-up. The record reader
|
||||
// (PipeShaderCsoRecordForHandle) has been band-aware since P4a.
|
||||
BackendProgramObjectImpl* ResolveProgramTwin(MG_Pipe::MGPipeHandle cso);
|
||||
#endif
|
||||
|
||||
// Points one shader storage block of an ALREADY-LINKED backend program at
|
||||
// `binding`. `blockName` is the frontend interface-query spelling; the real
|
||||
@@ -3520,13 +3378,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// has to rebuild it. Computed from the values, so re-setting a block to the binding it
|
||||
// already has costs nothing. 0 when nothing was ever rebound.
|
||||
Uint64 ComputeShaderStorageBlockBindingSignature(const ProgramBuildSource& src);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e (pg): the computation itself, for the monolith arm - the source constructor seeds
|
||||
// itself with it and the monolith draw path asks it per draw. Push-only: in a pull build
|
||||
// the overload above IS this body, so no name is added there.
|
||||
Uint64 ComputeShaderStorageBlockBindingSignatureOf(
|
||||
const MG_State::GLState::ProgramObject& program);
|
||||
#endif
|
||||
|
||||
// Everything the image-format bake needs from one walk of a program's uniform
|
||||
// reflection. GLSL ES requires a format layout qualifier on every image uniform;
|
||||
@@ -3569,7 +3425,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
};
|
||||
ImageFormatBakeInputs CollectImageFormatBakeInputs(const ProgramBuildSource& src);
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P5e SEAM (MG_Remote/CONTRACT-P5E.md §4.2, §5.5; declared by c0e, bodied by
|
||||
// id/pg) ---------------------------------------------------------------------------
|
||||
//
|
||||
@@ -3596,7 +3451,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// and a handful of samplers, and a linear scan per sampler would be quadratic).
|
||||
Uint ProgramBlockBindingFromRecord(const MG_Pipe::MGPipeShaderCsoRecord& record, Int blockIndex);
|
||||
Int ProgramSamplerUnitFromRecord(const MG_Pipe::MGPipeShaderCsoRecord& record, Uint location);
|
||||
#endif
|
||||
} // namespace PrgramImpl
|
||||
|
||||
namespace SamplerImpl {
|
||||
@@ -3609,7 +3463,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
~BackendSamplerObject();
|
||||
BackendSamplerObject(const BackendSamplerObject&) = delete;
|
||||
BackendSamplerObject& operator=(const BackendSamplerObject&) = delete;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// THE SAMPLER CSO HANDLE IS CARRIED BY THE CALLER, and it has to be, because a
|
||||
// SamplerCso is CONTENT-ADDRESSED on the client (D-F1) while this twin is keyed on
|
||||
// the frontend OBJECT. g_backendSamplerObjects mints a SamplerCso slot off the
|
||||
@@ -3632,9 +3485,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// build and P4a's admitted-change set is EMPTY (D-P/G1).
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject,
|
||||
MG_Pipe::MGPipeHandle pushedCso = MG_Pipe::kMGPipeNullHandle);
|
||||
#else
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::SamplerObject>& stateSamplerObject);
|
||||
#endif
|
||||
void Bind(Uint unit);
|
||||
Uint GetBackendSamplerId() const;
|
||||
|
||||
@@ -3644,7 +3494,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Bool m_isInitialized = false;
|
||||
SamplerParameters m_cacheSamplerParameters;
|
||||
Uint16 m_syncedSamplerVersion = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a (D-B3): the SamplerCso record's Serial at the last completed sync. It replaces
|
||||
// m_syncedSamplerVersion, which stays beside it because the pre-handle arm compiles
|
||||
// under MOBILEGL_PIPE_LEGACY_MEMOS through P3a/P4a (ARCHITECTURE.md:369).
|
||||
@@ -3656,7 +3505,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
//
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedSamplerSerial = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
void UnbindSampler(Uint unit);
|
||||
@@ -3666,7 +3514,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
extern TwinRegistry<MG_State::GLState::SamplerObject, BackendSamplerObject, MG_Pipe::MGPipeKind::SamplerCso>
|
||||
g_backendSamplerObjects;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a FABLE SEAM F-4: THE TWIN FOR A CONTENT-ADDRESSED SamplerCso HANDLE.
|
||||
//
|
||||
// bind_sampler_states carries, per unit, the handle of a CSO the client allocated BY
|
||||
@@ -3697,10 +3544,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// pre-handle arm - a twin keyed on the frontend object - is untouched and still serves
|
||||
// the raw-depth-fetch sampler and every caller that carries no handle.
|
||||
BackendSamplerObject* ResolveSamplerCsoTwin(MG_Pipe::MGPipeHandle cso);
|
||||
#endif
|
||||
} // namespace SamplerImpl
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
namespace SamplerViewImpl {
|
||||
// P4a (D-F2/D-F3): the SIXTH Espryt twin table, and the only one of the six whose kind
|
||||
// has no frontend object at all. MobileGL has no sampler-view class: GL binds a texture
|
||||
@@ -3767,7 +3612,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
MG_Pipe::MGPipeHandle HandleOfSamplerViewForTexture(
|
||||
const MG_State::GLState::ITextureObject* textureObject);
|
||||
} // namespace SamplerViewImpl
|
||||
#endif
|
||||
|
||||
namespace RenderbufferImpl {
|
||||
class BackendRenderbufferObject {
|
||||
@@ -3779,7 +3623,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
BackendRenderbufferObject(const BackendRenderbufferObject&) = delete;
|
||||
BackendRenderbufferObject& operator=(const BackendRenderbufferObject&) = delete;
|
||||
void SyncToBackend(const SharedPtr<MG_State::GLState::RenderbufferObject>& stateRBOObject);
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5e SEAM (declared by c0e, bodied by fb): the renderbuffer twin of the
|
||||
// framebuffer overload above. MGPSurface::Res names the renderbuffer and the
|
||||
// resource record already carries its format, extent and sample count (P4a), so the
|
||||
@@ -3788,7 +3631,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// cross-check, the sibling that never got the Transport == Monolith gate its
|
||||
// texture counterpart has).
|
||||
void SyncToBackendByHandle(MG_Pipe::MGPipeHandle renderbuffer);
|
||||
#endif
|
||||
Uint GetBackendRenderbufferId() const { return m_backendRBOId; }
|
||||
void Bind() const;
|
||||
|
||||
@@ -3800,7 +3642,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
Int m_cacheWidth = 0;
|
||||
Int m_cacheHeight = 0;
|
||||
Int m_cacheSamples = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P4a (D-D2/D-B3): the resource record's Serial at the last completed allocation.
|
||||
// It replaces the four-field cache above AS A GATE - the four members stay, because
|
||||
// they are also what the legacy arm compares and what the twin reports about the
|
||||
@@ -3813,7 +3654,6 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
//
|
||||
// Push-only, so the pull build's object is byte-for-byte the pre-P4a one (D-P).
|
||||
Uint64 m_syncedResourceSerial = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern TwinRegistry<MG_State::GLState::RenderbufferObject, BackendRenderbufferObject, MG_Pipe::MGPipeKind::Renderbuffer>
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
// translation units that include it without copying Managers.h's include order.
|
||||
#include "DirectGLES.h"
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
#include <MG_Impl/Pipe/SlotAllocator.h>
|
||||
#endif
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#include <MG_Pipe/PipeSessionFail.h>
|
||||
#endif
|
||||
@@ -104,7 +102,6 @@
|
||||
// The registry guard is independent of Magma's legacy allocator debt scope.
|
||||
namespace MobileGL::MG_Backend::DirectGLES {
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
|
||||
// Declared in Managers.h as well; repeated here because this header is included from it
|
||||
// before that declaration, and the table below is the arming site on this arm (D13: "the
|
||||
@@ -1070,5 +1067,4 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
mutable MG_Pipe::MGPipeHandle m_memoHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
};
|
||||
|
||||
#endif // MOBILEGL_PIPE_PUSH
|
||||
} // namespace MobileGL::MG_Backend::DirectGLES
|
||||
|
||||
@@ -433,7 +433,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void BackendObject_DirectVulkan::Initialize() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
VkBufferManager::RegisterWireResourceOps();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P7 wave 2 package C (CONTRACT-P7 §5.5). BESIDE the resource ops and for the same
|
||||
// reason: this is the one place both Magma server roles pass through - the inproc
|
||||
// role and the spawn/TCP session child - and ServerLoop::CreateBackend calls it at
|
||||
@@ -441,7 +440,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// before any frontend object can die unheard. A per-transport install is how one of
|
||||
// the two roles ends up without it.
|
||||
InstallStateObjectDeathOps();
|
||||
#endif
|
||||
#endif
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
#include <Config.h>
|
||||
#include <MG_Remote/Server/ServerLoop.h>
|
||||
#include <MG_Pipe/PipeApply.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P7 wave 2 package C (CONTRACT-P7 §5.5): Magma's own death-notice table. Both headers are
|
||||
// push-only and reached here for the same reason DirectGLES/Managers.cpp reaches them - the
|
||||
// notice is declared by the frontend and answered by whichever backend is running.
|
||||
#include <MG_Remote/Client/WireTables.h>
|
||||
#include <MG_State/GLState/StateObjectDeathNotice.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
@@ -70,7 +68,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
SessionLocal<RendererGeneration> g_rendererGeneration;
|
||||
} // namespace
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED && MOBILEGL_PIPE_PUSH
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
namespace {
|
||||
// P7 wave 2 package C, CONTRACT-P7 §5.5: MAGMA'S MIRROR OF g_glesStateObjectDeathOps
|
||||
// (DirectGLES/Managers.cpp:335), and the one arm of that table Magma has any work in.
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint64 GetRendererGeneration();
|
||||
void BumpRendererGeneration();
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED && MOBILEGL_PIPE_PUSH
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P7 wave 2 package C (CONTRACT-P7 §5.5). Magma's StateObjectDeathOps table, installed
|
||||
// from BackendObject_DirectVulkan::Initialize() so that GetStateObjectDeathOps() is
|
||||
// non-null on every Magma role that owns a backend. See the definition for what the one
|
||||
|
||||
@@ -10,13 +10,11 @@
|
||||
#include <Includes.h>
|
||||
|
||||
#include <Config.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// kMGPipeSubsystem* - the runtime bitmask's named bits - and MGPipeHandle itself. Both are
|
||||
// header-only constant/POD declarations, and both are push-only, so the pull build's include
|
||||
// graph is unchanged (G1).
|
||||
#include <MG_Pipe/MGPipe.h>
|
||||
#include <MG_Pipe/MGPipeHandles.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -44,7 +42,6 @@
|
||||
// below is behind it, and the pull build's translation units are byte-identical (G1).
|
||||
namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Is `subsystemBit` (MG_Pipe/MGPipe.h's kMGPipeSubsystem*) migrated in this run?
|
||||
inline Bool MagmaPipeSubsystemOn(Uint64 subsystemBit) {
|
||||
return (MG_Config::Features.PipePush & subsystemBit) != 0;
|
||||
@@ -93,18 +90,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static_cast<unsigned long long>(MG_Config::Features.PipePush |
|
||||
MG_Pipe::kMGPipeSubsystemRenderState));
|
||||
}
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// The pre-handle arm is compiled AND the operator has not forbidden entering it, so a
|
||||
// clear bit is an ordinary, valid A/B: the site takes the legacy arm.
|
||||
if (MG_Config::Features.PipeLegacyMemos) return;
|
||||
#endif
|
||||
if (MagmaPipeSubsystemOn(MG_Pipe::kMGPipeSubsystemMagmaVertexInput)) return;
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
const char* const why = "this run has MOBILEGL_PIPE_LEGACY_MEMOS=0";
|
||||
#else
|
||||
const char* const why =
|
||||
"this build has cmake -DMOBILEGL_PIPE_LEGACY_MEMOS=OFF, which compiles no such arm";
|
||||
#endif
|
||||
MGLOG_F("MGPipe: Fatal{PipeLegacyMemosDisabled} Magma's Track-H subsystem "
|
||||
"(kMGPipeSubsystemMagmaVertexInput, bit 6 of MOBILEGL_PIPE_PUSH) is clear, so the "
|
||||
"vertex-input cache and the VAO draw memo want the pre-handle arm - but %s. Set "
|
||||
@@ -119,15 +107,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// "Does this Track-H site run the handle arm?" - the ONE question every re-keyed Track-H
|
||||
// site asks, so that they cannot disagree with each other or with the startup gate.
|
||||
inline Bool MagmaPipeTrackHArmIsHandles(Uint64 trackHBit) {
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
return MagmaPipeSubsystemOn(trackHBit);
|
||||
#else
|
||||
// No pre-handle arm exists in this build, and MagmaPipeValidateSubsystemConfiguration
|
||||
// has already made a clear bit a startup Fatal, so the handle arm is the only arm a
|
||||
// running process can be on.
|
||||
(void)trackHBit;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
@@ -607,5 +591,4 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
return memos;
|
||||
}
|
||||
#endif // MOBILEGL_PIPE_PUSH
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -13,10 +13,8 @@
|
||||
#include "MG_Impl/GLImpl/Framebuffer/GL_Framebuffer.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev: the surface-changed event's producer callback, installed by the server session.
|
||||
#include <MG_Pipe/MGPipeCallbacks.h>
|
||||
#endif
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<vulkan/vk_enum_string_helper.h>)
|
||||
@@ -349,7 +347,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
break;
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged != nullptr) {
|
||||
// P5c ev (CONTRACT-P5C §4.2): with an active transport the default FBO's
|
||||
// attachments are CLIENT memory and this thread may not write them - the backend
|
||||
@@ -367,7 +364,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
info.IsDefault = 1;
|
||||
MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged(&info);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
auto* colorTex = static_cast<MG_State::GLState::TextureObject2D*>(defaultFBOInfo->colorAttachment.get());
|
||||
colorTex->AllocateStorage(
|
||||
|
||||
@@ -12,10 +12,8 @@
|
||||
#include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h"
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include <MG_Pipe/PipeInputsSwitch.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev: the GPU-write announcement routes through the reverse channel (R2).
|
||||
#include <MG_Impl/Pipe/ResourceTracker.h>
|
||||
#endif
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject1D.h"
|
||||
#include "MG_State/GLState/TextureState/TextureObject2D.h"
|
||||
@@ -1631,13 +1629,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// changed a byte of it.
|
||||
bufferObject->EnsureGpuResidentStorage();
|
||||
if (imageBinding.Access != GL_READ_ONLY) {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev (R2, CONTRACT-P5C §4.2): the announcement goes through the reverse
|
||||
// channel - the apply thread may not poke the client object directly.
|
||||
MG_Pipe::MGPipeAnnounceBufferGpuWritten(bufferObject);
|
||||
#else
|
||||
bufferObject->MarkGpuWritten();
|
||||
#endif
|
||||
}
|
||||
|
||||
BufferSlice slice{};
|
||||
@@ -1884,13 +1878,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// results are visible without a readback path, exactly as for a capture buffer.
|
||||
bufferObject->EnsureGpuResidentStorage();
|
||||
// ... and the read that follows has to wait for this draw or dispatch to retire.
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev (R2, CONTRACT-P5C §4.2): through the reverse channel, not a direct poke of
|
||||
// the client object from the apply thread.
|
||||
MG_Pipe::MGPipeAnnounceBufferGpuWritten(bufferObject);
|
||||
#else
|
||||
bufferObject->MarkGpuWritten();
|
||||
#endif
|
||||
|
||||
BufferSlice slice{};
|
||||
if (!m_bufferManager->AcquireResidentSlice(BufferKind::ShaderStorage, bufferObject, slice) || !slice.IsValid()) {
|
||||
|
||||
@@ -58,7 +58,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// changes is that the key is now the identity the SERVER will be handed once
|
||||
// buffers travel as handles, instead of a number only the client can mint.
|
||||
Uint64 bufferKey = attr.Buffer ? attr.Buffer->GetLifetimeId() : 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (attr.Buffer) {
|
||||
// The SAME arm question the other four re-keyed sites ask, through the same
|
||||
// helper: a site that decided for itself could silently key on the pre-handle
|
||||
@@ -86,14 +85,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
bufferKey = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
XXHASH_VERIFY(XXH64_update(m_hashState, &bufferKey, sizeof(bufferKey)));
|
||||
}
|
||||
|
||||
return XXH64_digest(m_hashState);
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
VertexInputStateFactory::VaoBackendMemos& VertexInputStateFactory::MemosFor(
|
||||
const MG_State::GLState::VertexArrayObject& vao) const {
|
||||
const MG_Pipe::MGPipeHandle handle =
|
||||
@@ -113,9 +110,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// suite's business, for the reason MagmaPipeAbaControlDefeatsIdentity spells out.
|
||||
return MagmaPipeClaimSlotMemos(m_vaoMemos, handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
Bool VertexInputStateFactory::TryGetMemoizedHash(const MG_State::GLState::VertexArrayObject& vao,
|
||||
Uint64& outHash) const {
|
||||
if (MagmaPipeTrackHArmIsHandles(MG_Pipe::kMGPipeSubsystemMagmaVertexInput)) {
|
||||
@@ -124,18 +119,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
outHash = memos.Hash;
|
||||
return true;
|
||||
}
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
return vao.GetBackendHashMemo(outHash);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
VertexInputStateFactory::HashType VertexInputStateFactory::GetOrComputeHash(
|
||||
const MG_State::GLState::VertexArrayObject& vao) const {
|
||||
HashType hash = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.5: the same memo, on the backend's side of the boundary.
|
||||
if (MagmaPipeTrackHArmIsHandles(MG_Pipe::kMGPipeSubsystemMagmaVertexInput)) {
|
||||
VaoBackendMemos& memos = MemosFor(vao);
|
||||
@@ -147,19 +136,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
memos.HashConfigVersion = vao.GetConfigVersion();
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
if (!vao.GetBackendHashMemo(hash)) {
|
||||
hash = ComputeHash(vao);
|
||||
vao.SetBackendHashMemo(hash);
|
||||
}
|
||||
#endif
|
||||
return hash;
|
||||
}
|
||||
|
||||
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
|
||||
const MG_State::GLState::VertexArrayObject& vao) {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.5: the same per-draw fast path, but the resolved-entry pointer lives in this
|
||||
// factory's slot-indexed table instead of on the frontend VAO. The eviction epoch
|
||||
// survives the move and is still what stops a stale pointer being dereferenced: the
|
||||
@@ -186,33 +167,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// live reader anywhere, so the handle arm retires it rather than moving it.
|
||||
return resolved;
|
||||
}
|
||||
#endif
|
||||
#if !MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// Unreachable: with no legacy arm compiled MagmaPipeTrackHArmIsHandles is a compile-
|
||||
// time true, so the handle arm above always returns. Written out rather than left to
|
||||
// fall off the end so the function still has a return on every path a compiler sees.
|
||||
return GetOrCreateVertexInputState(vao, GetOrComputeHash(vao));
|
||||
#else
|
||||
// Per-draw fast path: the VAO carries a pointer to its resolved entry,
|
||||
// valid while its config version and the cache's eviction epoch both
|
||||
// match - no re-hash, no map lookup.
|
||||
const void* memoState = nullptr;
|
||||
Uint64 memoEpoch = 0;
|
||||
if (vao.GetBackendStateMemo(memoState, memoEpoch) && memoEpoch == m_evictionEpoch) {
|
||||
const auto* entry = static_cast<const BackendVertexInputState*>(memoState);
|
||||
entry->lastUsedFrameBoundary = m_frameBoundaryCounter;
|
||||
return *entry;
|
||||
}
|
||||
const BackendVertexInputState& entry = GetOrCreateVertexInputState(vao, GetOrComputeHash(vao));
|
||||
vao.SetBackendStateMemo(&entry, m_evictionEpoch);
|
||||
// Also mirror the layout identity and the two per-draw masks into the VAO's aux
|
||||
// memo (pure VALUES derived from the VAO configuration, so config-version
|
||||
// guarding alone is sound). The draw fast path reads them from the VAO object it
|
||||
// already touched instead of chasing into this entry - see PackVertexInputAuxMemo.
|
||||
vao.SetBackendAuxMemo(entry.layoutHash,
|
||||
PackVertexInputAuxMasks(entry.unsupportedAttribMask, entry.attributeLocationMask));
|
||||
return entry;
|
||||
#endif // MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
}
|
||||
|
||||
const VertexInputStateFactory::BackendVertexInputState& VertexInputStateFactory::GetOrCreateVertexInputState(
|
||||
@@ -599,11 +557,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// instances (see the member comment). With no legacy arm the memos
|
||||
// live in this factory and die with it, so a per-instance bump is
|
||||
// enough - P2 D12.5.
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
m_evictionEpoch = ++s_evictionEpochSource;
|
||||
#else
|
||||
++m_evictionEpoch;
|
||||
#endif
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
};
|
||||
};
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The mint is the RENDERER's (MagmaPipeIdentityTables), not a process-global and not
|
||||
// this factory's: VulkanRenderer::LookupVaoDrawMemo has to derive the same {slot, gen}
|
||||
// for the same VAO, and a table that outlived the context it was minted for would share
|
||||
@@ -86,10 +85,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VertexInputStateFactory(const VulkanRendererConfig& config, VkPhysicalDevice physicalDevice,
|
||||
MagmaPipeIdentityTables& identity):
|
||||
m_config(config), m_physicalDevice(physicalDevice), m_identity(&identity) {}
|
||||
#else
|
||||
VertexInputStateFactory(const VulkanRendererConfig& config, VkPhysicalDevice physicalDevice):
|
||||
m_config(config), m_physicalDevice(physicalDevice) {}
|
||||
#endif
|
||||
~VertexInputStateFactory() = default;
|
||||
VertexInputStateFactory(const VertexInputStateFactory&) = delete;
|
||||
|
||||
@@ -104,13 +99,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// Memoized ComputeHash: reuses the VAO's cached hash while its config version
|
||||
// is unchanged. Use this on per-draw paths.
|
||||
HashType GetOrComputeHash(const MG_State::GLState::VertexArrayObject& vao) const;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The VAO's content hash IF it has already been memoized, without computing one.
|
||||
// P2 D12.5: the three draw-path readers that used to ask the VAO object this
|
||||
// question ask the factory instead, because that is where the memo lives once the
|
||||
// frontend object stops carrying the backend's state.
|
||||
Bool TryGetMemoizedHash(const MG_State::GLState::VertexArrayObject& vao, Uint64& outHash) const;
|
||||
#endif
|
||||
const BackendVertexInputState& GetOrCreateVertexInputState(
|
||||
const MG_State::GLState::VertexArrayObject& vao, HashType hash);
|
||||
const BackendVertexInputState& GetOrCreateVertexInputState(const MG_State::GLState::VertexArrayObject& vao);
|
||||
@@ -144,7 +137,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
static VkFormat ToFloat32VertexFormat(Int componentCount);
|
||||
Bool SupportsVertexBufferFormat(VkFormat format) const;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- P2 D12.5: the backend's memos, off the frontend VAO and into the backend ----
|
||||
//
|
||||
// The two facts that used to live as `mutable` fields on VertexArrayObject
|
||||
@@ -180,7 +172,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// The entry belonging to `vao`, claimed (and cleared) if the slot currently holds
|
||||
// someone else's.
|
||||
VaoBackendMemos& MemosFor(const MG_State::GLState::VertexArrayObject& vao) const;
|
||||
#endif
|
||||
|
||||
const VulkanRendererConfig& m_config;
|
||||
VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
|
||||
@@ -217,12 +208,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// memos live on the frontend VAOs and therefore outlive the factory. The handle arm's
|
||||
// memo table is owned by this factory and dies with it, so a per-instance counter is
|
||||
// enough there and the epoch shrinks back to what it looks like it should be.
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
static inline std::atomic<Uint64> s_evictionEpochSource{0};
|
||||
Uint64 m_evictionEpoch = ++s_evictionEpochSource;
|
||||
#else
|
||||
Uint64 m_evictionEpoch = 1;
|
||||
#endif
|
||||
static inline thread_local XXH64_state_t* m_hashState = XXH64_createState();
|
||||
};
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
|
||||
#include "MG_State/GLState/Core.h"
|
||||
#include <MG_Pipe/PipeInputsSwitch.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev: the GPU-write announcement routes through the reverse channel (R2).
|
||||
#include <MG_Impl/Pipe/ResourceTracker.h>
|
||||
#endif
|
||||
#include "MG_State/GLState/ProgramState/ProgramObject.h"
|
||||
#include "MG_State/GLState/ProgramState/ShaderObject.h"
|
||||
#include "MG_State/GLState/SamplerState/SamplerObject.h"
|
||||
@@ -441,7 +439,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// Per Magma session (MagmaSession.h): it shadows the session's own command buffer.
|
||||
static SessionLocal<DynamicStateShadow> g_dynamicStateShadow;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// ---- D12.3: DynamicTailKey's inputs against the P2 chunk table ----
|
||||
//
|
||||
// DynamicTailKey's inventory (declared above, one line per reader) is an exact,
|
||||
@@ -534,7 +531,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
"ScissorTestEnabledMask is written by SetCapability(ScissorTest), which calls "
|
||||
"BumpVersions(), so the chunk table must keep it in the pipeline half");
|
||||
} // namespace
|
||||
#endif // MOBILEGL_PIPE_PUSH
|
||||
|
||||
static void ResetDynamicStateShadow() {
|
||||
*g_dynamicStateShadow = {};
|
||||
@@ -3262,13 +3258,11 @@ void main() {
|
||||
}
|
||||
|
||||
void VulkanRenderer::Initialize() {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D14, and it belongs HERE rather than on a draw: "a Track-H subsystem whose bit is
|
||||
// clear is a STARTUP Fatal{PipeLegacyMemosDisabled}". Checks Magma's own bit only, and
|
||||
// only once this backend is the one being brought up, so an Espryt-side bitmask cannot
|
||||
// kill a Magma run and vice versa.
|
||||
MagmaPipeValidateSubsystemConfiguration();
|
||||
#endif
|
||||
CreateInstance();
|
||||
if (!CreateSurface()) throw RuntimeError("DirectVulkan: the initial surface could not be created");
|
||||
PickPhysicalDevice();
|
||||
@@ -3454,12 +3448,8 @@ void main() {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
m_uniformManager->SetWireInvalidStorageImageArm(m_wireNullDescriptor);
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
m_vertexInputStateFactory =
|
||||
MakeUnique<VertexInputStateFactory>(m_config, m_physicalDevice.handle, m_pipeIdentity);
|
||||
#else
|
||||
m_vertexInputStateFactory = MakeUnique<VertexInputStateFactory>(m_config, m_physicalDevice.handle);
|
||||
#endif
|
||||
MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed.");
|
||||
|
||||
// Prime the first frame so Render() always targets an acquired swapchain image.
|
||||
@@ -3838,7 +3828,6 @@ void main() {
|
||||
if (m_vaoDrawMemoTable.empty()) {
|
||||
m_vaoDrawMemoTable.resize(kVaoDrawMemoSlotCount);
|
||||
}
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
if (MagmaPipeAbaControlDefeatsIdentity()) {
|
||||
// Negative control C (P2 brief D18), ahead of BOTH arms because it defeats the
|
||||
// identity half of both keys at once: the legacy arm's (address, lifetime id) pair
|
||||
@@ -3907,7 +3896,6 @@ void main() {
|
||||
victim->bindings.indexBuffer = nullptr;
|
||||
return victim;
|
||||
}
|
||||
#endif
|
||||
// Multiplicative mix of the (16-byte-aligned) address; take high bits, they
|
||||
// carry the most entropy of a multiply.
|
||||
const Uint64 mixed = static_cast<Uint64>(reinterpret_cast<SizeT>(vao) >> 4) * 0x9E3779B97F4A7C15ull;
|
||||
@@ -5314,100 +5302,7 @@ void main() {
|
||||
return MGB_CTX->GetRenderStateParameters().SampleMaskValue;
|
||||
}
|
||||
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
Uint64 VulkanRenderer::ComputePipelineStateHash(Uint32 colorAttachmentCount,
|
||||
VkSampleCountFlagBits rasterizationSamples) const {
|
||||
// One bulk fetch instead of ~17 per-field accessor calls into MG_State: every
|
||||
// input below is a plain field of RenderStateParameters, and each accessor this
|
||||
// replaces (IsCapabilityEnabled / Get*) is a verified pure read of that same
|
||||
// field (RenderState.cpp), so the hashed values are bit-identical. This runs on
|
||||
// every draw whose pipeline-state version moved (a per-draw GL_BLEND toggle),
|
||||
// where the accessor-call overhead dominated the hash itself.
|
||||
const RenderStateParameters& p = MGB_CTX->GetRenderStateParameters();
|
||||
Uint64 capabilityBits = 0;
|
||||
capabilityBits |= p.CullFaceEnabled ? 1ull << 0 : 0;
|
||||
capabilityBits |= p.DepthTestEnabled ? 1ull << 1 : 0;
|
||||
capabilityBits |= p.PolygonOffsetFillEnabled ? 1ull << 2 : 0;
|
||||
capabilityBits |= p.RasterizerDiscardEnabled ? 1ull << 3 : 0;
|
||||
capabilityBits |= p.ColorLogicOpEnabled ? 1ull << 4 : 0;
|
||||
capabilityBits |= p.StencilTestEnabled ? 1ull << 5 : 0;
|
||||
capabilityBits |= p.PrimitiveRestartEnabled ? 1ull << 6 : 0;
|
||||
capabilityBits |= p.PrimitiveRestartFixedIndexEnabled ? 1ull << 7 : 0;
|
||||
capabilityBits |= p.DepthMask ? 1ull << 8 : 0;
|
||||
capabilityBits |= p.SampleShadingEnabled ? 1ull << 9 : 0;
|
||||
// The EFFECTIVE mask enable, not the raw GL bit: at one sample GL says the whole
|
||||
// multisample fragment-operations step makes no change, so the pipeline is built with
|
||||
// full coverage and the memo word has to say so too. Keying on the raw bit here while
|
||||
// the payload gates on the sample count would let one FBO's cached pipeline answer for
|
||||
// another whose sample count reads the mask differently.
|
||||
const Bool sampleMaskEffective = ResolveEffectiveSampleMask(rasterizationSamples) != 0xffffffffu;
|
||||
capabilityBits |= sampleMaskEffective ? 1ull << 10 : 0;
|
||||
Uint64 hash = CombinePipelineStateWord(0x243F6A8885A308D3ull, capabilityBits);
|
||||
// glMinSampleShading. Hashed by BITS, not by value: this memo compares hashes rather than
|
||||
// versions, so an unhashed float would let a pipeline built at one rate be handed back
|
||||
// after glMinSampleShading moved it - the memo would see identical state.
|
||||
{
|
||||
Uint32 minSampleShadingBits = 0;
|
||||
std::memcpy(&minSampleShadingBits, &p.MinSampleShadingValue, sizeof(minSampleShadingBits));
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(minSampleShadingBits));
|
||||
}
|
||||
// glSampleMaski's word, for the same reason glMinSampleShading's bits are hashed above:
|
||||
// this memo compares hashes, not versions, so a mask that moved between two otherwise
|
||||
// identical draws has to key a different pipeline. Hashed unconditionally rather than only
|
||||
// while GL_SAMPLE_MASK is enabled - the enable bit is already in capabilityBits, and
|
||||
// folding one more word costs nothing on a path that only recomputes when the
|
||||
// pipeline-state version moved.
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(ResolveEffectiveSampleMask(rasterizationSamples)));
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(p.PatchVertices));
|
||||
// The default tessellation levels belong here for the same reason PatchVertices does:
|
||||
// when a program has an evaluation stage and no control stage, both are compiled into the
|
||||
// synthesized pass-through control stage, so two draws that differ only in a level need
|
||||
// different pipelines. Hashed over the RAW BITS so a NaN level - which glPatchParameterfv
|
||||
// accepts - keys to itself. Six extra words on a path that only recomputes when the
|
||||
// pipeline-state version moved.
|
||||
for (Uint32 i = 0; i < 4; ++i) {
|
||||
hash = CombinePipelineStateWord(hash,
|
||||
static_cast<Uint64>(std::bit_cast<Uint32>(p.PatchDefaultOuterLevel[i])));
|
||||
}
|
||||
for (Uint32 i = 0; i < 2; ++i) {
|
||||
hash = CombinePipelineStateWord(hash,
|
||||
static_cast<Uint64>(std::bit_cast<Uint32>(p.PatchDefaultInnerLevel[i])));
|
||||
}
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(p.PolygonModeFront));
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(p.CullFaceModeSetting));
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(p.DepthFunc));
|
||||
hash = CombinePipelineStateWord(hash, static_cast<Uint64>(p.LogicOp));
|
||||
// StencilStates[0] is Front, [1] is Back (RenderState::GetStencilFaceIndex) -
|
||||
// the same order the two GetStencilState(face) calls used to hash in.
|
||||
for (const StencilFaceState& stencil : p.StencilStates) {
|
||||
hash = CombinePipelineStateWord(hash,
|
||||
static_cast<Uint64>(stencil.FailOp) |
|
||||
(static_cast<Uint64>(stencil.PassDepthPassOp) << 16) |
|
||||
(static_cast<Uint64>(stencil.PassDepthFailOp) << 32) |
|
||||
(static_cast<Uint64>(stencil.Func) << 48));
|
||||
}
|
||||
MOBILEGL_ASSERT(colorAttachmentCount <= p.BlendStates.size(),
|
||||
"ComputePipelineStateHash: colorAttachmentCount %u exceeds MAX_DRAW_BUFFERS",
|
||||
colorAttachmentCount);
|
||||
for (Uint32 i = 0; i < colorAttachmentCount; ++i) {
|
||||
const PerBufferBlendState& blend = p.BlendStates[i];
|
||||
const BoolVec4 mask = p.ColorMasks[m_independentBlendFeatureEnabled ? i : 0];
|
||||
Uint64 attachmentWord = blend.Enabled ? 1ull : 0;
|
||||
attachmentWord |= (mask.r() ? 1ull << 1 : 0) | (mask.g() ? 1ull << 2 : 0) |
|
||||
(mask.b() ? 1ull << 3 : 0) | (mask.a() ? 1ull << 4 : 0);
|
||||
attachmentWord |= static_cast<Uint64>(blend.SrcFactorRGB) << 8;
|
||||
attachmentWord |= static_cast<Uint64>(blend.DstFactorRGB) << 16;
|
||||
attachmentWord |= static_cast<Uint64>(blend.SrcFactorAlpha) << 24;
|
||||
attachmentWord |= static_cast<Uint64>(blend.DstFactorAlpha) << 32;
|
||||
attachmentWord |= static_cast<Uint64>(blend.ColorEquation) << 40;
|
||||
attachmentWord |= static_cast<Uint64>(blend.AlphaEquation) << 48;
|
||||
hash = CombinePipelineStateWord(hash, attachmentWord);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
#endif // MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH && !MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
Uint64 VulkanRenderer::ComputePipelineSubsetStateHashFallback() const {
|
||||
// The client's own hash, over the client's own definition of the pipeline subset - the
|
||||
// seven pipeline chunks of the P2 chunk table, which is a strict SUPERSET of what
|
||||
@@ -5421,7 +5316,6 @@ void main() {
|
||||
// arm to fall back to instead.
|
||||
return MG_Pipe::MGPipeComputePipelineSubsetHash(MGB_CTX->GetRenderStateParameters());
|
||||
}
|
||||
#endif
|
||||
|
||||
// A program that runs a geometry shader AND captures transform feedback. Both halves are
|
||||
// link-time properties, so this is safe to fold into a pipeline keyed on the program hash.
|
||||
@@ -5529,7 +5423,6 @@ void main() {
|
||||
// per-draw state flips (GL_BLEND toggles) would otherwise miss entries the memo holds.
|
||||
// The version only guards recomputing the hash - unchanged version, unchanged bytes.
|
||||
const Uint renderStateVersion = MGB_CTX->GetPipelineStateVersion();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.1. Non-null means the client's render-state CSO handle is this draw's state
|
||||
// key and the hash below is not computed at all; null means the pre-handle arm. The
|
||||
// two arms' entries can never match each other: the handle arm stores hash 0 and a
|
||||
@@ -5544,22 +5437,6 @@ void main() {
|
||||
: ResolveFallbackPipelineStateHash(renderStateVersion,
|
||||
renderPassEntry.colorAttachmentCount,
|
||||
renderPassEntry.sampleCount);
|
||||
#else
|
||||
// THE PULL BUILD'S TEXT, statement for statement what the base ref has: G1 admits no
|
||||
// resize of this function, and a helper the compiler merely inlines is not the same
|
||||
// instruction schedule.
|
||||
if (!m_pipelineStateHashValid || m_pipelineStateHashVersion != renderStateVersion ||
|
||||
m_pipelineStateHashColorCount != renderPassEntry.colorAttachmentCount ||
|
||||
m_pipelineStateHashSampleCount != renderPassEntry.sampleCount) {
|
||||
m_pipelineStateHash =
|
||||
ComputePipelineStateHash(renderPassEntry.colorAttachmentCount, renderPassEntry.sampleCount);
|
||||
m_pipelineStateHashVersion = renderStateVersion;
|
||||
m_pipelineStateHashColorCount = renderPassEntry.colorAttachmentCount;
|
||||
m_pipelineStateHashSampleCount = renderPassEntry.sampleCount;
|
||||
m_pipelineStateHashValid = true;
|
||||
}
|
||||
const Uint64 pipelineStateHash = m_pipelineStateHash;
|
||||
#endif
|
||||
for (Uint32 i = 0; i < m_pipelineMemoCount; ++i) {
|
||||
const PipelineMemoEntry& entry = m_pipelineMemo[i];
|
||||
if (entry.pipeline != VK_NULL_HANDLE && entry.mode == mode &&
|
||||
@@ -5569,9 +5446,7 @@ void main() {
|
||||
entry.wireRenderPassCompatibilityId == wireRenderPassCompatibilityId &&
|
||||
#endif
|
||||
entry.pipelineStateHash == pipelineStateHash &&
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
entry.renderStateCso == renderStateCso &&
|
||||
#endif
|
||||
entry.primitiveRestartEnable == primitiveRestartEnable &&
|
||||
entry.transformFlags == transformFlags) {
|
||||
if (MG_Util::PipeStats::Enabled()) {
|
||||
@@ -6311,9 +6186,7 @@ void main() {
|
||||
entry.wireRenderPassCompatibilityId = wireRenderPassCompatibilityId;
|
||||
#endif
|
||||
entry.pipelineStateHash = pipelineStateHash;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
entry.renderStateCso = renderStateCso;
|
||||
#endif
|
||||
entry.primitiveRestartEnable = primitiveRestartEnable;
|
||||
entry.transformFlags = transformFlags;
|
||||
entry.pipeline = pipeline;
|
||||
@@ -6771,7 +6644,6 @@ void main() {
|
||||
// draw of a VAO-cycling stream (Minecraft chunk rendering) through the full
|
||||
// path, re-resolving descriptors and texture layouts nothing invalidated.
|
||||
const auto& vao = *MGB_CTX->GetBoundVertexArray();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.4: the handle replaces the (address, lifetime id) pair here too - one
|
||||
// compare instead of two, and the same identity the VAO draw memo is keyed on, so
|
||||
// the two cannot disagree about whether "the VAO moved". The config version stays:
|
||||
@@ -6783,11 +6655,6 @@ void main() {
|
||||
: (static_cast<const void*>(&vao) != snap.vao ||
|
||||
vao.GetLifetimeId() != snap.vaoLifetimeId ||
|
||||
vao.GetConfigVersion() != snap.vaoConfigVersion);
|
||||
#else
|
||||
const Bool vaoMoved =
|
||||
static_cast<const void*>(&vao) != snap.vao || vao.GetLifetimeId() != snap.vaoLifetimeId ||
|
||||
vao.GetConfigVersion() != snap.vaoConfigVersion;
|
||||
#endif
|
||||
const auto& drawFbo =
|
||||
MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject();
|
||||
if (static_cast<const void*>(drawFbo.get()) != snap.drawFbo ||
|
||||
@@ -7013,7 +6880,6 @@ void main() {
|
||||
// what lets a per-draw GL_BLEND toggle alternate between two memo entries
|
||||
// instead of missing forever on a monotonic version. A miss falls through
|
||||
// to the full lookup.
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Same arm selector as GetOrCreatePipeline's probe (P2 D12.1); this site is the
|
||||
// fast path's copy of it, and the two must key identically or the fast path would
|
||||
// hand back a pipeline the full path would not have matched.
|
||||
@@ -7023,20 +6889,6 @@ void main() {
|
||||
? 0
|
||||
: ResolveFallbackPipelineStateHash(renderStateVersion, snap.renderPassColorCount,
|
||||
snap.renderPassSampleCount);
|
||||
#else
|
||||
// The pull build's text, statement for statement (see GetOrCreatePipeline).
|
||||
if (!m_pipelineStateHashValid || m_pipelineStateHashVersion != renderStateVersion ||
|
||||
m_pipelineStateHashColorCount != snap.renderPassColorCount ||
|
||||
m_pipelineStateHashSampleCount != snap.renderPassSampleCount) {
|
||||
m_pipelineStateHash =
|
||||
ComputePipelineStateHash(snap.renderPassColorCount, snap.renderPassSampleCount);
|
||||
m_pipelineStateHashVersion = renderStateVersion;
|
||||
m_pipelineStateHashColorCount = snap.renderPassColorCount;
|
||||
m_pipelineStateHashSampleCount = snap.renderPassSampleCount;
|
||||
m_pipelineStateHashValid = true;
|
||||
}
|
||||
const Uint64 pipelineStateHash = m_pipelineStateHash;
|
||||
#endif
|
||||
const auto memoTransformFlags =
|
||||
ProgramFactory::CompileOptionFlags(snap.resolvedTransformFlags);
|
||||
for (Uint32 i = 0; i < m_pipelineMemoCount; ++i) {
|
||||
@@ -7048,9 +6900,7 @@ void main() {
|
||||
entry.wireRenderPassCompatibilityId == 0 &&
|
||||
#endif
|
||||
entry.pipelineStateHash == pipelineStateHash &&
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
entry.renderStateCso == renderStateCso &&
|
||||
#endif
|
||||
entry.primitiveRestartEnable == drawPrimitiveRestartEnable &&
|
||||
entry.transformFlags == memoTransformFlags) {
|
||||
pipeline = entry.pipeline;
|
||||
@@ -7084,7 +6934,6 @@ void main() {
|
||||
snap.bindGeneration = bindGeneration;
|
||||
snap.vao = static_cast<const void*>(&vao);
|
||||
snap.vaoLifetimeId = vao.GetLifetimeId();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Guarded by the SUBSYSTEM, not only by the build switch: with bit 6 clear the field
|
||||
// is dead (vaoMoved takes the address/lifetime-id branch), and minting a handle for it
|
||||
// would put this package's cost inside MOBILEGL_PIPE_PUSH=0 - the all-pull control arm
|
||||
@@ -7092,7 +6941,6 @@ void main() {
|
||||
if (MagmaPipeTrackHArmIsHandles(MG_Pipe::kMGPipeSubsystemMagmaVertexInput)) {
|
||||
snap.vaoHandle = ResolveVaoHandle(vao);
|
||||
}
|
||||
#endif
|
||||
snap.vaoConfigVersion = vao.GetConfigVersion();
|
||||
snap.vaoLayoutHash = vaoLayoutHash;
|
||||
snap.pipeline = pipeline;
|
||||
@@ -7697,13 +7545,11 @@ void main() {
|
||||
snap.programVersion = program.GetBackendStateVersion();
|
||||
snap.vao = &vao;
|
||||
snap.vaoLifetimeId = vao.GetLifetimeId();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Subsystem-guarded for the same reason as the other stamping site: the field
|
||||
// is dead with bit 6 clear, and MOBILEGL_PIPE_PUSH=0 has to be P1 exactly.
|
||||
if (MagmaPipeTrackHArmIsHandles(MG_Pipe::kMGPipeSubsystemMagmaVertexInput)) {
|
||||
snap.vaoHandle = ResolveVaoHandle(vao);
|
||||
}
|
||||
#endif
|
||||
snap.vaoConfigVersion = vao.GetConfigVersion();
|
||||
snap.drawFbo = drawFbo.get();
|
||||
snap.drawFboLifetimeId = drawFbo->GetLifetimeId();
|
||||
@@ -12634,13 +12480,9 @@ void main() {
|
||||
// have happened, so the buffer is also flagged for the wait that a later CPU
|
||||
// read has to perform - the capture is a GPU write like any shader's.
|
||||
bufferObject->EnsureGpuResidentStorage();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P5c ev (R2, CONTRACT-P5C §4.2): through the reverse channel, not a direct poke
|
||||
// of the client object from the apply thread.
|
||||
MG_Pipe::MGPipeAnnounceBufferGpuWritten(bufferObject);
|
||||
#else
|
||||
bufferObject->MarkGpuWritten();
|
||||
#endif
|
||||
BufferSlice slice{};
|
||||
if (!m_bufferManager.AcquireResidentSlice(BufferKind::Vertex, bufferObject, slice)) {
|
||||
MGLOG_E_ONCE("BeginXfbCaptureForDraw: failed to acquire capture buffer %zu", i);
|
||||
@@ -14109,14 +13951,12 @@ void main() {
|
||||
if (m_vertexInputStateFactory) {
|
||||
m_vertexInputStateFactory->OnFrameBoundary();
|
||||
}
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// Reclaim {slot, gen} for objects that have not been drawn for a long time, on the same
|
||||
// cadence and the same retirement age as the entries those slots key. This is the
|
||||
// stand-in for the frontend death notification P2 has no hook for, and it is what keeps
|
||||
// the mint's footprint the LIVE working set rather than every object ever created
|
||||
// (review v2 MAJOR 1 / MAJOR 3).
|
||||
m_pipeIdentity.OnFrameBoundary();
|
||||
#endif
|
||||
if (m_samplerManager) {
|
||||
m_samplerManager->OnFrameBoundary();
|
||||
}
|
||||
@@ -14655,9 +14495,7 @@ void main() {
|
||||
InvalidateSetupDrawSnapshots();
|
||||
}
|
||||
m_vertexInputStateFactory->OnFrameBoundary();
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
m_pipeIdentity.OnFrameBoundary();
|
||||
#endif
|
||||
m_samplerManager->OnFrameBoundary();
|
||||
auto& frame = m_frameContext.GetCurrent();
|
||||
auto* activeRenderPass = VkRenderPassManager::GetActiveRenderPass();
|
||||
|
||||
@@ -32,11 +32,9 @@
|
||||
#include <MG_Backend/BackendObject.h>
|
||||
#include <MG_Pipe/MGPipeHandles.h>
|
||||
#include <MG_Util/SelfTest/PrimitivesGeneratedNoXfbProbe.h>
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The applier's CSO store: MGPipeApplier().BoundRenderStateCso is what the pipeline memo
|
||||
// keys on after P2 (D12.1). Push-only, so the pull build's include graph is unchanged.
|
||||
#include <MG_Pipe/PipeApply.h>
|
||||
#endif
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#include "../VkIncludes.h"
|
||||
@@ -1382,7 +1380,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// never repeats, so a per-draw GL_BLEND toggle would miss all entries forever even
|
||||
// though the state alternates between two values the memo already holds.
|
||||
Uint64 pipelineStateHash = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The HANDLE arm's key component, and the whole of D12.1: the CLIENT already
|
||||
// hashed the pipeline subset of RenderStateParameters and minted a content-
|
||||
// addressed CSO for it (MG_Pipe/MGPipeRenderStateSpans.h, MG_Impl/Pipe/CsoCache),
|
||||
@@ -1400,7 +1397,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// Null in an entry minted by the legacy arm, so entries of the two arms can never
|
||||
// match each other: the compare below tests BOTH components.
|
||||
MG_Pipe::MGPipeHandle renderStateCso = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
ProgramFactory::CompileOptionFlags transformFlags = {};
|
||||
// Baked into the pipeline (PipelineFactory::ComputeHash mixes it), and NOT derivable
|
||||
// from anything else in this key: it depends on whether the draw is indexed and on the
|
||||
@@ -1415,7 +1411,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 m_pipelineMemoCount = 0;
|
||||
Uint32 m_pipelineMemoNext = 0;
|
||||
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.1's arm selector, and the whole of the pipeline memo's re-key. Returns the
|
||||
// render-state CSO this draw is keyed on, or the null handle when the pre-handle arm
|
||||
// is the one that runs.
|
||||
@@ -1500,12 +1495,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
if (!m_pipelineStateHashValid || m_pipelineStateHashVersion != renderStateVersion ||
|
||||
m_pipelineStateHashColorCount != colorAttachmentCount ||
|
||||
m_pipelineStateHashSampleCount != rasterizationSamples) {
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
m_pipelineStateHash =
|
||||
ComputePipelineStateHash(colorAttachmentCount, rasterizationSamples);
|
||||
#else
|
||||
m_pipelineStateHash = ComputePipelineSubsetStateHashFallback();
|
||||
#endif
|
||||
m_pipelineStateHashVersion = renderStateVersion;
|
||||
m_pipelineStateHashColorCount = colorAttachmentCount;
|
||||
m_pipelineStateHashSampleCount = rasterizationSamples;
|
||||
@@ -1513,8 +1503,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
return m_pipelineStateHash;
|
||||
}
|
||||
#endif // MOBILEGL_PIPE_PUSH
|
||||
#if MOBILEGL_PIPE_PUSH && !MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// The same answer as ComputePipelineStateHash, computed from the P2 chunk table
|
||||
// instead of from a hand-written field list, for the build that compiles no
|
||||
// pre-handle arm (cmake -DMOBILEGL_PIPE_LEGACY_MEMOS=OFF). It is the CLIENT's own
|
||||
@@ -1524,22 +1512,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// way. This is what makes the no-legacy build RUNNABLE rather than a configuration
|
||||
// that aborts on the first draw that arrives without a CSO.
|
||||
Uint64 ComputePipelineSubsetStateHashFallback() const;
|
||||
#endif
|
||||
#if MOBILEGL_PIPE_LEGACY_MEMOS
|
||||
// THE PRE-HANDLE ARM (P2 brief D12.1 / D14). Hash of every fixed-function GL state the
|
||||
// pipeline payload reads that the memo key's other fields (mode / program / vertex
|
||||
// input / render pass / transform flags) do not already pin down. Equal hash under an
|
||||
// equal rest of key => byte-identical PipelineCreatePayload. Cached per pipeline-state
|
||||
// version: the version is monotonic and bumps on every pipeline-state
|
||||
// change, so an unchanged (version, colorAttachmentCount) proves the state
|
||||
// bytes are unchanged and the hash can be reused without re-reading them.
|
||||
//
|
||||
// The handle arm computes none of this: the client hashed the same bytes when it
|
||||
// minted the CSO, so all five cached-hash members below exist only to avoid a
|
||||
// re-hash the handle arm never performs.
|
||||
Uint64 ComputePipelineStateHash(Uint32 colorAttachmentCount,
|
||||
VkSampleCountFlagBits rasterizationSamples) const;
|
||||
#endif
|
||||
// The effective GL_SAMPLE_MASK word for a draw at this rasterization sample count; see
|
||||
// the definition for the GL-vs-Vulkan rule it reconciles. Shared by the pipeline payload
|
||||
// and the pipeline-state memo word so the two cannot disagree. NOT part of the legacy
|
||||
@@ -1667,13 +1639,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// common shape), and "the VAO did not move" would then skip the layout
|
||||
// re-resolve for a different VAO.
|
||||
Uint64 vaoLifetimeId = 0;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.4: the handle arm's answer to the same question, and one compare rather
|
||||
// than the pair above. Kept BESIDE them rather than replacing them because the
|
||||
// pre-handle arm is still compiled (MOBILEGL_PIPE_LEGACY_MEMOS) and this snapshot
|
||||
// is a value struct, not a wire type.
|
||||
MG_Pipe::MGPipeHandle vaoHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
Uint32 vaoConfigVersion = 0;
|
||||
const void* drawFbo = nullptr;
|
||||
// Never-reused lifetime id beside the raw pointer + Uint16 version: a
|
||||
@@ -1948,13 +1918,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// - bindings revalidates per draw exactly as before (frame serial, content
|
||||
// hash, per-binding live buffer pointers and slice epochs).
|
||||
struct alignas(64) VaoDrawMemo {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// P2 D12.4: the handle arm's key, and the ONLY key it needs. {slot, gen} is an
|
||||
// identity, so the pointer-plus-lifetime-id pair below stops being a key here;
|
||||
// the slot also picks the table entry, so the address hash and the two-way probe
|
||||
// go with it. Null in an entry that has never been claimed.
|
||||
MG_Pipe::MGPipeHandle vaoHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
const MG_State::GLState::VertexArrayObject* vaoKey = nullptr;
|
||||
// The VAO's never-reused lifetime id, checked alongside vaoKey. The pointer
|
||||
// ALONE is not an identity: a deleted VAO's heap address is handed straight
|
||||
@@ -1998,7 +1966,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// (VertexInputStateFactory::m_vaoMemos) had NO capacity, so they keep having none.
|
||||
static constexpr Uint32 kVaoDrawMemoSlotCount = 2048; // power of two
|
||||
Vector<VaoDrawMemo> m_vaoDrawMemoTable;
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
// The renderer's {slot, gen} mint, shared with its VertexInputStateFactory so both
|
||||
// derive the same handle for the same VAO. Per renderer, never a process-global: a
|
||||
// global would share one table and one reclamation clock across two live contexts and
|
||||
@@ -2010,18 +1977,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
return m_pipeIdentity.HandleOf(MG_Pipe::MGPipeKind::VertexElementsCso,
|
||||
vao.GetLifetimeId());
|
||||
}
|
||||
#endif
|
||||
// "Is this VAO's content hash already memoized?", asked of whichever side owns the
|
||||
// memo (P2 D12.5). Force-inlined and defined in the class body so that the PULL
|
||||
// build's three readers keep compiling to the very same two loads they always did -
|
||||
// G1 admits no resize, and an out-of-line call here would be one.
|
||||
[[gnu::always_inline]] inline Bool VaoContentHashIfKnown(
|
||||
const MG_State::GLState::VertexArrayObject& vao, Uint64& outHash) const {
|
||||
#if MOBILEGL_PIPE_PUSH
|
||||
return m_vertexInputStateFactory->TryGetMemoizedHash(vao, outHash);
|
||||
#else
|
||||
return vao.GetBackendHashMemo(outHash);
|
||||
#endif
|
||||
}
|
||||
// Finds the slot holding `vao`, or recycles the older of its two candidate
|
||||
// slots into an empty memo keyed on `vao`. Never returns null.
|
||||
|
||||
@@ -27,8 +27,7 @@
|
||||
// MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG (Defines.h); the verify CI build is
|
||||
// Release/INFO with MOBILEGL_BUILD_DISAGGREGATED=OFF, so the third arm is what arms the poison
|
||||
// there without dragging MG_Remote in.
|
||||
#if MOBILEGL_PIPE_PUSH && (MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG || MOBILEGL_BUILD_DISAGGREGATED || \
|
||||
MOBILEGL_PIPE_VERIFY)
|
||||
#if (MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG || MOBILEGL_BUILD_DISAGGREGATED || MOBILEGL_PIPE_VERIFY)
|
||||
#define MOBILEGL_PIPE_POISON 1
|
||||
#else
|
||||
#define MOBILEGL_PIPE_POISON 0
|
||||
|
||||
Reference in New Issue
Block a user