diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp index a2f6f4f1..446fd954 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.cpp @@ -19,7 +19,6 @@ #include #include #include -#if MOBILEGL_PIPE_PUSH // P3a: the applier's vertex-input records the re-keyed draw-buffer memo is validated against. #include // P5c ev: the surface-changed event's producer callback, installed by the server session. @@ -29,7 +28,6 @@ // The draw path's attribute-values sync reads Archive->Link, so this TU needs it complete - // Managers.cpp already includes it for ProgramArchiveSource, which is the same reason. #include -#endif #if MOBILEGL_BUILD_DISAGGREGATED // P5c (tx): §1's server-side per-level extent derivation, for GenerateMipmap's shape reads. #include @@ -106,85 +104,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static SharedPtr g_rawDepthFetchSamplerState; static SharedPtr g_rawDepthFetchSamplerBackend; -#if MOBILEGL_PIPE_LEGACY_MEMOS - // Two objects are the same binding iff they share a control block. Raw addresses lie - // (a freed object's heap slot is reused), but a held weak_ptr pins the control block, - // so no later object can ever owner-equal a snapshot of its predecessor. - // - // This is the pre-handle identity mechanism, and it is compiled only for the legacy arm. - // On the {slot, gen} arm nothing needs it: a handle already cannot be reproduced by a - // recycled address, so there is no snapshot to owner-compare. - template - static Bool OwnerEquals(const WeakPtr& snapshot, const SharedPtr& current) { - return !snapshot.owner_before(current) && !current.owner_before(snapshot); - } - - // Owner-keyed direct-mapped memo over a StateBackendObjectRegistry, for the object - // kinds the draw path re-Finds every draw (VAO, program). A hit replaces the - // registry's hash-map Find with one array index plus an owner-equality compare. - // - // Why the raw twin pointer is safe to hand back: the twin is owned by the registry - // entry's SharedPtr, and a LIVE state object's entry is never erased nor has its - // twin replaced once set — Find and CollectGarbage erase only expired entries, - // GetOrCreate resets the twin only when the previous owner at that address expired, - // and the sync paths create a twin only when the slot is null. Owner-equality of - // the weak snapshot with the live frontend therefore proves the memoed pointer is - // still that frontend's registered twin. A recycled heap address fails the - // owner-equality (the weak snapshot pins the predecessor's control block), and a - // slot collision merely falls back to the registry Find. Nothing here needs an - // explicit invalidation hook: registry entries survive ES-context loss (twins - // re-sync via their own generation gates), matching the Find they replace. - template - class TwinLookupMemo { - public: - BackendObject* Lookup(const SharedPtr& stateObj) const { - const Slot& slot = m_slots[IndexFor(stateObj.get())]; - if (slot.key == stateObj.get() && slot.twin != nullptr && OwnerEquals(slot.owner, stateObj)) { - return slot.twin; - } - return nullptr; - } - - void Store(const SharedPtr& stateObj, BackendObject* twin) { - Slot& slot = m_slots[IndexFor(stateObj.get())]; - slot.key = stateObj.get(); - slot.owner = stateObj; - slot.twin = twin; - } - - private: - struct Slot { - StateObject* key = nullptr; - WeakPtr owner; - BackendObject* twin = nullptr; - }; - - static SizeT IndexFor(const StateObject* ptr) { - // Fibonacci hashing: heap addresses share alignment zeros and arena locality; - // the multiply spreads them before the top bits pick the slot. - const Uint64 h = reinterpret_cast(ptr) * 0x9E3779B97F4A7C15ull; - return static_cast(h >> (64u - kIndexBits)); - } - - Array m_slots; - }; - - // 4096 slots (128 KiB, sparse-touched): Minecraft-shaped workloads cycle hundreds - // of section VAOs per frame (the driver bench cycles 512), and a colliding pair - // ping-pongs back onto the hash Find every frame — at 512 keys the expected - // collided fraction is ~12% here vs ~22% at 2048. Programs are far fewer; 256 - // slots is plenty. - static TwinLookupMemo - g_vaoTwinLookupMemo; - static TwinLookupMemo - g_programTwinLookupMemo; - // Framebuffers qualify for the same memo (see the class comment's registry - // invariants: g_backendFramebufferObjects only GetOrCreate-resets an expired - // owner's twin and never erases/replaces a live one). Apps bind a handful of - // FBOs; 64 slots is plenty. - static TwinLookupMemo - g_fboTwinLookupMemo; -#endif // MOBILEGL_PIPE_LEGACY_MEMOS // Cached addresses of the frontend's framebuffer binding slots. The frontend // getter linear-scans its slot array per call and the draw path asks for these @@ -197,10 +116,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // exactly the pointer compare below. using FbBindingSlot = std::remove_reference_tGetFramebufferBindingSlot(FramebufferTarget::Draw))>; -#if !MOBILEGL_PIPE_PUSH || MOBILEGL_PIPE_LEGACY_MEMOS - static const void* g_fbSlotCacheContext = nullptr; - static Array g_fbSlotCache = {}; -#endif // P2 step e4. On the {slot, gen} arm this is an ORDINARY read of pushed state and the cache // above is not consulted, which closes the P1 accessor bypass: the cached raw pointer ran // the checked accessor once per context change and then handed out the pointee forever, so @@ -216,56 +131,13 @@ namespace MobileGL::MG_Backend::DirectGLES { // the pull build MGB_CTX is the live GLContext, there is no poison to bypass and the // frontend getter still linear-scans, so the cache is exactly the code it was. static inline FbBindingSlot& GetFramebufferBindingSlotChecked(FramebufferTarget target) { -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { return MGB_CTX->GetFramebufferBindingSlot(target); } -#endif -#if !MOBILEGL_PIPE_PUSH || MOBILEGL_PIPE_LEGACY_MEMOS - const void* ctx = MGB_CTX_IDENTITY; -#if MOBILEGL_PIPE_PUSH - // `st` (CONTRACT-P6 3.4): THE NAMED FATAL PipeInputs.h ALREADY ASKED FOR. - // - // This memo compares the identity FIRST and with NO GENERATION, and its cache variable - // starts at nullptr - so an identity that is ALSO nullptr reads as a CACHE HIT and the - // function returns `*g_fbSlotCache[target]`, a pointer nothing ever filled. The crash - // that follows names neither the memo nor the identity. - // - // It is reachable exactly when a process runs this legacy arm with an unset identity, - // which is what a spawn server used to be: MGPipeServerBlockNoteIdentity early-returned - // on the REHEARSAL knob, so the server's block carried nullptr for the life of the - // process. `sm` widened that gate to MGPipeBlocksAreDistinct() and closed the hole; this - // says so out loud if it ever reopens, because a silent wrong answer here is - // indistinguishable from memory corruption three frames later. - // - // Under MOBILEGL_PIPE_PUSH only: in a pull build MGB_CTX_IDENTITY is the live - // GLContext's address, which is non-null on every path that reaches here, so the test - // would be dead code and G1 measures dead code. - if (ctx == nullptr) { - MGLOG_F("MGPipe: Fatal{UnnamedIdentity, \"FbSlotMemo\"} - the framebuffer binding-slot " - "memo was consulted with a NULL context identity. Its cache starts null too, " - "so this would have read as a hit and returned a slot pointer that was never " - "filled. The identity is set by MGPipeServerBlockNoteIdentity, which arms on " - "MGPipeBlocksAreDistinct(); a null here means this process runs the legacy " - "memo arm with a block nobody claimed (CONTRACT-P6 3.4)."); - std::abort(); - } -#endif - if (ctx != g_fbSlotCacheContext) { - auto& live = *MGB_CTX; - for (SizeT i = 0; i < g_fbSlotCache.size(); ++i) { - g_fbSlotCache[i] = &live.GetFramebufferBindingSlot(static_cast(i)); - } - g_fbSlotCacheContext = ctx; - } - return *g_fbSlotCache[SizeT(target)]; -#else // No legacy arm compiled: EsprytSlotTablesEnabled() is unconditionally true above. return MGB_CTX->GetFramebufferBindingSlot(target); -#endif } -#if MOBILEGL_PIPE_PUSH // A4, TAKEN AT THE VERIFICATION ROUND, AND THE FOUR TEMPORARY LATCHES ARE GONE WITH IT. // This package landed BEFORE D and so carried its own bit tests, plus a copy of D-K2's // dependency directions, so that a half-running mask was refused in the meantime too. @@ -329,7 +201,6 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Pipe::gPipeInputs.CurrentVerb()); } #endif // MOBILEGL_BUILD_DISAGGREGATED -#endif // MOBILEGL_PIPE_PUSH static Bool IsDualSourceBlendFactor(BlendFactor v) { switch (v) { @@ -955,14 +826,10 @@ namespace MobileGL::MG_Backend::DirectGLES { for (SizeT i = 0; i < bindingPointCnt; ++i) { const auto& obj = MGB_CTX->GetBufferBindingPoint(BufferTarget::ShaderStorage, i).GetBoundObject(); -#if MOBILEGL_PIPE_PUSH // P3a (D-D): announced on the reverse channel on the handle arm, poked into // the object on the legacy one. MarkBufferGpuWritten is the one place that // decides, so the three announcement sites stay one line each. MarkBufferGpuWritten(obj); -#else - if (obj) obj->MarkGpuWritten(); -#endif } } @@ -1072,11 +939,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // conformance case reads the result back with glMapBufferRange or // glGetBufferSubData - which serve the frontend's CPU shadow until the buffer is // flagged (BufferObject::SyncGpuWrites), exactly as for a storage buffer. -#if MOBILEGL_PIPE_PUSH MarkBufferGpuWritten(obj); -#else - obj->MarkGpuWritten(); -#endif } } @@ -1098,7 +961,6 @@ namespace MobileGL::MG_Backend::DirectGLES { BindBufferId(glTarget, backendResource->id); } -#if MOBILEGL_PIPE_PUSH // The handle arm of the resolved-draw-buffers memo (D-G4). Two substitutions and // nothing else: // @@ -1304,7 +1166,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } #endif // MOBILEGL_BUILD_DISAGGREGATED -#endif // MOBILEGL_PIPE_PUSH // `vaoConfigVersion` is the caller's early read of currentVAOObject->GetConfigVersion(): // the VAO's config fields live on a cache line the draw path touches nowhere else, and @@ -1358,11 +1219,9 @@ namespace MobileGL::MG_Backend::DirectGLES { SyncVaoAttributeBuffersByRecord(memo, bufferEpoch); } else #endif -#if MOBILEGL_PIPE_PUSH if (VertexInputSubsystemEnabled()) { SyncVaoAttributeBuffersByHandle(currentVAOObject, memo, bufferEpoch); } else -#endif if (memo && memo->valid && memo->configVersion == configVersion) { if (memo->vboCleanEpoch != bufferEpoch) { Bool allClean = true; @@ -1473,7 +1332,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // rebind another buffer with no epoch (and no config-version) move, // so the identity compare always runs; only the clean PROBE is // elided while the stamp holds. -#if MOBILEGL_PIPE_PUSH if (ResourceSubsystemEnabled()) { // Same three cases, with the identity re-keyed off the raw frontend // address onto the resource's {slot, gen} (D-G4). @@ -1495,7 +1353,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } } else -#endif if (memo && memo->iboFrontend == possibleIBO.get() && memo->iboCleanEpoch == bufferEpoch) { // probed fully clean at this epoch; nothing can have dirtied it } else if (memo && memo->iboFrontend == possibleIBO.get() && @@ -2497,7 +2354,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { // No memo on this arm. The memo existed to turn the registry's hash probe into // an array index; the slot table's Find already IS the array index, and the @@ -2510,21 +2366,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } return backendObj.get(); } -#endif -#if MOBILEGL_PIPE_LEGACY_MEMOS - if (auto* twin = g_vaoTwinLookupMemo.Lookup(vao)) { - return twin; - } - auto* backendVAOSlot = g_backendVertexArrayObjects.Find(vao.get()); - auto& backendObj = backendVAOSlot ? *backendVAOSlot : g_backendVertexArrayObjects.GetOrCreate(vao); - if (!backendObj) { - backendObj = MakeShared(); - } - g_vaoTwinLookupMemo.Store(vao, backendObj.get()); - return backendObj.get(); -#else return nullptr; -#endif } void SyncCurrentVAO(const SharedPtr& currentVAOObject, @@ -2938,7 +2780,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } -#if MOBILEGL_PIPE_PUSH // P5e (pa), CONTRACT-P5E §5.5 / §5.8 (ruling ID-81): THE SAME SYNC, OFF THE RECORD. // // The overload above is the MONOLITH GLUE and keeps its text token for token; this one is @@ -3105,7 +2946,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } } -#endif } // namespace VertexArrayImpl namespace TextureImpl { @@ -3161,7 +3001,6 @@ namespace MobileGL::MG_Backend::DirectGLES { backendObj->SyncBuiltinSamplerToBackend(textureObject); } -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { // One re-resolve, and only because a nested GetOrCreate may have GROWN the // vector and moved the element; the entry itself cannot have been erased, since @@ -3182,7 +3021,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return repaired; } -#endif auto* refreshedSlot = g_backendTextureObjects.Find(textureObject.get()); auto& refreshedBackendObj = refreshedSlot ? *refreshedSlot : g_backendTextureObjects.GetOrCreate(textureObject); @@ -3209,7 +3047,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // * everything unit bindings say nothing about: the touched-unit high-water mark, // the frontend context identity, the backend ES context generation, and (for the // resolution memo) the program keys that arbitrate aliased targets. -#if MOBILEGL_PIPE_PUSH // P2: the snapshot stops holding weak_ptrs and holds the frontend objects' LIFETIME IDs. // The weak_ptr was here for one reason - a raw address lies once the allocator recycles // it - and a lifetime id is a monotone per-class counter that is never handed out twice, @@ -3231,12 +3068,6 @@ namespace MobileGL::MG_Backend::DirectGLES { struct UnitBindingsSnapshot { Array slotObjects{}; Uint64 samplerObject = 0; -#if MOBILEGL_PIPE_LEGACY_MEMOS - // P1's identity, kept verbatim for the legacy arm only. - Array, (SizeT)TextureTarget::TextureTargetCount> - legacySlotObjects{}; - WeakPtr legacySamplerObject{}; -#endif }; static Uint64 LifetimeIdOf(const SharedPtr& object) { @@ -3247,11 +3078,7 @@ namespace MobileGL::MG_Backend::DirectGLES { return object ? object->GetLifetimeId() : 0; } -#if MOBILEGL_PIPE_LEGACY_MEMOS -#define MGB_UNIT_BINDINGS_HANDLE_ARM (EsprytSlotTablesEnabled()) -#else #define MGB_UNIT_BINDINGS_HANDLE_ARM (true) -#endif static void CaptureUnitBindings(Int maxTouchedUnit, Vector& out) { const Bool handleArm = MGB_UNIT_BINDINGS_HANDLE_ARM; @@ -3264,20 +3091,10 @@ namespace MobileGL::MG_Backend::DirectGLES { if (handleArm) { snapshot.slotObjects[i] = LifetimeIdOf(slots[i].GetBoundObject()); } -#if MOBILEGL_PIPE_LEGACY_MEMOS - else { - snapshot.legacySlotObjects[i] = slots[i].GetBoundObject(); - } -#endif } if (handleArm) { snapshot.samplerObject = LifetimeIdOf(textureUnit.GetSamplerObject()); } -#if MOBILEGL_PIPE_LEGACY_MEMOS - else { - snapshot.legacySamplerObject = textureUnit.GetSamplerObject(); - } -#endif } } @@ -3292,58 +3109,14 @@ namespace MobileGL::MG_Backend::DirectGLES { if (handleArm) { if (snapshot.slotObjects[i] != LifetimeIdOf(slots[i].GetBoundObject())) return false; } -#if MOBILEGL_PIPE_LEGACY_MEMOS - else if (!OwnerEquals(snapshot.legacySlotObjects[i], slots[i].GetBoundObject())) { - return false; - } -#endif } if (handleArm) { if (snapshot.samplerObject != LifetimeIdOf(textureUnit.GetSamplerObject())) return false; } -#if MOBILEGL_PIPE_LEGACY_MEMOS - else if (!OwnerEquals(snapshot.legacySamplerObject, textureUnit.GetSamplerObject())) { - return false; - } -#endif } return true; } #undef MGB_UNIT_BINDINGS_HANDLE_ARM -#else - struct UnitBindingsSnapshot { - Array, (SizeT)TextureTarget::TextureTargetCount> - slotObjects{}; - WeakPtr samplerObject{}; - }; - - static void CaptureUnitBindings(Int maxTouchedUnit, Vector& out) { - out.resize(static_cast(maxTouchedUnit + 1)); - for (Int unit = 0; unit <= maxTouchedUnit; ++unit) { - auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit); - auto& snapshot = out[static_cast(unit)]; - const auto& slots = textureUnit.GetAllBindingSlots(); - for (SizeT i = 0; i < slots.size(); ++i) { - snapshot.slotObjects[i] = slots[i].GetBoundObject(); - } - snapshot.samplerObject = textureUnit.GetSamplerObject(); - } - } - - static Bool UnitBindingsUnchanged(Int maxTouchedUnit, const Vector& snapshots) { - if (snapshots.size() != static_cast(maxTouchedUnit + 1)) return false; - for (Int unit = 0; unit <= maxTouchedUnit; ++unit) { - auto& textureUnit = MGB_CTX->GetTextureUnitObject(unit); - const auto& snapshot = snapshots[static_cast(unit)]; - const auto& slots = textureUnit.GetAllBindingSlots(); - for (SizeT i = 0; i < slots.size(); ++i) { - if (!OwnerEquals(snapshot.slotObjects[i], slots[i].GetBoundObject())) return false; - } - if (!OwnerEquals(snapshot.samplerObject, textureUnit.GetSamplerObject())) return false; - } - return true; - } -#endif static Vector g_observedUnitBindings; static Uint64 g_observedUnitBindingsContextId = 0; @@ -3361,7 +3134,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // a context switch, a high-water-mark move or a bindings change each recapture and // bump - so epoch equality alone proves the bindings a consumer resolved against // are the bindings on the units now. -#if MOBILEGL_PIPE_PUSH // P4a e2 (D-G1). THE UNIT-BINDINGS EPOCH DERIVATION, REPLACED BY THE RECORDS' SERIALS. // // CurrentUnitBindingsEpoch below exists to answer one question - "did WHAT the touched @@ -3457,10 +3229,8 @@ namespace MobileGL::MG_Backend::DirectGLES { out = mixed; return true; } -#endif static Uint64 CurrentUnitBindingsEpoch(Int maxTouchedUnit) { -#if MOBILEGL_PIPE_PUSH // P4a decline-site T1: M - the mask says this family is not switched on, and it // IS D's SamplerSubsystemEnabled() now. Silent, confirmed at the verification // round: the mask's word is the one thing a decline may be quiet about. @@ -3487,7 +3257,6 @@ namespace MobileGL::MG_Backend::DirectGLES { /*hit=*/false); } } -#endif const Uint64 contextId = MGB_CTX->GetTextureContextId(); const Uint64 bindGeneration = MGB_CTX->GetTextureBindGeneration(); if (MG_Util::PipeStats::Enabled()) { @@ -3606,7 +3375,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static Uint64 g_unitTextureSyncListEpoch = 0; static Uint64 g_unitTextureSyncListSamplingGeneration = 0; -#if MOBILEGL_PIPE_PUSH // P5e (fb, CONTRACT-P5E.md §5.4): THE TWO ATTACHMENT LISTS GET AN ENTRY OF THEIR OWN, // and it borrows nothing. // @@ -3629,7 +3397,6 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Pipe::MGPipeHandle Res = MG_Pipe::kMGPipeNullHandle; BackendTextureObject* backend = nullptr; }; -#endif // Sibling memo for the draw FBO's texture attachments (see the use site in // SyncNeccessaryTextures for the key derivation and the borrow rules, which are the @@ -3640,7 +3407,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static Uint16 g_fboTextureSyncListObjectVersion = 0; static Uint64 g_fboTextureSyncListContextId = 0; static Uint g_fboTextureSyncListContextGeneration = 0; -#if MOBILEGL_PIPE_PUSH // P4a e2. The record-keyed half of the same memo. The draw framebuffer record's // ContentHash replaces the two VERSION halves of the key - the hash is taken over // every field the record carries, so an attachment edit always moves it, and Fbo is @@ -3707,7 +3473,6 @@ namespace MobileGL::MG_Backend::DirectGLES { add(record.Depth); add(record.Stencil); } -#endif // The frontend texture-state keys the per-draw texture stages // (SyncNeccessaryTextures, then BindCurrentTextures) both consume. Captured @@ -3749,7 +3514,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return keys; } -#if MOBILEGL_PIPE_PUSH // P4a e2 (D-E3). The READ framebuffer's texture attachments, and why this exists. // // A texture that is an attachment of the READ framebuffer ONLY reaches @@ -3922,7 +3686,6 @@ namespace MobileGL::MG_Backend::DirectGLES { g_readFboTextureSyncListContentHash = contentHash; g_readFboTextureSyncListRecordKeyed = recordKeyed; } -#endif // MOBILEGL_PIPE_PUSH void SyncNeccessaryTextures(const DrawTextureSyncKeys& keys) { #ifdef TRACY_ENABLE @@ -4070,7 +3833,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // registry keeps a backend object alive until its frontend texture expires, which an // attached texture cannot. A renderbuffer-only FBO - the common Minecraft frame - // reduces to the key compare and an empty loop. -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5e (fb): under a transport with the framebuffer bit set, BOTH attachment lists // are answered from the two records and neither binding slot is touched. The // pre-handle pair below stays compiled and stays the monolith path (ruling 1). @@ -4084,7 +3847,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (currentFBO) { const Uint16 fboSlotVersion = drawSlot.GetVersion(); const Uint16 fboObjectVersion = currentFBO->GetObjectVersion(); -#if MOBILEGL_PIPE_PUSH Bool fboRecordKeyed = false; Uint64 fboContentHash = 0; // P4a decline-site F8 (draw list): K - a memo-KEY selection, not a decline; see @@ -4096,19 +3858,13 @@ namespace MobileGL::MG_Backend::DirectGLES { fboContentHash = drawRecord->ContentHash; } } -#endif const Bool fboListValid = g_fboTextureSyncListFbo == currentFBO.get() && -#if MOBILEGL_PIPE_PUSH g_fboTextureSyncListRecordKeyed == fboRecordKeyed && (fboRecordKeyed ? g_fboTextureSyncListContentHash == fboContentHash : (g_fboTextureSyncListSlotVersion == fboSlotVersion && g_fboTextureSyncListObjectVersion == fboObjectVersion)) && -#else - g_fboTextureSyncListSlotVersion == fboSlotVersion && - g_fboTextureSyncListObjectVersion == fboObjectVersion && -#endif g_fboTextureSyncListContextId == keys.contextId && g_fboTextureSyncListContextGeneration == g_backendContextGeneration && PairingsIntact(g_fboTextureSyncList); @@ -4139,21 +3895,17 @@ namespace MobileGL::MG_Backend::DirectGLES { g_fboTextureSyncListObjectVersion = fboObjectVersion; g_fboTextureSyncListContextId = keys.contextId; g_fboTextureSyncListContextGeneration = g_backendContextGeneration; -#if MOBILEGL_PIPE_PUSH g_fboTextureSyncListContentHash = fboContentHash; g_fboTextureSyncListRecordKeyed = fboRecordKeyed; -#endif } } else { g_fboTextureSyncListFbo = nullptr; g_fboTextureSyncList.clear(); } -#if MOBILEGL_PIPE_PUSH // D-E3: and then the READ framebuffer's, which nothing else in this backend gives // texture parameters to. SyncReadFramebufferTextureAttachments(keys, currentFBO.get()); -#endif } void SyncNeccessaryTextures() { SyncNeccessaryTextures(CaptureDrawTextureSyncKeys()); } @@ -4223,7 +3975,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // draw-path staleness check below at one integer test. static Uint g_imageUnitHighWaterMark = 0; -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5e (fb): the eager glBindImageTexture funnel's HANDLE ARM, and it binds nothing. // // `bind_shader_image` is an unbarriered row (§2.2) whose backend entry point takes GL @@ -4344,7 +4096,6 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindImageTexture(unit, bindTextureId, level, layered, layer, access, bindFormat); } -#if MOBILEGL_PIPE_PUSH // MGPImageView::Access -> the GL token glBindImageTexture takes. The three numbers are // MGPipeValueTypes.h's, so this is a spelling change and not a second table; anything // else on the wire is Fatal{ProtocolCorruption, "ImageView.Access"} AT THE READER, @@ -4422,7 +4173,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(view.InternalFormat), static_cast(view.Level), view.Layered != 0, static_cast(view.Layer), access); } -#endif // MOBILEGL_PIPE_PUSH // The pre-handle form: the MONOLITH one, and now purely frontend. P4a e3 read the four // well-defined fields off the record HERE whenever ResolveShaderImageRecord could @@ -4516,11 +4266,7 @@ namespace MobileGL::MG_Backend::DirectGLES { auto* textureBuffer = static_cast(imageBinding.Texture.get()); const auto& bufferObject = textureBuffer->GetBufferBindingSlot().GetBoundObject(); -#if MOBILEGL_PIPE_PUSH BufferImpl::MarkBufferGpuWritten(bufferObject); -#else - if (bufferObject) bufferObject->MarkGpuWritten(); -#endif } } @@ -4532,7 +4278,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // limit raises GL_INVALID_VALUE on every dispatch. const Uint unitCount = std::min(MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS, static_cast(std::max(g_GLESCapabilities.MaxImageUnits, 0))); -#if MOBILEGL_PIPE_PUSH // P4a e3 (D-G2, D-J2), CORRECTED BY THE REVIEW'S MAJOR-1. // // THE RECORD'S WINDOW IS NOT THIS SWEEP'S MEMBERSHIP. D-J2 and PipeApply.h:461-464 @@ -4615,7 +4360,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } } -#endif #if MOBILEGL_BUILD_DISAGGREGATED // The wide pre-handle sweep reads the frontend binding of every unit, which an // apply thread may not do. Under a transport there is nothing for it to do anyway: @@ -4735,7 +4479,6 @@ namespace MobileGL::MG_Backend::DirectGLES { g_fboSyncedBackendIdGenerations[SizeT(target)] = g_attachmentBackendIdGeneration; } -#if MOBILEGL_PIPE_PUSH // P4a e1 (D-C2, D-B3). The framebuffer family's handle arm. // // THE FOUR-PART MEMO BECOMES TWO VALUES, and the halves are not symmetric. @@ -5087,7 +4830,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return true; } -#endif // MOBILEGL_PIPE_PUSH void SyncCurrentFBO() { #ifdef TRACY_ENABLE @@ -5097,7 +4839,6 @@ namespace MobileGL::MG_Backend::DirectGLES { TextureImpl::g_backendTextureObjects.CollectGarbageIfNeeded(); RenderbufferImpl::g_backendRenderbufferObjects.CollectGarbageIfNeeded(); -#if MOBILEGL_PIPE_PUSH // The handle arm first, and it declines rather than half-running: with no record // yet it hands the walk straight back to the pre-handle arm below, unchanged. // P4a decline-site F1: M - the mask says this family is not switched on, and it @@ -5117,7 +4858,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (FramebufferRecordArmIsMandatory()) { RefuseFramebufferBindingSlotRead(); } -#endif #endif const FramebufferTarget fboTargets[] = {FramebufferTarget::Draw, FramebufferTarget::Read}; @@ -5963,7 +5703,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // never be consumed (the stale pair is overwritten before any consumer runs). static const MG_State::GLState::ProgramObject* g_currentDrawFrontendProgram = nullptr; static BackendProgramObjectImpl* g_currentDrawBackendProgram = nullptr; -#if MOBILEGL_PIPE_PUSH // P5e (pg), CONTRACT-P5E.md §5.5: THE SAME STASH, KEYED ON THE HANDLE. The raw frontend // pointer above is one of the five frontend-keyed reads this family retires: every // consumer compared it against GetProgramForDraw().get(), which under run-ahead is a @@ -5976,7 +5715,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // glue's key and the handle is the transport's, and SyncCurrentProgram* clears the one // it does not use so a stale key can never be consumed. static MG_Pipe::MGPipeHandle g_currentDrawProgramHandle = MG_Pipe::kMGPipeNullHandle; -#endif // Memo of the per-draw enabled-draw-buffers walk feeding g_fragColorBroadcastCount: // the answer is a pure function of WHICH FBO is bound and its draw-buffer edits, so @@ -5991,7 +5729,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static Bool g_broadcastMemoValid = false; static Uint g_broadcastMemoCount = 1; -#if MOBILEGL_PIPE_PUSH // P4a e1 (D-C4). The handle arm's key is the framebuffer record's ContentHash, and it // is a COMPLETE key for this answer rather than a cheaper approximation of the trio // above: the hash is taken over every field the record carries - Fbo included, so a @@ -6013,7 +5750,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static Uint64 g_broadcastMemoContentHash = 0; static Bool g_broadcastMemoHandleValid = false; static Uint g_broadcastMemoHandleCount = 1; -#endif // The identity+version key above is only monotonic WITHIN one GLContext: a // library teardown + re-init frees every FramebufferObject and restarts the @@ -6022,12 +5758,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // structurally identical SyncCurrentFBO trio (InvalidateFramebufferBindingCache). void InvalidateBroadcastMemo() { g_broadcastMemoValid = false; -#if MOBILEGL_PIPE_PUSH g_broadcastMemoHandleValid = false; -#endif } -#if MOBILEGL_PIPE_PUSH // P4a e4 (D-H6, D-H7). The ShaderCso record behind a handle, WITH the composite band // resolved: the band starts at kMGPipeShaderCsoCompositeSlotBase and the applier keeps // it in a second dense table indexed by (slot - base), because one composite in the @@ -6211,7 +5944,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return ResolveGlobalConstantsRecordForHandle(g_backendProgramObjects.HandleOf(program), program->GetUBOSize()); } -#endif // Read from the frontend rather than from the backend framebuffer sync, which // only runs later in PrepareForDraw: a program compiled against a stale count @@ -6237,7 +5969,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static void ResolveFragColorBroadcastCount(BroadcastCountPolicy policy) { Bool broadcastCountResolved = false; -#if MOBILEGL_PIPE_PUSH // The trust latch is fresh here and costs nothing: PrepareForDraw runs // SyncCurrentFBO immediately before this, so the records have just been // checked against the two bindings. @@ -6272,7 +6003,6 @@ namespace MobileGL::MG_Backend::DirectGLES { broadcastCountResolved = true; } } -#endif if (policy == BroadcastCountPolicy::RecordOnly) return; if (policy == BroadcastCountPolicy::RefuseFallback && !broadcastCountResolved) { // The record arm declined under a transport. g_fboRecordsTrusted is set by @@ -6339,7 +6069,6 @@ namespace MobileGL::MG_Backend::DirectGLES { ResolveFragColorBroadcastCount(BroadcastCountPolicy::FrontendFallback); BackendProgramObjectImpl* twin = nullptr; -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { auto* slot = g_backendProgramObjects.Find(currentProgram.get()); auto& backendObj = slot ? *slot : g_backendProgramObjects.GetOrCreate(currentProgram); @@ -6348,21 +6077,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } twin = backendObj.get(); } else -#endif { -#if MOBILEGL_PIPE_LEGACY_MEMOS - twin = g_programTwinLookupMemo.Lookup(currentProgram); - if (!twin) { - auto* backendProgramSlot = g_backendProgramObjects.Find(currentProgram.get()); - auto& backendObj = backendProgramSlot ? *backendProgramSlot - : g_backendProgramObjects.GetOrCreate(currentProgram); - if (!backendObj) { - backendObj = MakeShared(); - } - g_programTwinLookupMemo.Store(currentProgram, backendObj.get()); - twin = backendObj.get(); - } -#endif } // A link-version mismatch means the program was relinked: the backend // shaders and every cache built by CacheResourceLocations (block @@ -6389,7 +6104,6 @@ namespace MobileGL::MG_Backend::DirectGLES { twin->GetSnormFallbackClampOutputMask() != g_snormFallbackClampOutputMask || twin->GetUnormFallbackClampOutputMask() != g_unormFallbackClampOutputMask || twin->GetFragColorBroadcastCount() != g_fragColorBroadcastCount || -#if MOBILEGL_PIPE_PUSH // P5e (ID-124): ComputeShaderStorageBlockBindingSignatureOf is declared only // under MOBILEGL_PIPE_PUSH (Managers.h:3122) and this clause read it from an // UNGUARDED condition list, so the pull flavour did not compile. The clause is @@ -6397,7 +6111,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // map the wire carries, and without the wire there is nothing to compare. twin->GetShaderStorageBlockBindingSignature() != ComputeShaderStorageBlockBindingSignatureOf(*currentProgram) || -#endif // A fourth of the same shape, and the reason glBindImageTexture itself does // nothing: GLSL ES demands a format layout qualifier on an image where desktop // GLSL lets a writeonly declaration omit one, so a format-less declaration is @@ -6444,12 +6157,9 @@ namespace MobileGL::MG_Backend::DirectGLES { } g_currentDrawFrontendProgram = currentProgram.get(); g_currentDrawBackendProgram = twin; -#if MOBILEGL_PIPE_PUSH g_currentDrawProgramHandle = MG_Pipe::kMGPipeNullHandle; -#endif } -#if MOBILEGL_PIPE_PUSH // P5e (pg), CONTRACT-P5E.md §5.5: THE SAME SYNC, FROM THE HANDLE THE RECORD CARRIED. // Two overloads and not an `#if` inside one body (ruling 1 / ID-81): the frontend one // above is visibly the monolith-glue half, this one names no frontend object at all. @@ -6519,14 +6229,12 @@ namespace MobileGL::MG_Backend::DirectGLES { g_currentDrawProgramHandle = cso; g_currentDrawBackendProgram = twin; } -#endif } // namespace PrgramImpl void BindCurrentFBO(FramebufferTarget target) { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif -#if MOBILEGL_PIPE_PUSH // The handle arm reads the record instead of the binding slot, which is one of the // five GetFramebufferBindingSlotChecked call sites this phase retires. Everything the // pre-handle arm below is careful about is careful here for the same reasons and in @@ -6582,7 +6290,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (FramebufferRecordArmIsMandatory()) { RefuseFramebufferBindingSlotRead(); } -#endif #endif auto& slot = GetFramebufferBindingSlotChecked(target); @@ -6605,7 +6312,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const MG_Pipe::MGPipeFrontendKeyedRegistryScope frontendKeyedRegistry; #endif FramebufferImpl::BackendFramebufferObject* twin = nullptr; -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { // Not "slot": the enclosing scope's `slot` is the framebuffer BINDING slot, // and this one is the twin table's entry. @@ -6614,18 +6320,7 @@ namespace MobileGL::MG_Backend::DirectGLES { twin = twinEntry->get(); } } else -#endif { -#if MOBILEGL_PIPE_LEGACY_MEMOS - twin = g_fboTwinLookupMemo.Lookup(currentFBO); - if (!twin) { - auto* backendFBOSlot = FramebufferImpl::g_backendFramebufferObjects.Find(currentFBO.get()); - if (backendFBOSlot && *backendFBOSlot) { - twin = backendFBOSlot->get(); - g_fboTwinLookupMemo.Store(currentFBO, twin); - } - } -#endif } if (twin) { twin->Bind(target); @@ -6736,7 +6431,7 @@ namespace MobileGL::MG_Backend::DirectGLES { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5c (hd): with an active transport the bound framebuffer's handle is the applier's // own working state; the object form's registry probe never runs (T2). // @@ -6767,7 +6462,6 @@ namespace MobileGL::MG_Backend::DirectGLES { FramebufferImpl::g_fboSyncedBackendIdGenerations[(SizeT)target] = FramebufferImpl::g_attachmentBackendIdGeneration; } -#if MOBILEGL_PIPE_PUSH // P4a decline-site F9 / MINOR-3: THE HANDLE ARM'S MEMO IS INVALIDATED HERE, NOT // STAMPED, and it is done per target for the reason the memo is kept per target at // all - this entry point syncs ONE binding and must not say anything about the other. @@ -6781,7 +6475,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (FramebufferSubsystemEnabled()) { FramebufferImpl::InvalidateSyncedFramebufferSerial(target); } -#endif } static void BindCurrentProgramWithResources( @@ -6915,7 +6608,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // stores into a buffer texture from the FRAGMENT stage, not from a dispatch. TextureImpl::MarkWritableImageBufferTexturesGpuWritten(); FramebufferImpl::SyncCurrentFBO(); -#if MOBILEGL_PIPE_PUSH // P5e (pg), kimi row 91 / S4 1.1: the SharedPtr pull above is the row this family // retires. On the handle arm the program is MGPipeApplier().DrawProgram - a handle the // set_draw_program record carried - and `currentProgram` is not consulted for the sync @@ -6925,7 +6617,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (ProgramHandleArm()) { PrgramImpl::SyncCurrentProgramByHandle(MG_Pipe::MGPipeApplier().DrawProgram, true); } else -#endif { PrgramImpl::SyncCurrentProgram(currentProgram); } @@ -6944,7 +6635,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } -#if MOBILEGL_PIPE_PUSH // P5e (pa): the third consumer, on ITS OWN arm and not on the hoist's. The hoist above is // a conjunction over four callees; this one is served by the record whenever the PROGRAM // family is on the handle arm, which includes the mixed A/B where the texture bits are @@ -6952,18 +6642,13 @@ namespace MobileGL::MG_Backend::DirectGLES { if (ProgramHandleArm()) { VertexArrayImpl::SyncCurrentVertexAttributeValues(vaoTwin, MG_Pipe::MGPipeApplier().DrawProgram); } else -#endif { VertexArrayImpl::SyncCurrentVertexAttributeValues(vaoTwin, currentProgram); } BindCurrentTextures(textureKeys, currentProgram); BindCurrentProgramWithResources(currentProgram, textureKeys, -#if MOBILEGL_PIPE_PUSH MG_Pipe::MGPipeApplier().DrawProgram -#else - MG_Pipe::kMGPipeNullHandle -#endif ); // Last: opening the capture span needs the program current and the capture @@ -7200,15 +6885,10 @@ namespace MobileGL::MG_Backend::DirectGLES { // pass creates it later in the same draw), and a cached miss would keep skipping the // bind after it appears. struct UnitSamplerLookupMemo { -#if MOBILEGL_PIPE_PUSH // The {slot, gen} of the frontend sampler this row was resolved for. It replaces the // weak_ptr and its owner compare: a stale row cannot match, because the successor of a // freed sampler is handed the same slot only with a higher Gen. MG_Pipe::MGPipeHandle frontendHandle = MG_Pipe::kMGPipeNullHandle; -#endif -#if MOBILEGL_PIPE_LEGACY_MEMOS - WeakPtr frontend{}; -#endif SamplerImpl::BackendSamplerObject* backend = nullptr; }; static Array @@ -7241,7 +6921,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const MG_Pipe::MGPipeFrontendKeyedRegistryScope frontendKeyedRegistry; #endif auto& memo = g_unitSamplerLookupMemos[static_cast(unit)]; -#if MOBILEGL_PIPE_PUSH if (EsprytSlotTablesEnabled()) { const MG_Pipe::MGPipeHandle handle = SamplerImpl::g_backendSamplerObjects.HandleOf(samplerObject.get()); @@ -7258,18 +6937,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return nullptr; } -#endif -#if MOBILEGL_PIPE_LEGACY_MEMOS - if (memo.backend && OwnerEquals(memo.frontend, samplerObject)) { - return memo.backend; - } - auto* backendSamplerSlot = SamplerImpl::g_backendSamplerObjects.Find(samplerObject.get()); - if (backendSamplerSlot && *backendSamplerSlot) { - memo.frontend = samplerObject; - memo.backend = backendSamplerSlot->get(); - return memo.backend; - } -#endif return nullptr; } @@ -7307,7 +6974,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } g_unitSamplerWalkValid = false; -#if MOBILEGL_PIPE_PUSH Bool walkedFromRecords = false; // P4a e4 (D-G2). THE WALK ITSELF READS THE APPLIER'S PER-UNIT HANDLE ARRAY. // @@ -7413,7 +7079,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } if (!walkedFromRecords) -#endif { for (Int unit = 0; unit <= maxTouchedUnit; ++unit) { const auto& samplerObject = MGB_CTX->GetTextureUnitObject(unit).GetSamplerObject(); @@ -7710,7 +7375,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static void BindCurrentProgramWithResources( const SharedPtr& currentProgram, const TextureImpl::DrawTextureSyncKeys& keys, MG_Pipe::MGPipeHandle programCso) { -#if MOBILEGL_PIPE_PUSH // P5e (pg): THE HANDLE ARM'S GATE, from the record rather than from the object. Hoisted // out of the `if` below because the whole body's entry condition is "the program linked // and has SPIR-V", and on this arm both answers are fields of the descriptor @@ -7727,16 +7391,11 @@ namespace MobileGL::MG_Backend::DirectGLES { const Bool programUsable = handleArm ? programRecord != nullptr : (currentProgram && currentProgram->GetLinkStatus() && currentProgram->GetSpirvStatus()); -#else - const Bool programUsable = - currentProgram && currentProgram->GetLinkStatus() && currentProgram->GetSpirvStatus(); -#endif if (programUsable) { #ifdef TRACY_ENABLE ZoneScopedNC("BindCurrentProgram", TRACY_ZONECOLOR_BACKEND); #endif PrgramImpl::BackendProgramObjectImpl* twin = nullptr; -#if MOBILEGL_PIPE_PUSH if (handleArm) { // THE STASH, KEYED ON THE HANDLE (CONTRACT-P5E §5.5). SyncCurrentProgramByHandle // wrote it a few lines ago in the same Prepare; the fallback is the by-handle @@ -7747,7 +7406,6 @@ namespace MobileGL::MG_Backend::DirectGLES { : nullptr; if (!twin) twin = PrgramImpl::ResolveProgramTwin(programCso); } else -#endif { #if MOBILEGL_BUILD_DISAGGREGATED // P5c (G6, CONTRACT-P5C §5.4): MONOLITH GLUE ONLY now. The frontend-keyed twin @@ -7775,20 +7433,15 @@ namespace MobileGL::MG_Backend::DirectGLES { // Global UBO: block index and binding-point assignment are cached at // link time (CacheResourceLocations); re-upload only when the CPU shadow // actually changed since the last upload for this program. -#if MOBILEGL_PIPE_PUSH // P5e (pg): the block's SIZE is Desc.GlobalUboSize on the handle arm. It is the // same number GetUBOSize() answers - the emitter takes it from there - but it is // the record's copy, which is the point. const Uint globalUboSize = handleArm ? programRecord->Desc.GlobalUboSize : currentProgram->GetUBOSize(); -#else - const Uint globalUboSize = currentProgram->GetUBOSize(); -#endif if (globalUboSize > 0 && backendProgram.HasGlobalUboBlock()) { #ifdef TRACY_ENABLE ZoneScopedNC("UpdateGlobalUBO", TRACY_ZONECOLOR_BACKEND); #endif -#if MOBILEGL_PIPE_PUSH // P4a e4 (D-H6): set_global_constants' counterpart. The version and the // block image come off the ShaderCso record when it carries them; the UBO // RING BELOW IS UNTOUCHED - it is on the Espryt do-not-touch list, keeps @@ -7830,23 +7483,16 @@ namespace MobileGL::MG_Backend::DirectGLES { programCso.Slot, programCso.Gen, globalUboSize); std::abort(); } -#endif const Uint32 uboContentVersion = -#if MOBILEGL_PIPE_PUSH globalConstants ? globalConstants->GlobalConstantsVersion : -#endif currentProgram->GetUBOContentVersion(); const SizeT uboSize = static_cast(globalUboSize); // Substituted at the two upload sites rather than hoisted into a local: // MapUBO() is called there today and only there, and hoisting it would // call it on paths that skip the upload entirely. -#if MOBILEGL_PIPE_PUSH #define MGB_UBO_BYTES \ (globalConstants ? static_cast(globalConstants->GlobalConstants.data()) \ : static_cast(currentProgram->MapUBO())) -#else -#define MGB_UBO_BYTES currentProgram->MapUBO() -#endif // Preferred path: write changed contents into a fresh slot of the // shared persistent-mapped ring and bind it as a range. The GPU // never reads bytes the CPU is writing, so the driver has no @@ -7933,10 +7579,8 @@ namespace MobileGL::MG_Backend::DirectGLES { // this very index space. The BINDING POINT it names is sb's row (the // GetBufferBindingPoint below); this line is the boundary S4 R5 named. auto binding = -#if MOBILEGL_PIPE_PUSH handleArm ? PrgramImpl::ProgramBlockBindingFromRecord(*programRecord, i) : -#endif currentProgram->GetUniformBlockBinding(i); #if MOBILEGL_BUILD_DISAGGREGATED // P5e (sb, §5.6): THE POINT HALF, by record. `binding` above is the @@ -8066,9 +7710,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // safe for a memo key - it is a change detector, not an ordering - and the // record's serial would need four billion binding records to wrap. const Uint32 programBackendStateVersion = -#if MOBILEGL_PIPE_PUSH handleArm ? static_cast(programRecord->BindingsSerial) : -#endif currentProgram->GetBackendStateVersion(); Bool samplerPassClean = samplerPassMemo.valid && samplerPassMemo.contextId == keys.contextId && @@ -8096,12 +7738,10 @@ namespace MobileGL::MG_Backend::DirectGLES { // of the three post-link mutable fields, carried sparse and ascending // by location in set_program_bindings' second tail. const auto unit = -#if MOBILEGL_PIPE_PUSH handleArm ? PrgramImpl::ProgramSamplerUnitFromRecord( *programRecord, samplerBinding.frontendLocation) : -#endif currentProgram->GetUniformSamplerOrImageUnitIndex( samplerBinding.frontendLocation); if (unit == -1) continue; @@ -8234,7 +7874,6 @@ namespace MobileGL::MG_Backend::DirectGLES { GetRawDepthFetchSampler()->Bind(unit); MGLOG_D("Using raw depth fetch sampler on unit %d.", unit); } else if (samplerObject) { -#if MOBILEGL_PIPE_PUSH // P4a fable seam F-4: on the handle arm the unit's sampler is THE // CSO's OWN TWIN, the same one BindCurrentUnitSamplers' record arm // binds, so this pass and that walk cannot hand the unit back and @@ -8257,7 +7896,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (csoTwin != nullptr) { csoTwin->Bind(unit); } else { -#endif auto* backendSampler = ResolveUnitSamplerBackend(unit, samplerObject); if (!backendSampler) { auto& backendObj = @@ -8267,22 +7905,16 @@ namespace MobileGL::MG_Backend::DirectGLES { } backendSampler = backendObj.get(); } -#if MOBILEGL_PIPE_PUSH backendSampler->SyncToBackend( samplerObject, static_cast(unit) < MG_Pipe::MGPipeApplier().BoundSamplerStates.size() ? MG_Pipe::MGPipeApplier().BoundSamplerStates[static_cast(unit)] : MG_Pipe::kMGPipeNullHandle); -#else - backendSampler->SyncToBackend(samplerObject); -#endif // Syncing the object's parameters is not the same as putting it on the // unit: without this the driver kept sampling with the texture's own // parameters and every sampler object was inert. backendSampler->Bind(unit); -#if MOBILEGL_PIPE_PUSH } -#endif } else { SamplerImpl::UnbindSampler(unit); } @@ -8314,7 +7946,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // PrepareForCompute, where the current program (and therefore its registry twin) // is pinned for the duration. Prefers the per-draw stash those preparations wrote. static PrgramImpl::BackendProgramObjectImpl* GetCurrentBackendProgram() { -#if MOBILEGL_PIPE_PUSH // P5e (pg), kimi row 107: THE PER-SUB-DRAW ROW. This is reached once per indirect // sub-draw for the gl_DrawID / gl_BaseVertex / gl_BaseInstance uniforms, and before P5e // every one of those pulled GetProgramForDraw() and, on a stash miss, probed the client @@ -8333,7 +7964,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return PrgramImpl::ResolveProgramTwin(cso); } -#endif const auto& currentProgram = MGB_CTX->GetProgramForDraw(); if (!currentProgram || !currentProgram->GetLinkStatus() || !currentProgram->GetSpirvStatus()) { return nullptr; @@ -8391,7 +8021,6 @@ namespace MobileGL::MG_Backend::DirectGLES { Bool CurrentProgramMayNeedPerSubDrawBuiltins(Bool batchCarriesBaseVertices) { const auto program = GetCurrentBackendProgram(); if (program == nullptr) return true; -#if MOBILEGL_PIPE_PUSH // P5e (pg), kimi row 108: the same "is this twin current" question, from the record's // serial instead of the frontend's link version. The ANSWER TO AN UNANSWERABLE PROGRAM // IS STILL `true` - a flattened batch that turns out to need per-sub-draw values is @@ -8405,7 +8034,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return program->ReadsDrawID() || (batchCarriesBaseVertices && program->ReadsBaseVertex()); } -#endif const auto& currentProgram = MGB_CTX->GetProgramForDraw(); if (!currentProgram || program->GetSyncedLinkVersion() != currentProgram->GetLinkVersion()) { return true; @@ -8855,7 +8483,6 @@ namespace MobileGL::MG_Backend::DirectGLES { TextureImpl::SyncNeccessaryTextures(textureKeys); TextureImpl::SyncImageTextureBindings(); TextureImpl::MarkWritableImageBufferTexturesGpuWritten(); -#if MOBILEGL_PIPE_PUSH // P5e (pg), kimi row 92: the DISPATCH half of the same retirement - // MGPipeApplier().DispatchProgram, which set_dispatch_program carried. A compute-only // pipeline has no draw program at all, which is why the two applier fields are separate. @@ -8865,12 +8492,10 @@ namespace MobileGL::MG_Backend::DirectGLES { if (programHandleArm) { PrgramImpl::SyncCurrentProgramByHandle(dispatchCso, false); } else -#endif { PrgramImpl::SyncCurrentProgram(currentProgram); } -#if MOBILEGL_PIPE_PUSH if (programHandleArm) { // The same gate as the frontend one below, from the record: a dispatch of a program // the frontend reports unlinked, or one whose SPIR-V never arrived, binds nothing. @@ -8881,7 +8506,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } } else -#endif if (!currentProgram || !currentProgram->GetLinkStatus() || !currentProgram->GetSpirvStatus()) { g_GLESFuncs.glUseProgram(0); PrgramImpl::g_lastUsedBackendProgramId = 0; @@ -8896,11 +8520,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // uniform-block bindings and sampler units only exist through the API // because layout(binding) is stripped from the transpiled ESSL. BindCurrentProgramWithResources(currentProgram, textureKeys, -#if MOBILEGL_PIPE_PUSH dispatchCso -#else - MG_Pipe::kMGPipeNullHandle -#endif ); } @@ -9042,7 +8662,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const GLenum rbErr = g_GLESFuncs.glGetError(); int feDb0 = -1, feDb1 = -1; Uint feIdx = 0, feVer = 0; -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5e (fb): DEBUG-ONLY, and still a BARRIER_PULLED read. A diagnostic // is not a reason to touch the binding slot on an apply thread, so // under a transport the same four numbers come off the draw record - @@ -9977,12 +9597,7 @@ namespace MobileGL::MG_Backend::DirectGLES { return UseNativeBaseInstance() ? 0u : static_cast(baseinstance); } -#if MOBILEGL_PIPE_LEGACY_MEMOS -#define MGL_SCOPED_FETCH_BASE_INSTANCE(name, value) \ - const VertexArrayImpl::ScopedFetchBaseInstance name(value) -#else #define MGL_SCOPED_FETCH_BASE_INSTANCE(name, value) ((void)(value)) -#endif void DrawElementsInstancedBaseVertexBaseInstance(GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance) { @@ -10310,9 +9925,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, static_cast(previousRead)); g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(previousDraw)); FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif if (!resolved) { MGLOG_E_ONCE("BlitFramebuffer: multisample resolve fallback failed"); } @@ -10828,9 +10441,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(previousDraw)); g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, static_cast(previousRead)); FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif if (!ok) { MGLOG_E_ONCE("BlitFramebuffer: could not stage the source for the multisample replicate"); return false; @@ -10930,9 +10541,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, static_cast(previousRead)); g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(previousDraw)); FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif } if (readSamples <= 0 && drawSamples > 0) { // Single-sample source into a multisample destination: ES rejects the call @@ -11144,7 +10753,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return handled & mask; } -#if MOBILEGL_PIPE_PUSH // ---- P5e (fb, CONTRACT-P5E.md §5.4): the same aspect plan, from the two RECORDS --------- // // The blit was the last entry point in this family that still reached into two frontend @@ -11347,7 +10955,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return st.FramebufferRecordFor(fbo); } -#endif // MOBILEGL_PIPE_PUSH void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { @@ -11429,7 +11036,7 @@ namespace MobileGL::MG_Backend::DirectGLES { dstX1, dstY1, mask, MG_Util::ConvertGLEnumToString(filter).c_str()); // A no-op on every driver that honours a non-zero destination array layer, which is all // of them but the probed one. Whatever it performs itself is taken out of the mask. -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5e (fb, §5.4): the bound arm's two binding-slot reads were the last GetBoundObject // pair on this path; under a transport the two bound RECORDS answer instead // (FramebufferRecordFor(st.BoundFramebuffer[t]), through BlitEndpointRecord's null @@ -11750,7 +11357,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (existingLevelCount == 0) { return false; } -#if MOBILEGL_PIPE_PUSH // P4a (D-M). glGenerateMipmap's storage grow reaches into the frontend texture's own // level shadows to decide - and then to define - the levels the driver is about to // fill. In monolith that is exactly what it does today and nothing here changes; under @@ -11758,7 +11364,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // Named and greppable rather than silent, so the site cannot quietly disappear before // then. MG_Pipe::MGPipeUnmigratedEmulation("generate-mipmap-storage"); -#endif const IntVec3 baseTexelSize = texture.GetMipmapTexelSize(uploadTarget, 0); const SizeT baseByteSize = texture.GetMipmapByteSize(uploadTarget, 0); @@ -12011,7 +11616,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // KEY, i.e. the raw frontend address, and has to test the entry's weak_ptr by hand // before it dares dereference it; the body is otherwise identical, which is why it // is lifted into a lambda both arms call. -#if MOBILEGL_PIPE_PUSH // P5e (id, CONTRACT-P5E §4.1): the push arm walks the twin table through // ForEachLive, which now hands over the entry's HANDLE and its twin - never a // frontend SharedPtr, because a walk that produced one on every step was the last @@ -12157,71 +11761,6 @@ namespace MobileGL::MG_Backend::DirectGLES { }); return; } -#if MOBILEGL_PIPE_LEGACY_MEMOS - for (auto it = FramebufferImpl::g_backendFramebufferObjects.begin(); - it != FramebufferImpl::g_backendFramebufferObjects.end(); ++it) { - // An entry whose state object died is only waiting for the next collection; - // the key is a dangling address, so it must not be dereferenced here. - if (it->second.stateRef.expired()) { - continue; - } - detachFrom(it->first, it->second.backend); - } -#endif -#else - // Pull build: exactly the pre-P2 walk, so this translation unit generates the - // same code it did before P2 (G1). - for (auto it = FramebufferImpl::g_backendFramebufferObjects.begin(); - it != FramebufferImpl::g_backendFramebufferObjects.end(); ++it) { - auto* stateFBO = it->first; - const auto& backendFBO = it->second.backend; - // An entry whose state object died is only waiting for the next collection; - // the key is a dangling address, so it must not be dereferenced here. - if (stateFBO == nullptr || !backendFBO || it->second.stateRef.expired() || - stateFBO->IsDefaultFramebuffer()) { - continue; - } - - const auto& attachments = stateFBO->GetAllAttachmentObjects(); - for (SizeT i = 0; i < attachments.size(); ++i) { - const auto& attachmentObject = attachments[i]; - if (!attachmentObject.IsTexture() || attachmentObject.GetTexture().get() != texture.get()) { - continue; - } - - const auto frontendType = static_cast(i); - GLenum backendAttachment = GL_NONE; - if (frontendType >= FramebufferAttachmentType::Color0 && - frontendType <= FramebufferAttachmentType::Color31) { - backendAttachment = backendFBO->GetBackendAttachmentType(frontendType); - } else { - backendAttachment = MG_Util::ConvertFramebufferAttachmentTypeToGLEnum(frontendType); - } - if (backendAttachment == GL_NONE || backendAttachment == GL_UNKNOWN_MGL) { - continue; - } - - GLenum textureTarget = TextureImpl::ConvertTextureUploadTargetToBackendGLEnum( - attachmentObject.GetTextureUploadTarget()); - if (textureTarget == GL_UNKNOWN_MGL) { - textureTarget = TextureImpl::ConvertTextureTargetToBackendGLEnum(texture->GetTarget()); - } - - const GLuint backendFBOId = backendFBO->GetBackendFramebufferId(); - FramebufferImpl::BindFramebufferId(GL_DRAW_FRAMEBUFFER, backendFBOId); - if (attachmentObject.IsLayered()) { - g_GLESFuncs.glFramebufferTexture(GL_DRAW_FRAMEBUFFER, backendAttachment, 0, 0); - } else { - g_GLESFuncs.glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, backendAttachment, textureTarget, 0, 0); - } - ClearGLErrors(); - m_detachedAttachments.push_back( - {backendFBOId, backendAttachment, textureTarget, backendTextureId, - static_cast(attachmentObject.GetTextureLevel()), attachmentObject.IsLayered()}); - } - } -#endif } ~ScopedDetachedTextureFramebufferAttachments() { @@ -13000,14 +12539,12 @@ namespace MobileGL::MG_Backend::DirectGLES { auto* mipmapTexture = MG_State::GLState::AsMipmapTexture(texture.get()); if (mipmapTexture == nullptr) return false; -#if MOBILEGL_PIPE_PUSH // P4a (D-M). The three-channel float mipmap fallback filters the CHAIN ON THE CPU out // of the frontend's level shadows and uploads the result. Monolith keeps doing exactly // that; a split server has no shadow to filter, and P8 is what retires it. The texels // themselves are the other half of ARCHITECTURE.md's generate_mipmap item, which is // P8's too. MG_Pipe::MGPipeUnmigratedEmulation("generate-mipmap-cpu-fallback"); -#endif const Uint levelCount = mipmapTexture->GetMipmapLevelCount(); constexpr Int kChannels = 3; @@ -13850,7 +13387,7 @@ namespace MobileGL::MG_Backend::DirectGLES { (void)layer; (void)access; (void)format; -#if MOBILEGL_PIPE_PUSH && MOBILEGL_BUILD_DISAGGREGATED +#if MOBILEGL_BUILD_DISAGGREGATED // P5e (fb): see NoteImageUnitBoundWithoutReadingTheFrontend. Under a transport this // entry point records the high-water mark and lets the next validate point's sweep do // the bind from the record; reading the frontend image binding here is the @@ -15378,7 +14915,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return true; } const void* shadow = textureMipmapObject->MapMipmapData(uploadTarget, level); -#if MOBILEGL_PIPE_PUSH #if MOBILEGL_BUILD_DISAGGREGATED // P4a (D-M) SAID "a split server holds no shadow to convert" AND ABORTED. That is the // premise this row of P3b/P4b re-examined, and it is wrong in the only case that can @@ -15415,7 +14951,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } else #endif MG_Pipe::MGPipeUnmigratedEmulation("get-tex-image-shadow"); -#endif const auto& pixelPackBufferObject = #if MOBILEGL_BUILD_DISAGGREGATED MG_Config::Transport != MG_Config::TransportMode::Monolith @@ -16373,7 +15908,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (resolver != nullptr) (void)resolver(&outSession, &outToken); } -#if MOBILEGL_PIPE_PUSH // P14 S6: the twin tables' key. Same probe/fallback shape as the native tuple's above and // for the same reason (the whole single-context world must keep getting one key), and // deliberately a SEPARATE resolver: this one answers for a table that is consulted on paths @@ -16392,7 +15926,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (resolver == nullptr) return false; return resolver(outKey); } -#endif // MOBILEGL_PIPE_PUSH Uint64 CurrentNativeSessionKey() { Uint64 session = 0; @@ -16612,7 +16145,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // resizing depth/stencil without colour would report the default framebuffer incomplete. static void PublishDefaultFramebufferDepthStencilFormat() { auto& defaultFBOInfo = MG_Impl::GLImpl::FramebufferImpl::pDefaultFramebufferInfo; -#if MOBILEGL_PIPE_PUSH // P8-SE: THE PLACEHOLDER IS ONLY THE MONOLITH ARM'S TARGET. With a transport the answer is // posted (OnSurfaceChanged, below) and the client writes its own placeholder; a spawn or tcp // server process has no frontend at all, so pDefaultFramebufferInfo is null there. Gating on @@ -16621,9 +16153,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // (notes/p8/SE.md). Inproc only passed because client and server share the process. if (!g_GLESFuncs.glGetFramebufferAttachmentParameteriv) return; if (!defaultFBOInfo && MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged == nullptr) return; -#else - if (!defaultFBOInfo || !g_GLESFuncs.glGetFramebufferAttachmentParameteriv) return; -#endif // GL_DEPTH / GL_STENCIL are the default framebuffer's spellings; a user framebuffer // would need GL_DEPTH_ATTACHMENT / GL_STENCIL_ATTACHMENT and answers GL_INVALID_ENUM @@ -16652,9 +16181,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(previousDrawFramebuffer)); } FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif // A driver that refuses the query leaves both at 0. Fall back to what the EGL config // was chosen with, which is what the surface actually has. P14 S4: the config belongs to the @@ -16706,15 +16233,9 @@ namespace MobileGL::MG_Backend::DirectGLES { stencilFormat = TextureInternalFormat::StencilIndex8; } -#if MOBILEGL_PIPE_PUSH // Null in a spawn / tcp server (above); only the monolith arm below writes through them. auto* depthTexture = defaultFBOInfo ? defaultFBOInfo->depthAttachment.get() : nullptr; auto* stencilTexture = defaultFBOInfo ? defaultFBOInfo->stencilAttachment.get() : nullptr; -#else - auto* depthTexture = defaultFBOInfo->depthAttachment.get(); - auto* stencilTexture = defaultFBOInfo->stencilAttachment.get(); -#endif -#if MOBILEGL_PIPE_PUSH if (MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged != nullptr) { // P5c ev (CONTRACT-P5C §4.2): with an active transport the attachments are CLIENT // memory and this thread may not write them - the backend fills MGPSurfaceInfo @@ -16748,7 +16269,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #endif MG_Pipe::gMGPipeCallbacks.OnSurfaceChanged(&info); } else -#endif { if (depthTexture) depthTexture->SetInternalFormat(depthFormat); if (stencilTexture) stencilTexture->SetInternalFormat(stencilFormat); @@ -16979,9 +16499,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // vars the D14/D18 A/B is driven with (ROADMAP.md:7). The stop now belongs to the first // twin lookup, which happens in a scenario body where a crash IS a test failure. static void DiagnoseEsprytSlotArmAtBringUp() { -#if MOBILEGL_PIPE_PUSH DiagnoseEsprytSlotArm(); -#endif } // RESET NOTIFICATION, decided once per process by its first native context (EnsureNativeContext @@ -17729,9 +17247,7 @@ namespace MobileGL::MG_Backend::DirectGLES { BufferImpl::InvalidatePixelBufferBindingCaches(); BufferImpl::InvalidateTransformFeedbackBindingShadows(); FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif VertexArrayImpl::InvalidateVAOBindingCache(); PixelStoreImpl::InvalidatePackStateCache(); // The render-state shadow belongs in this list for the same reason as the ones above: @@ -18494,9 +18010,7 @@ namespace MobileGL::MG_Backend::DirectGLES { ScratchFBOImpl::OnBackendContextDestroyed(); ReleasePackedWordScratchTexture(); FramebufferImpl::InvalidateFramebufferBindingCache(); -#if MOBILEGL_PIPE_PUSH FramebufferImpl::InvalidateFramebufferHandleArmMemos(); -#endif VertexArrayImpl::InvalidateVAOBindingCache(); PixelStoreImpl::InvalidatePackStateCache(); PrgramImpl::InvalidateBroadcastMemo(); diff --git a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h index fb25ec0c..e1df7b5d 100644 --- a/MobileGL/MG_Backend/DirectGLES/DirectGLES.h +++ b/MobileGL/MG_Backend/DirectGLES/DirectGLES.h @@ -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 diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.cpp b/MobileGL/MG_Backend/DirectGLES/Managers.cpp index 83d598cd..4dd19c41 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.cpp +++ b/MobileGL/MG_Backend/DirectGLES/Managers.cpp @@ -8,7 +8,6 @@ #include "Managers.h" #include -#if MOBILEGL_PIPE_PUSH // P3a: the handle-shaped resource op table, the applier's records and the reverse channel. // Both headers are compiled into the library only under push, so they are included here // under the same condition - a pull build must gain no declaration it cannot link. @@ -19,7 +18,6 @@ // needs only the name - the deleter is captured where the archive is constructed - but the // program build reads through it, so the one translation unit that does needs the whole type. #include -#endif #if MOBILEGL_BUILD_DISAGGREGATED // R-11's server-owned staging copy. Header-only and package v1's; see its own header block for // why GLESBufferResource does not simply gain a member. @@ -212,7 +210,6 @@ namespace MobileGL::MG_Backend::DirectGLES { [] { std::atexit(+[] { g_processTeardown = true; }); }); } -#if MOBILEGL_PIPE_PUSH namespace { // P2 step e2's dispatcher: the frontend told us an object died, so free its slot and // drop its twin NOW. One entry point for all six kinds, because the answer is the same @@ -469,16 +466,11 @@ namespace MobileGL::MG_Backend::DirectGLES { // The one sentence that decides the arm, written once so that a test can drive every // combination of the two knobs and so that bring-up and first-use cannot disagree. EsprytSlotArmVerdict ClassifyEsprytSlotArm(Bool subsystemBitSet, Bool legacyMemosEnabled) { -#if MOBILEGL_PIPE_LEGACY_MEMOS - if (subsystemBitSet) return EsprytSlotArmVerdict::Handles; - return legacyMemosEnabled ? EsprytSlotArmVerdict::Legacy : EsprytSlotArmVerdict::NoArm; -#else // The legacy arm is not compiled, so the handle arm is the only arm and neither knob // can produce an armless configuration. (void)subsystemBitSet; (void)legacyMemosEnabled; return EsprytSlotArmVerdict::Handles; -#endif } EsprytSlotArmVerdict CurrentEsprytSlotArmVerdict() { @@ -529,21 +521,18 @@ namespace MobileGL::MG_Backend::DirectGLES { if (verdict == EsprytSlotArmVerdict::Legacy) { return false; } -#if !MOBILEGL_PIPE_LEGACY_MEMOS if ((MG_Config::Features.PipePush & MG_Pipe::kMGPipeSubsystemEsprytSlots) == 0) { // The bit is clear but this build has no legacy twin registry to fall back to, so // the bit decides nothing. Recorded so a log reader sees the mismatch. MGLOG_D("MGPipe: kMGPipeSubsystemEsprytSlots is clear but this build has no " "legacy twin registry; running the handle arm anyway"); } -#endif // The notice is only consumable on the handle arm (the legacy registry keys on the // frontend ADDRESS, which is gone by the time a destructor speaks), so it is installed // exactly where it can be answered. Once per process, cold. MG_State::GLState::SetStateObjectDeathOps(&g_glesStateObjectDeathOps); return true; } -#endif Bool VertexStageStorageBlockUsable(Int maxVertexShaderStorageBlocks) { // One block is all the indirect-params view needs, so this is a >= 1 test and not a @@ -1187,7 +1176,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return DirectGLES::IsBackendContextCurrentOnThisThread(); } -#if MOBILEGL_PIPE_PUSH // P3a: ONE body per helper, parameterised on where its host bytes and its // extent come from, so the legacy arm and the handle arm of a push build share // the three-tier flush, the respecify and the range upload rather than owning a @@ -1446,14 +1434,12 @@ namespace MobileGL::MG_Backend::DirectGLES { // sizeable (page-coverable) range to engage, and below it the driver // falls back to waiting out the WAR hazard on the CPU. constexpr SizeT kInvalidateRangeMinBytes = 128u * 1024u; -#if MOBILEGL_PIPE_PUSH // The push arm's copy of this threshold lives in Managers.h, where a unit case can // reach it (InvalidateFlushAccessFor). Two constants, one value, and the compiler // is what keeps them one: the pull arm's FlushPendingRangesNow is byte-frozen // against 5cb826b0 (ID-15), so the constant it reads may not move to a header. static_assert(kInvalidateRangeMinBytes == kEsprytInvalidateRangeMinBytes, "the two arms of the three-tier ladder must use the same tier-1 threshold"); -#endif // Push every queued range of `resource` from the shadow into the backend // store, without ever letting a driver resolve the WAR hazard against @@ -1687,255 +1673,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (void)bufferObject; DrainResidentWritesNow(resource); } -#else - // (Re)specify backend storage from the shadow copy: glBufferData. - // The orphaning point - the ES driver performs the actual rename. - // TODO(buffer-pool Phase 2): orphan-on-respecify is NOT yet implemented. - // When the current id is BUSY (lastUseFrameSerial > CompletedFrameSerial()) - // && !persistentMapped && !noOrphan, express the orphan as an id-swap - // (retire the busy id into the pool, bind a fresh/pooled id) instead of the - // in-place glBufferData below, to avoid the driver's own rename/stall. Not - // pursued yet: glBufferData/glBufferSubData currently sit below profiler - // noise, so respecify is not a hot path in the profiled scenes. - void RespecifyStorageNow(GLESBufferResource& resource, BufferObject& bufferObject) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - const SizeT size = bufferObject.GetSize(); - // Read BEFORE the fields below are overwritten: whether this respecify changes - // the store's EXTENT is what decides if the indexed-binding shadow still - // describes the driver. - const Bool extentChanged = !resource.storageInitialized || resource.storageSize != size; - const GLenum usage = MG_Util::ConvertBufferUsageToGLEnum(bufferObject.GetUsage()); - BindBufferId(TempBufferTarget, resource.id); - // An orphaning respecify (glBufferData with NULL, content never - // written since) stays a pure NULL reallocation: the driver renames - // the store without a stall and nothing is transferred. Uploading - // the stale shadow here turned Minecraft-style orphaning into a - // full-size synchronized upload. - const void* initialData = - (size > 0 && bufferObject.HasDefinedContent()) ? bufferObject.MappedData() : nullptr; - g_GLESFuncs.glBufferData(TempBufferTarget, (GLsizeiptr)size, initialData, usage); - if (MG_Util::PipeStats::Enabled() && initialData != nullptr) { - // An ORPHANING respecify passes NULL and moves nothing, which is exactly - // why the test is on initialData rather than on size. - MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer, - static_cast(size)); - } - resource.storageSize = size; - resource.storageInitialized = true; - resource.pendingRespecify = false; - resource.pendingRanges.clear(); - resource.pendingResidentWrites.clear(); - resource.syncedChangeSerial = bufferObject.GetChangeSerial(); - // A GROWN store keeps its indexed bindings, and BindBufferBaseCached skips a - // rebind whenever the shadow already records this id at that index - so on a - // driver that resolves a whole-buffer indexed binding's extent at BIND time - // (Adreno does; Mali does not) the shader keeps seeing the old, smaller range: - // stores past it are dropped and loads return zero. Forget what the shadow - // claims for this id so the next SyncBufferBindingPoints issues the bind for - // real. Only when the extent actually moved: an orphaning respecify at the same - // size is Minecraft's per-frame hot path and its bindings are still exact. - if (extentChanged) { - InvalidateIndexedBufferBindingShadowsForId(resource.id); - } - } - - Bool StorageMatches(const GLESBufferResource& resource, const BufferObject& bufferObject) { - return resource.storageInitialized && !resource.pendingRespecify && - resource.storageSize == bufferObject.GetSize(); - } - - - - void UploadRangeNow(GLESBufferResource& resource, BufferObject& bufferObject, SizeT start, SizeT end) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - if (start >= end) return; - BindBufferId(TempBufferTarget, resource.id); - g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)start, (GLsizeiptr)(end - start), - bufferObject.MappedData() + start); - } - - // Ring machinery shared with the UBO/unpack rings; defined further down in - // this same unnamed namespace. - Bool RingAllocate(PersistentRing& ring, SizeT size, SizeT& outOffset); - Bool RingAvailable(PersistentRing& ring); - - // True when a pending-range flush can go through the staging ring right - // now: kill switch off, the ES copy entry point resolved, and the ring's - // own availability gate (EXT_buffer_storage + fences + live context) up. - Bool UploadRingUsableNow() { - if (MG_Config::Features.EsprytDisableUploadRing) return false; - if (!g_GLESFuncs.glCopyBufferSubData) return false; - return RingAvailable(UploadRing()); - } - - // A partial range below this goes through the staging ring instead of a - // range-invalidating map: the map's page-substitution fast path needs a - // sizeable (page-coverable) range to engage, and below it the driver - // falls back to waiting out the WAR hazard on the CPU. - constexpr SizeT kInvalidateRangeMinBytes = 128u * 1024u; - - // Push every queued range of `resource` from the shadow into the backend - // store, without ever letting a driver resolve the WAR hazard against - // in-flight frames at the WHOLE BUFFER's expense. Three tiers: - // - // 1. glMapBufferRange(WRITE | INVALIDATE_RANGE) + memcpy. The entire - // mapped range is rewritten from the authoritative shadow, so - // declaring its old bytes dead is exact - and it lets the driver - // swap fresh pages in for JUST that range. This is the only tier - // whose cost scales with the RANGE on this Mali driver: both the - // immediate glBufferSubData (pre-queueing) and a staged - // glCopyBufferSubData into a busy MUTABLE store ghost the whole - // destination with a worker-thread memcpy - Minecraft 26.3 streams - // ~1MB section meshes into 128MB arenas about nine times a frame - // during a camera pan, and 9 x 128MB of ghosting per frame is - // ~380ms, the measured 2-4 fps. (Backing the arenas with immutable - // stores also kills the ghost, but eagerly commits every arena's - // full extent - +hundreds of MB - which LMK'd the whole device.) - // 2. The staging ring + glCopyBufferSubData: the copy is ordered on - // the GPU timeline, no CPU wait (MOBILEGL_ESPRYT_DISABLE_INVALIDATE_FLUSH - // forces this tier as the map path's negative control). - // 3. Direct glBufferSubData (potentially stalling) when neither the - // map entry points nor the ring exist. - // - // The ranges are flushed AS QUEUED (VecRange1D::Add already merges - // near-adjacent ones): bytes, not flush calls, are the cost axis here, - // and collapsing a scattered flush into its union re-copied nearly whole - // chunk-mesh arenas every frame. - // The caller owns syncedChangeSerial; this only drains the queue. - void FlushPendingRangesNow(GLESBufferResource& resource, BufferObject& bufferObject) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - VecRange1D ranges; - { - const std::lock_guard lock(resource.pendingMutex); - if (resource.pendingRanges.empty()) return; - ranges = std::move(resource.pendingRanges); - resource.pendingRanges.clear(); - } - // Clamp against BOTH extents: the readback flush may run while the - // frontend size and the backend store disagree (a pending respecify - // resolves that later; bytes past either end have nowhere to land). - const SizeT limit = std::min(bufferObject.GetSize(), resource.storageSize); - const Bool mapUsable = !MG_Config::Features.EsprytDisableInvalidateFlush && - g_GLESFuncs.glMapBufferRange && g_GLESFuncs.glUnmapBuffer; - const Bool ringUsable = UploadRingUsableNow(); - for (const auto& range : ranges) { - const SizeT end = std::min(range.end, limit); - const SizeT start = std::min(range.start, end); - const SizeT size = end - start; - if (size == 0) continue; - if (MG_Util::PipeStats::Enabled()) { - // Counted once per queued range, before the three delivery shapes - // below diverge: all three move exactly these bytes, and it is the - // byte count - not the shape - that sizes SEG_STAGE. - MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer, - static_cast(size)); - } - // The invalidating map's fast path is SHAPE-dependent on this Mali - // driver: a whole-buffer invalidation renames the store outright, - // and a large range gets fresh pages - but a small unaligned range - // of a busy store makes the map WAIT (osup_sync_object_wait, ~9% - // of a Minecraft 26.3 replay). So: whole buffer -> orphan-map; - // large range -> range-invalidating map; small range -> the staged - // ring copy, whose worst case (a whole-destination ghost) is only - // ever the small destination itself. - // - // The map covers EXACTLY the queued range: only those bytes are the - // shadow's to rewrite. Widening to page bounds looked free and was - // not - the widened bytes clobbered GPU-written data (an SSBO - // counter beside the app's SubData) with the stale shadow. - // - // A partial range-invalidating map must not overtake a ring copy into - // this store the GPU has not run yet. Adreno 830 answers such a map on - // a store with a copy still queued by losing the copy: the Embeddium - // section meshes create-instancing staged through the ring came out - // empty (whole terrain sections missing, SSIM 0.870), and routing the - // map ranges behind the copies - the ring tier, GPU-ordered after them - - // brings every one back. The whole-buffer orphan-map is exempt: it - // rewrites every byte from the shadow the queued copies were taken from. - const Bool wholeBuffer = start == 0 && end == limit && limit == resource.storageSize; - const Bool ringCopyInFlight = resource.ringCopyRetireSerial > DirectGLES::CompletedFrameSerial(); - if (mapUsable && (wholeBuffer || (size >= kInvalidateRangeMinBytes && !ringCopyInFlight))) { - BindBufferId(TempBufferTarget, resource.id); - const GLbitfield access = - GL_MAP_WRITE_BIT | - (wholeBuffer ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_INVALIDATE_RANGE_BIT); - void* dst = g_GLESFuncs.glMapBufferRange(TempBufferTarget, (GLintptr)start, - (GLsizeiptr)size, access); - if (dst) { - Memcpy(dst, bufferObject.MappedData() + start, size); - g_GLESFuncs.glUnmapBuffer(TempBufferTarget); - continue; - } - } - SizeT ringOffset = 0; - if (ringUsable && size <= kUploadRingMaxBytes && - RingAllocate(UploadRing(), size, ringOffset)) { - Memcpy(UploadRing().store.mappedPtr + ringOffset, bufferObject.MappedData() + start, size); - BindBufferId(GL_COPY_READ_BUFFER, UploadRing().store.id); - BindBufferId(GL_COPY_WRITE_BUFFER, resource.id); - g_GLESFuncs.glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, - (GLintptr)ringOffset, (GLintptr)start, (GLsizeiptr)size); - // Commands recorded now retire with the fence the next Present inserts. - resource.ringCopyRetireSerial = DirectGLES::CurrentFrameSerial() + 1; - } else { - UploadRangeNow(resource, bufferObject, start, end); - } - } - } - - // Land the app bytes queued for an ADOPTED store on the GPU timeline: staged - // into the upload ring and delivered by glCopyBufferSubData. The destination - // is the IMMUTABLE persistent store, which the driver can neither rename nor - // ghost, so the copy is plain job ordering - after every in-flight reader, - // before the next consumer - which is exactly glBufferSubData's contract. - // (The in-place host write these bytes replaced tore the frames still - // reading the old vertex data: one-frame wrong geometry during fast camera - // movement.) Fallback: direct glBufferSubData - the adopted store carries - // DYNAMIC_STORAGE, and immutability again forbids the whole-store ghost. - void DrainResidentWritesNow(GLESBufferResource& resource, BufferObject& bufferObject) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - Vector writes; - { - const std::lock_guard lock(resource.pendingMutex); - if (resource.pendingResidentWrites.empty()) return; - writes = std::move(resource.pendingResidentWrites); - resource.pendingResidentWrites.clear(); - } - const SizeT limit = resource.storageSize; - const Bool ringUsable = UploadRingUsableNow(); - for (const auto& write : writes) { - if (write.offset >= limit) continue; - const SizeT size = std::min(write.bytes.size(), limit - write.offset); - if (size == 0) continue; - if (MG_Util::PipeStats::Enabled()) { - MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageBuffer, - static_cast(size)); - } - SizeT ringOffset = 0; - if (ringUsable && size <= kUploadRingMaxBytes && - RingAllocate(UploadRing(), size, ringOffset)) { - Memcpy(UploadRing().store.mappedPtr + ringOffset, write.bytes.data(), size); - BindBufferId(GL_COPY_READ_BUFFER, UploadRing().store.id); - BindBufferId(GL_COPY_WRITE_BUFFER, resource.id); - g_GLESFuncs.glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, - (GLintptr)ringOffset, (GLintptr)write.offset, - (GLsizeiptr)size); - } else { - BindBufferId(TempBufferTarget, resource.id); - g_GLESFuncs.glBufferSubData(TempBufferTarget, (GLintptr)write.offset, (GLsizeiptr)size, - write.bytes.data()); - } - } - } -#endif // MOBILEGL_PIPE_PUSH // EXT_buffer_storage bit values (same numeric values as the desktop ARB // tokens); defined locally so this compiles regardless of which GLES headers @@ -2219,14 +1956,10 @@ namespace MobileGL::MG_Backend::DirectGLES { // Queued app writes must land in the backend store before it is read // back, or the writeback below would revert them in the shadow. -#if MOBILEGL_PIPE_PUSH // The shared ladder, by ID-11: a push build has no FlushPendingRangesNow (see // the note at its would-be forwarder), so this arm and the handle arm call the // one body between them. FlushPendingRangesFrom(*resource, bufferObject.MappedData(), bufferObject.GetSize()); -#else - FlushPendingRangesNow(*resource, bufferObject); -#endif BindBufferId(TempBufferTarget, resource->id); void* mapped = g_GLESFuncs.glMapBufferRange(TempBufferTarget, 0, static_cast(size), @@ -2320,7 +2053,6 @@ namespace MobileGL::MG_Backend::DirectGLES { BumpBufferMutationEpoch(); } -#if MOBILEGL_PIPE_PUSH // ---- P3a: the same seven ops plus the create/unmap pair, BY HANDLE ------------ // // Every body below is its Ops_* counterpart above with exactly the substitutions @@ -3439,7 +3171,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #endif #endif }; -#endif // MOBILEGL_PIPE_PUSH const BufferBackendOps g_glesBufferBackendOps = { .Respecify = Ops_RespecifyTracked, @@ -3527,7 +3258,6 @@ namespace MobileGL::MG_Backend::DirectGLES { g_bufferMutationEpoch.fetch_add(1, std::memory_order_release); } -#if MOBILEGL_PIPE_PUSH // The seventh slot table. A process-lifetime global, like the other six, so it links // itself into its own holder list from its own constructor with no initialisation // order question to answer (SlotTables.h). @@ -3629,11 +3359,7 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Pipe::MGPipeSubsystemDependencyWhy(MG_Pipe::kMGPipeSubsystemVertexInput)); return false; } -#if MOBILEGL_PIPE_LEGACY_MEMOS - constexpr Bool kLegacyVaoArmCompiled = true; -#else constexpr Bool kLegacyVaoArmCompiled = false; -#endif // Unlike the buffer family, this one's legacy arm IS conditional: the pre-handle // SyncToBackend body and the twin memos it reads are inside MOBILEGL_PIPE_LEGACY_MEMOS. const PipeSubsystemArmVerdict verdict = @@ -3876,7 +3602,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const MG_Pipe::MGPRange whole{0, MG_Pipe::kMGPipeWholeBuffer}; MG_Pipe::gMGPipeCallbacks.OnGpuWritten(res, 1, &whole); } -#endif // See the declaration: re-mints of a live resource's driver id. Written only on // the context thread (all re-mint sites run there), read only by the VAO sync. @@ -3884,7 +3609,6 @@ namespace MobileGL::MG_Backend::DirectGLES { void RegisterBufferBackendOps() { MG_State::GLState::SetBufferBackendOps(&g_glesBufferBackendOps); -#if MOBILEGL_PIPE_PUSH // P3a: the handle-shaped table goes up beside it, at the same two bring-up sites // and with the same lifetime. Registration is UNCONDITIONAL, exactly as // BufferBackendOps' is: the subsystem bit is the FRONTEND's dispatch predicate @@ -3892,7 +3616,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // build with bit 7 clear registers a table nobody calls and the A/B stays a pure // configuration question rather than a bring-up-order one. MG_Pipe::MGPipeSetResourceOps(&g_glesResourceOps); -#endif // Frontend writes issued while ops were unregistered advanced change // serials with no per-op bump; re-open every draw-clean memo. Advanced directly, // past BumpBufferMutationEpoch's apply-thread pin: a registration mutates no buffer @@ -3907,11 +3630,9 @@ namespace MobileGL::MG_Backend::DirectGLES { if (MG_State::GLState::GetBufferBackendOps() == &g_glesBufferBackendOps) { MG_State::GLState::SetBufferBackendOps(nullptr); } -#if MOBILEGL_PIPE_PUSH if (MG_Pipe::MGPipeGetResourceOps() == &g_glesResourceOps) { MG_Pipe::MGPipeSetResourceOps(nullptr); } -#endif // From here on frontend writes bypass the tracked ops entirely. BumpBufferMutationEpoch(); InvalidateArrayBufferBindingCache(); @@ -3924,14 +3645,12 @@ namespace MobileGL::MG_Backend::DirectGLES { } void OnServerSessionEndedWithOthersLive() { -#if MOBILEGL_PIPE_PUSH // Only what belongs to the ending session: its staged bytes (both stores are // session-scoped). The rings, the ops table and the buffer generation are the // process's and every other session's GL buffers are still alive in the shared group. MGL_SERVER_STAGED_DROP_ALL(); #if MOBILEGL_BUILD_DISAGGREGATED MG_Remote::Server::ServerStagedTexture().DropAll(); -#endif #endif } @@ -3948,7 +3667,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // handles (no GL) and let the next draw / texture upload recreate them. ResetRingForNewContext(UboRing()); ResetRingForNewContext(UnpackRing()); -#if MOBILEGL_PIPE_PUSH // R-11's server copies die with the context for the same reason the rings' ids do: // the resource twins they are keyed by are about to be rebuilt against a new // generation, and a shadow that outlived its twin would be looked up by a RECYCLED @@ -3964,7 +3682,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // imports them again on the new context (EnsureBufferResourceForHandle). ProcessDeferredT0Retires(); SweepT0Retired(/*contextGone=*/true); -#endif #endif } @@ -4032,7 +3749,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return static_cast(bufferObject->GetBackendResource().get()); } -#if MOBILEGL_PIPE_PUSH // The same five questions, asked of the applier instead of the frontend object, with // IDENTICAL semantics (D-A4): // identity the slot table's twin at this handle, not GetBackendResource() @@ -4099,14 +3815,11 @@ namespace MobileGL::MG_Backend::DirectGLES { if (resource->storageSize != static_cast(record->Desc.Width)) return false; return resource->syncedChangeSerial.load(std::memory_order_acquire) == record->Serial; } -#endif Bool IsBufferDrawClean(const MG_State::GLState::BufferObject* frontend, const GLESBufferResource* resource) { -#if MOBILEGL_PIPE_PUSH if (ResourceSubsystemEnabled()) { return IsBufferDrawCleanByHandle(HandleOfBuffer(frontend), resource, frontend); } -#endif // Identity first: a respecify path can hand the frontend a NEW resource; the // memoed pointer is then stale (and only kept alive by the caller's shadow). if (!resource || resource != frontend->GetBackendResource().get()) return false; @@ -4129,7 +3842,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return resource->syncedChangeSerial.load(std::memory_order_acquire) == frontend->GetChangeSerial(); } -#if MOBILEGL_PIPE_PUSH // The handle arm of the ensure path. Same shape, same order, same branches; the four // frontend reads become the applier's stored descriptor, its Serial and the shadow base // the last content-carrying call handed over. @@ -4403,7 +4115,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return resource; } -#endif GLESBufferResource* EnsureBufferResource(const SharedPtr& bufferObject) { #ifdef TRACY_ENABLE @@ -4411,7 +4122,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #endif if (!bufferObject) return nullptr; -#if MOBILEGL_PIPE_PUSH if (ResourceSubsystemEnabled()) { const MG_Pipe::MGPipeHandle res = HandleOfBuffer(bufferObject.get()); if (MG_Pipe::MGPipeHandleIsNull(res)) { @@ -4426,7 +4136,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return EnsureBufferResourceForHandle(bufferObject, res); } -#endif auto* resource = static_cast(bufferObject->GetBackendResource().get()); if (!resource) { @@ -4534,12 +4243,8 @@ namespace MobileGL::MG_Backend::DirectGLES { resource->storageSize != bufferObject->GetSize()) { RespecifyStorageNow(*resource, *bufferObject); } else if (!resource->pendingRanges.empty()) { -#if MOBILEGL_PIPE_PUSH // The shared ladder, by ID-11 - see the note where the forwarder would be. FlushPendingRangesFrom(*resource, bufferObject->MappedData(), bufferObject->GetSize()); -#else - FlushPendingRangesNow(*resource, *bufferObject); -#endif resource->syncedChangeSerial = bufferObject->GetChangeSerial(); } else if (resource->syncedChangeSerial != bufferObject->GetChangeSerial()) { // Ops could not track some writes (e.g. the ops table was @@ -5049,7 +4754,6 @@ namespace MobileGL::MG_Backend::DirectGLES { void UploadRingOnPresent() { RingOnPresent(UploadRing()); } } // namespace BufferImpl -#if MOBILEGL_PIPE_PUSH // ---- P4a (D-K3): the four family arm resolvers, beside BufferImpl's two ---- // // They reuse BufferImpl's ClassifyPipeSubsystemArm / StopOnArmlessPipeSubsystem unchanged: @@ -5644,7 +5348,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return g_backendSamplerViews.HandleOf(textureObject); } } // namespace SamplerViewImpl -#endif namespace VertexArrayImpl { namespace { @@ -5796,24 +5499,8 @@ namespace MobileGL::MG_Backend::DirectGLES { g_GLESFuncs.glVertexBindingDivisor != nullptr; } -#if MOBILEGL_PIPE_LEGACY_MEMOS - // Draw state, not VAO state: set by the baseInstance draw entry points around - // PrepareForDraw and back to zero as soon as the draw is issued. The legacy arm's - // carrier; the handle arm's is MGPipeApplierState::VertexFetchBaseInstance (D-H2). - Uint32 g_pendingFetchBaseInstance = 0; - void SetPendingFetchBaseInstance(Uint32 baseInstance) { - g_pendingFetchBaseInstance = baseInstance; - } - - Uint32 GetPendingFetchBaseInstance() { - return g_pendingFetchBaseInstance; - } -#endif - -#if MOBILEGL_PIPE_PUSH Bool BackendUsesNativeBaseInstance() { return g_GLESCapabilities.SupportsBaseInstance; } -#endif // The "+ baseInstance" of GL's instanced-array element index, expressed as a byte shift // of the array's own offset. Only divisor'd arrays step per instance, so only they move. @@ -5866,7 +5553,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return true; } -#if MOBILEGL_PIPE_PUSH // ---- the handle arm's small helpers ------------------------------------------- // // Each one is its object-shaped counterpart above with the frontend reads replaced by @@ -5995,22 +5681,18 @@ namespace MobileGL::MG_Backend::DirectGLES { if (!*slot) *slot = MakeShared(); return slot->get(); } -#endif // MOBILEGL_PIPE_PUSH void BackendVertexArrayObject::SyncToBackend( const SharedPtr& stateVAOObject) { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif -#if MOBILEGL_PIPE_PUSH if (BufferImpl::VertexInputSubsystemEnabled()) { // Everything this arm needs is in the applier's records; the frontend VAO is // not read at all, which is the whole point of the conversion. SyncToBackendFromApplier(); return; } -#endif -#if !MOBILEGL_PIPE_LEGACY_MEMOS // UNREACHABLE as of M-4: VertexInputSubsystemEnabled() resolves the arm at its first // call, and an armless verdict now stops the process there rather than returning // false into this branch. Kept, and kept loud, because it is the second lock on the @@ -6021,236 +5703,8 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_E_ONCE("MGPipe: the vertex-input subsystem bit is clear and MOBILEGL_PIPE_LEGACY_MEMOS=0 " "removed the pre-handle VAO sync, so this configuration has no arm at all"); return; -#else - if (!stateVAOObject) { - MGLOG_E_ONCE("State VAO object is null, cannot sync to backend."); - return; - } - - MGLOG_D("Syncing VAO with backend ID %u to backend for state ID %u", m_backendVAOId, - stateVAOObject->GetExternalIndex()); - - // One compare instead of MAX_VERTEX_ATTRIBS x 3 per draw: the config version - // aggregates every per-attribute version bump (see the member comment), and the - // index-buffer slot version covers the only other thing this function reads. When - // both are clean there is nothing to emit, and the VAO is not even bound here - - // PrepareForDraw's BindCurrentVAO establishes the draw binding regardless. - const Uint32 currentConfigVersion = stateVAOObject->GetConfigVersion(); - const Uint16 currentIndexBufferVersion = stateVAOObject->GetIndexBufferBindingSlot().GetVersion(); - // A live buffer's driver id was re-minted since this twin's last emit - // (persistent-map adoption / immutable-store retire): every baked binding may - // hold the dead id while every frontend version still matches, so force a - // full re-emit. Read once; each buffer re-mints at most once per walk (its - // first EnsureBufferResource this draw), before its id is baked, so stamping - // the entry value at the end is exact - and a stale stamp only costs one - // extra full emit. - const Uint64 currentBufferIdGeneration = BufferImpl::g_bufferBackendIdGeneration; - const Bool bufferIdsRemitted = m_syncedBufferIdGeneration != currentBufferIdGeneration; - const Bool attributesDirty = - bufferIdsRemitted || !m_hasSyncedConfigVersion || m_syncedConfigVersion != currentConfigVersion; - // Identity joins the version compare: the slot version is a wrapping Uint16, - // so a wrapped-back count with a different buffer bound must still read dirty. - const MG_State::GLState::BufferObject* currentIndexBufferObject = - stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject().get(); - const Bool indexBufferDirty = bufferIdsRemitted || - currentIndexBufferVersion != m_syncedIndexBufferVersion || - currentIndexBufferObject != m_syncedIndexBufferObject; - - // The baseInstance shift lives in the attribute offsets the driver already holds, so - // a change of baseInstance has to re-emit the divisor'd arrays even when the frontend - // config version says nothing moved - and equally has to un-shift them for the next - // draw that carries no baseInstance. Resting state is 0 on both sides, so a program - // that never calls a *BaseInstance entry point never pays for this compare. - const Uint32 fetchBaseInstance = g_pendingFetchBaseInstance; - const Bool baseInstanceDirty = m_syncedFetchBaseInstance != fetchBaseInstance; - // A narrowed GL_DOUBLE stream is derived from the source buffer's CONTENT, and no - // VAO version moves when an app writes into a buffer, so the version gate cannot - // prove such a stream is still current. Re-walk while one is live; the walk itself - // re-checks the buffer's change serial and only re-converts on a real move. - const Bool emitAttributes = attributesDirty || baseInstanceDirty || m_hasConvertedFloat64Attribute; - if (!emitAttributes && !indexBufferDirty) { - return; - } - m_hasConvertedFloat64Attribute = false; - - Bind(); - - const auto& allAttributeVersions = stateVAOObject->GetAllAttributeVersions(); - const auto& allAttributes = stateVAOObject->GetAllAttributes(); - for (Uint attribIndex = 0; attribIndex < allAttributes.size() && emitAttributes; ++attribIndex) { - const auto& attrib = allAttributes[attribIndex]; - // Only the divisor'd arrays carry the shift, and only an enabled one is worth - // re-emitting - a disabled array has no pointer the draw could fetch through, - // and may well have no buffer to bind either. - const Bool needsSyncBaseInstance = baseInstanceDirty && attrib.Enabled && attrib.Divisor != 0; - Bool needsSyncSwitch = allAttributeVersions[attribIndex].SwitchVersion != - m_syncedAttributeVersions[attribIndex].SwitchVersion; - if (needsSyncSwitch) { - if (attrib.Enabled) { - g_GLESFuncs.glEnableVertexAttribArray(attribIndex); - } else { - g_GLESFuncs.glDisableVertexAttribArray(attribIndex); - } - } - - Bool needsSyncFormat = bufferIdsRemitted || allAttributeVersions[attribIndex].FormatVersion != - m_syncedAttributeVersions[attribIndex].FormatVersion; - Bool needsSyncBuffer = bufferIdsRemitted || allAttributeVersions[attribIndex].BufferVersion != - m_syncedAttributeVersions[attribIndex].BufferVersion; - // This is where a 64-bit array is narrowed. glVertexAttribLFormat is a legal call in - // a GL 4.3 context and the frontend RECORDS its format (the state queries have to - // answer), so IsLong does arrive here - what this backend cannot do is feed it at - // full precision: ES has no GL_DOUBLE vertex FORMAT and ESSL has no fp64 type, and - // passing GL_DOUBLE to glVertexAttribPointer would only raise GL_INVALID_ENUM on the - // real driver. But the FORMAT is the only 64-bit thing here: the source bytes are - // ordinary IEEE-754 doubles, and MobileGL already narrows every fp64 value in every - // shader (DemoteFloat64Pass) and every glUniform*d the same way, so the array is - // deinterleaved into a float32 stream and fetched as GL_FLOAT rather than dropped. - // glVertexAttribFormat(GL_DOUBLE) asks for exactly that conversion anyway; the L form - // asks for more precision than any backend here can give, and gets the same stream. - // - // The conversion is deliberately NOT behind the version gate below: it is derived - // from buffer CONTENT, which no VAO version covers. Its own memo (keyed on the - // source buffer's change serial) is what keeps the repeat cost down. - // - // When no stream can be built the array is DISABLED rather than left alone. That - // matters: becoming long bumps FormatVersion, not SwitchVersion, so the - // enable/disable block above will not run again and an already-enabled array would - // stay enabled with no pointer and no ARRAY_BUFFER binding - which did not merely - // raise INVALID_ENUM but had the Adreno driver dereference null inside the next draw - // and take the process with it (SIGSEGV in libGLESv2_adreno, - // KHR-GL43.vertex_attrib_binding.basic-input-case4). - if (attrib.IsLong || attrib.Type == DataType::Float64) { - if (attrib.Enabled && attrib.Type == DataType::Float64 && - SyncFloat64AttributeAsFloat32(attribIndex, attrib, fetchBaseInstance)) { - m_hasConvertedFloat64Attribute = true; - // Explicit, not redundant: an earlier walk that could not build the stream - // disabled this array, and becoming feedable again bumps no SwitchVersion, - // so the enable/disable block above would never turn it back on. - g_GLESFuncs.glEnableVertexAttribArray(attribIndex); - g_GLESFuncs.glVertexAttribDivisor(attribIndex, attrib.Divisor); - continue; - } - if (attrib.Enabled) { - MGLOG_W_ONCE("DirectGLES: vertex attribute %u is a 64-bit (GL_DOUBLE) array whose source " - "stream could not be narrowed to float32 - disabling the array", - attribIndex); - } - g_GLESFuncs.glDisableVertexAttribArray(attribIndex); - continue; - } - - if (!needsSyncFormat && !needsSyncBuffer && !needsSyncBaseInstance) continue; - - // A resolved stride of zero is the binding model's "never advance" (see - // VertexAttribute::Stride) and glVertexAttribPointer cannot say it - a zero - // stride argument there means "tightly packed" instead, i.e. exactly the - // opposite. ES 3.1's binding-point API can, so a zero-stride attribute takes - // that spelling: its own binding point (index == attribute index, the default - // mapping) carrying the buffer, the whole resolved offset and stride 0, with - // the format at relative offset 0. Everything the pointer call would have set - // for this attribute is set here too, so the two spellings stay interchangeable - // from one sync to the next. - if (attrib.Stride == 0 && HasVertexBindingApi()) { - if (!SyncZeroStrideAttribute(attribIndex, attrib)) { - continue; - } - // No BaseInstanceByteShift here on purpose: a zero stride never advances, so - // the shift is zero by construction and adding it would only obscure that. - if (needsSyncFormat) { - g_GLESFuncs.glVertexBindingDivisor(attribIndex, attrib.Divisor); - } - continue; - } - - if (!BindAttributeBuffer(attrib)) { - continue; - } - - // GL_BGRA as a vertex SIZE is desktop-only; ES has no equivalent and rejects - // it. That rejection is not benign: it leaves the array ENABLED with no - // pointer, and the Adreno driver then dereferences null inside the next draw - // and kills the process rather than reporting an error (SIGSEGV in - // libGLESv2_adreno, KHR-GL43.vertex_attrib_binding.basic-input-case5). So the - // refusal has to be observed and the array disabled. - // - // Deliberately ONLY this format. Everything else MobileGL can reach here is ES - // core - the packed 2_10_10_10 pair included, whose size the frontend has - // already pinned to the 4 that ES requires - so nothing else can be refused, - // and the per-draw sync must not grow a glGetError round trip (a driver - // pipeline stall) for the formats real applications actually use. BGRA is also - // still ATTEMPTED rather than refused up front: some ES drivers do accept it, - // and the ones that do should keep working. - const Bool formatMayBeRefused = attrib.IsBgra; - if (formatMayBeRefused) { - while (g_GLESFuncs.glGetError() != GL_NO_ERROR) { - } // start from a clean slate so the check below is about THIS call - } - - const SizeT fetchOffset = attrib.Offset + BaseInstanceByteShift(attrib, fetchBaseInstance); - - if (!attrib.IsInteger) { - // GL_BGRA is passed to the driver as the size argument (the driver reorders BGRA). - const GLint glSize = attrib.IsBgra ? static_cast(GL_BGRA) : attrib.Size; - g_GLESFuncs.glVertexAttribPointer( - attribIndex, glSize, MG_Util::ConvertDataTypeToGLEnum(attrib.Type), - attrib.Normalized ? GL_TRUE : GL_FALSE, attrib.Stride, (const void*)fetchOffset); - } else { - g_GLESFuncs.glVertexAttribIPointer(attribIndex, attrib.Size, - MG_Util::ConvertDataTypeToGLEnum(attrib.Type), attrib.Stride, - (const void*)fetchOffset); - } - - if (formatMayBeRefused && g_GLESFuncs.glGetError() != GL_NO_ERROR) { - MGLOG_W_ONCE("DirectGLES: the driver refused the vertex format of attribute %u " - "(size=%d bgra=%d type=%s) - disabling the array so the draw cannot " - "fetch through a pointer the driver never accepted", - attribIndex, attrib.Size, attrib.IsBgra ? 1 : 0, - MG_Util::ConvertGLEnumToString(MG_Util::ConvertDataTypeToGLEnum(attrib.Type)).c_str()); - g_GLESFuncs.glDisableVertexAttribArray(attribIndex); - continue; - } - - if (needsSyncFormat) { - g_GLESFuncs.glVertexAttribDivisor(attribIndex, attrib.Divisor); - } - } - - if (indexBufferDirty) { - const auto& indexBufferBinding = stateVAOObject->GetIndexBufferBindingSlot().GetBoundObject(); - Bool indexBufferSynced = false; - if (indexBufferBinding) { - auto* backendResource = BufferImpl::EnsureBufferResource(indexBufferBinding); - if (backendResource && backendResource->id != 0) { - BufferImpl::BindBufferId(GL_ELEMENT_ARRAY_BUFFER, backendResource->id); - indexBufferSynced = true; - } else { - MGLOG_W_ONCE("No backend buffer found for index buffer binding, cannot bind index buffer."); - } - } else { - g_GLESFuncs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - indexBufferSynced = true; - } - - if (indexBufferSynced) { - m_syncedIndexBufferVersion = currentIndexBufferVersion; - m_syncedIndexBufferObject = currentIndexBufferObject; - } - } - - if (attributesDirty) { - m_syncedAttributeVersions = allAttributeVersions; - m_syncedConfigVersion = currentConfigVersion; - m_hasSyncedConfigVersion = true; - } - if (emitAttributes) { - m_syncedFetchBaseInstance = fetchBaseInstance; - } - m_syncedBufferIdGeneration = currentBufferIdGeneration; -#endif // MOBILEGL_PIPE_LEGACY_MEMOS } -#if MOBILEGL_PIPE_PUSH // The same function, driven by the applier's records (D-G4). Every branch of the walk // survives - the enable/disable block, the fp64 narrowing with its Adreno disable, the // zero-stride binding-API path, the attribute-buffer bind, the BGRA refusal probe, the @@ -6478,7 +5932,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } m_syncedBufferIdGeneration = currentBufferIdGeneration; } -#endif // MOBILEGL_PIPE_PUSH // THE CLIENT-ARRAY UPLOAD FOR A DRAW WHOSE FETCHED ELEMENTS (first, count) DOES NOT // DESCRIBE. SyncClientSideAttributesForDrawArrays below answers the non-indexed family @@ -6713,129 +6166,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } -#if MOBILEGL_PIPE_LEGACY_MEMOS - Bool BackendVertexArrayObject::SyncFloat64AttributeAsFloat32( - Uint attribIndex, const MG_State::GLState::VertexAttribute& attrib, Uint32 fetchBaseInstance) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - if (attribIndex >= m_convertedAttributeBufferIds.size() || attrib.Size < 1 || attrib.Size > 4) { - return false; - } - const auto& bufferObject = attrib.Buffer; - if (!bufferObject) { - // A client-memory 64-bit array is narrowed on the draw path instead, which is the - // only place its fetch range is known (SyncClientSideAttributesForDrawArrays). - return false; - } - // The frontend shadow is what the conversion reads, so a shader write that has not - // been pulled back yet has to land first. A no-op unless one is outstanding. - bufferObject->SyncGpuWrites(); - const Uint8* const sourceBase = bufferObject->MappedData(); - const SizeT sourceSize = bufferObject->GetSize(); - if (sourceBase == nullptr || attrib.Offset >= sourceSize) { - return false; - } - - const SizeT componentCount = static_cast(attrib.Size); - const SizeT sourceElementSize = componentCount * sizeof(Double); - const SizeT available = sourceSize - attrib.Offset; - if (available < sourceElementSize) { - return false; - } - - // A resolved stride of zero is the binding model's "never advance" (see - // VertexAttribute::Stride): exactly one element exists and every vertex reads it, so - // exactly one is converted. Otherwise the array's extent is the source buffer's own - - // SyncToBackend has no draw range, and a whole-array conversion is affordable because - // it is memoised on the buffer's change serial and 64-bit arrays are vanishingly rare. - const Bool neverAdvances = attrib.Stride <= 0; - const SizeT sourceStride = neverAdvances ? sourceElementSize : static_cast(attrib.Stride); - const SizeT elementCount = neverAdvances ? 1 : ((available - sourceElementSize) / sourceStride) + 1; - - // baseInstance shifts the ELEMENT index of a divisor'd array, and one element of the - // converted stream is componentCount floats. A zero stride never advances, so no - // shift can move it. A shift past the array's own extent has no source data at all. - const SizeT firstElement = (fetchBaseInstance != 0 && attrib.Divisor != 0 && !neverAdvances) - ? static_cast(fetchBaseInstance) - : 0; - if (firstElement >= elementCount) { - return false; - } - - auto& stream = m_convertedAttributeStreams[attribIndex]; - Uint& convertedBufferId = m_convertedAttributeBufferIds[attribIndex]; - const Uint64 sourceLifetimeId = bufferObject->GetLifetimeId(); - const Uint64 sourceChangeSerial = bufferObject->GetChangeSerial(); - // A persistent map is written through the pointer, with no API call to bump the change - // serial (see BufferObject::SyncPersistentMappedRange), so its serial cannot prove the - // converted copy is still current and the memo is never trusted for one. - const Bool memoHit = - stream.valid && convertedBufferId != 0 && !bufferObject->IsBackendPersistentMapped() && - stream.sourceLifetimeId == sourceLifetimeId && stream.sourceChangeSerial == sourceChangeSerial && - stream.sourceOffset == attrib.Offset && stream.sourceStride == sourceStride && - stream.componentCount == componentCount && stream.elementCount == elementCount; - if (!memoHit) { - if (convertedBufferId == 0) { - g_GLESFuncs.glGenBuffers(1, &convertedBufferId); - if (convertedBufferId == 0) { - MGLOG_E_ONCE("Failed to create the float32 scratch buffer for the 64-bit vertex array at " - "attribute %u.", - attribIndex); - return false; - } - } - Vector converted; - NarrowDoubleStreamToFloat32(sourceBase + attrib.Offset, sourceStride, componentCount, elementCount, - converted); - BufferImpl::BindBufferId(GL_ARRAY_BUFFER, convertedBufferId); - g_GLESFuncs.glBufferData(GL_ARRAY_BUFFER, - static_cast(converted.size() * sizeof(Float)), - converted.data(), GL_STREAM_DRAW); - if (MG_Util::PipeStats::Enabled()) { - // The VBO-backed half of the 64-bit narrowing. Same population as the - // client-array half above: a stream the backend synthesises per draw. - MG_Util::PipeStats::AddBytes(MG_Util::PipeStats::ByteClass::StageVertexClient, - static_cast(converted.size() * sizeof(Float))); - } - stream.valid = true; - stream.sourceLifetimeId = sourceLifetimeId; - stream.sourceChangeSerial = sourceChangeSerial; - stream.sourceOffset = attrib.Offset; - stream.sourceStride = sourceStride; - stream.componentCount = componentCount; - stream.elementCount = elementCount; - MGLOG_D("DirectGLES: narrowed the 64-bit vertex array at attribute %u to %zu float32 element(s).", - attribIndex, elementCount); - } - - const SizeT convertedElementSize = componentCount * sizeof(Float); - if (neverAdvances) { - // Only the binding-point API can say "stride 0": glVertexAttribPointer's zero - // means "tightly packed" instead, i.e. the opposite, and would walk the driver - // straight off the end of the single converted element. - if (!HasVertexBindingApi()) { - return false; - } - g_GLESFuncs.glVertexAttribFormat(attribIndex, attrib.Size, GL_FLOAT, GL_FALSE, 0); - g_GLESFuncs.glVertexAttribBinding(attribIndex, attribIndex); - g_GLESFuncs.glBindVertexBuffer(attribIndex, convertedBufferId, 0, 0); - return true; - } - - BufferImpl::BindBufferId(GL_ARRAY_BUFFER, convertedBufferId); - // `normalized` is deliberately GL_FALSE rather than attrib.Normalized: GL ignores it - // for floating-point array types, and honouring it would scale the fetched values - // (KHR-GL43.vertex_attrib_binding.basic-input-case5 passes GL_TRUE and expects 10/20). - g_GLESFuncs.glVertexAttribPointer(attribIndex, attrib.Size, GL_FLOAT, GL_FALSE, - static_cast(convertedElementSize), - (const void*)(firstElement * convertedElementSize)); - return true; - } -#endif // MOBILEGL_PIPE_LEGACY_MEMOS - -#if MOBILEGL_PIPE_PUSH Bool BackendVertexArrayObject::SyncFloat64AttributeAsFloat32ByHandle( Uint attribIndex, const MGPVertexAttribWire& attrib, const MG_Pipe::MGPVertexBuffer& binding, Uint32 fetchBaseInstance) { @@ -6989,7 +6320,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (const void*)(firstElement * convertedElementSize)); return true; } -#endif // MOBILEGL_PIPE_PUSH TwinRegistry g_backendVertexArrayObjects; @@ -7070,7 +6400,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return m_backendTextureId; } -#if MOBILEGL_PIPE_PUSH // P5e (tx2), CONTRACT-P5E §5.2 / scout G-S2-5. See the declaration. void BackendTextureObject::RequireImageBindableStorageByHandle( MG_Pipe::MGPipeHandle res, const MG_Pipe::MGPipeResourceRecord& record) { @@ -7240,7 +6569,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // this transition does not move. m_forceTextureParamsResync = true; } -#endif // Replaces one level's shadow bytes with what the driver texture holds for it, then copies // back the client writes the driver has not been sent yet - exactly the texels written @@ -7265,10 +6593,8 @@ namespace MobileGL::MG_Backend::DirectGLES { const MG_State::GLState::ITextureObject& stateTextureObject, MG_State::GLState::TextureObjectMipmap& mipmapObject, TextureUploadTarget uploadTarget, Uint level -#if MOBILEGL_PIPE_PUSH , const MG_Pipe::MGPipeResourceRecord::PendingUpload* pipePending -#endif ) { const IntVec3 texelSize = mipmapObject.GetMipmapTexelSize(uploadTarget, level); const IntVec3 extent{texelSize.x(), texelSize.y(), std::max(texelSize.z(), 1)}; @@ -7282,7 +6608,6 @@ namespace MobileGL::MG_Backend::DirectGLES { pendingTexels += box.TexelCount(); } if (!pending.empty() && pendingTexels >= texelCount) return false; -#if MOBILEGL_PIPE_PUSH // Every box the entry names, checked against the level before anything is read: a box // outside it is a corrupt record, and the answer is the pre-readback one (keep the // shadow) rather than a copy out of bounds. @@ -7312,7 +6637,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return false; } } -#endif if (mipmapObject.GetMipmapCompressedFormat(uploadTarget, level) != GL_NONE) return false; if (!g_GLESFuncs.glGetTexLevelParameteriv) return false; @@ -7365,7 +6689,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } } -#if MOBILEGL_PIPE_PUSH if (pipePending != nullptr) { // The same merge for the applier's entry: its regions when it carries a list, its // union box when it does not (RegionCount 0 = "the box is the whole story", D-D3). @@ -7391,7 +6714,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } } -#endif Memcpy(shadow, snapshot.data(), shadowBytes); return true; } @@ -7462,7 +6784,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // THE COUNT IS TAKEN WHERE A LEVEL IS ACTUALLY REPLAYED, not on entry (review N-4): a // glBindImageTexture on a texture whose storage is not yet defined reaches here, finds // no defined level and replays nothing. -#if MOBILEGL_PIPE_PUSH // P4a (review M-1): ON THE HANDLE ARM THE RE-DIRTY HAS TO REACH THE APPLIER'S SET, // not only the frontend's model. The client cleared its own flags when it emitted // those levels, so MarkStorageDirty below re-arms a model the handle arm does not @@ -7494,7 +6815,6 @@ namespace MobileGL::MG_Backend::DirectGLES { "pending set - they would be allocated empty", stateTextureObject->GetExternalIndex()); } -#endif if (auto* mipmapObject = MG_State::GLState::AsMipmapTexture(stateTextureObject.get())) { const auto levelCount = mipmapObject->GetMipmapLevelCount(); for (const auto& uploadTarget : stateTextureObject->GetUploadTargets()) { @@ -7502,7 +6822,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const auto levelTexelSize = mipmapObject->GetMipmapTexelSize(uploadTarget, level); if (levelTexelSize.x() <= 0 || levelTexelSize.y() <= 0) continue; if (mipmapObject->GetMipmapByteSize(uploadTarget, level) == 0) continue; -#if MOBILEGL_PIPE_PUSH // This level's entry in the applier's pending set, read BEFORE the re-arm // below turns it into a whole-level box: the client writes it still owes // (see AdoptDriverLevelIntoShadow). Resolved per level - the re-arm may grow @@ -7513,21 +6832,17 @@ namespace MobileGL::MG_Backend::DirectGLES { rearmRecord != nullptr ? FindPipeTextureUpload(*rearmRecord, static_cast(uploadTarget), static_cast(level)) : nullptr; -#endif if (hadBackendStorage && !AdoptDriverLevelIntoShadow(m_backendTextureId, *this, *stateTextureObject, *mipmapObject, uploadTarget, level -#if MOBILEGL_PIPE_PUSH , rearmPending -#endif )) { MGLOG_D("Texture %u level %u: re-minting from the shadow, the driver's copy is not " "readable here", stateTextureObject->GetExternalIndex(), level); } mipmapObject->MarkStorageDirty(uploadTarget, level, true); -#if MOBILEGL_PIPE_PUSH // THE COUNTER BEHIND ROADMAP OPEN QUESTION 2 (final review M-A): once per // transition that replays a level of storage the backend already held, // not once per level. @@ -7550,7 +6865,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(uploadTarget)), static_cast(level), wholeLevel); } -#endif } } } @@ -8350,7 +7664,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return false; } -#if MOBILEGL_PIPE_PUSH // P5e (tx2): the GL name a log line wants, from whichever side of the arm can answer it. // Desc.GlNameForDiag is the declared diagnostics carrier (MGPipeTypes.h) and it is the // ONLY thing the by-handle arm may say about a texture's frontend name - a GL name is @@ -8438,13 +7751,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // storage switch used to ask the frontend object for a value it had just read from the record. #define MGB_TEXTURE_STORAGE_KIND(rec, obj) \ ((rec) != nullptr ? static_cast((rec)->Desc.StorageKind) : (obj)->GetStorageType()) -#else -#define MGB_TEXTURE_HANDLE_ARM_OFF(twin) (true) -#define MGB_TEXTURE_NULL_FRONTEND_REFUSED(twin, entry) (true) -#define MGB_TEXPARAM_TARGET(rec, obj) ((obj)->GetTarget()) -#define MGB_TEXTURE_DIAG_NAME(rec, obj) ((obj)->GetExternalIndex()) -#define MGB_TEXTURE_STORAGE_KIND(rec, obj) ((obj)->GetStorageType()) -#endif // The ES entry point for EXT/OES_texture_view, whichever spelling this driver brought. // Callers must have checked g_GLESCapabilities.SupportsTextureView first - the capability @@ -8755,7 +8061,7 @@ namespace MobileGL::MG_Backend::DirectGLES { (obj)->MarkStorageDirty(tgt, lvl, false); \ } \ } while (0) -#elif MOBILEGL_PIPE_PUSH +#else #define MGB_LEVEL_NEEDS_UPLOAD(obj, tgt, lvl) \ (pushedStorage != nullptr \ ? FindPipeTextureUpload(*pushedStorage, static_cast(tgt), static_cast(lvl)) != nullptr \ @@ -8771,9 +8077,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (obj)->MarkStorageDirty(tgt, lvl, false); \ } \ } while (0) -#else -#define MGB_LEVEL_NEEDS_UPLOAD(obj, tgt, lvl) ((obj)->IsStorageDirty(tgt, lvl)) -#define MGB_LEVEL_UPLOAD_DONE(obj, tgt, lvl) (obj)->MarkStorageDirty(tgt, lvl, false) #endif // THE STORAGE SHAPE, and on the handle arm it is the DESCRIPTOR's (C.3's d2: "the @@ -8808,7 +8111,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // PULL build and P4a's admitted-resize set is EMPTY. Each takes the object it would // otherwise have been spelled on, so the pull expansion is the pre-P4a expression with // one pair of parentheses around the receiver. All are #undef'd with the pair above. -#if MOBILEGL_PIPE_PUSH #define MGB_STORAGE_FORMAT(obj) \ (pushedStorage != nullptr ? static_cast(pushedStorage->Desc.InternalFormat) \ : (obj)->GetFormat()) @@ -8828,15 +8130,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #define MGB_STORAGE_KIND(obj) \ (pushedStorage != nullptr ? static_cast(pushedStorage->Desc.StorageKind) \ : (obj)->GetStorageType()) -#else -#define MGB_STORAGE_FORMAT(obj) ((obj)->GetFormat()) -#define MGB_STORAGE_BASE_SIZE(obj) ((obj)->GetBaseSize()) -#define MGB_STORAGE_LEVELS(obj) ((obj)->GetMipmapLevelCount()) -#define MGB_STORAGE_SAMPLES(obj) ((obj)->GetSamples()) -#define MGB_STORAGE_FIXED_SAMPLE_LOCATIONS(obj) ((obj)->HasFixedSampleLocations()) -#define MGB_STORAGE_IMMUTABLE(obj) ((obj)->IsImmutable()) -#define MGB_STORAGE_KIND(obj) ((obj)->GetStorageType()) -#endif #if MOBILEGL_BUILD_DISAGGREGATED // SHARED IMAGES (docs/Disaggregated/notes/anland/plan-ahb-dmabuf.md). The client defined @@ -9012,7 +8305,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } -#if MOBILEGL_PIPE_PUSH // P4a (D-B3/D-D5): on the handle arm the record IS the state this function reads. // P5e (tx2) hoists the resolution to the TOP of the function, because the view test // below needs it before anything else does; nothing else about it moves. @@ -9039,7 +8331,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } } -#endif #if MOBILEGL_BUILD_DISAGGREGATED // SHARED IMAGES: ahead of the view test and of the staged-store and serial gates below, // none of which knows the texels belong to an image - the staged store holds none of @@ -9097,7 +8388,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // function calls emits one. Pointers INTO record->PendingUploads do not - the // consume is a swap-and-pop - so every one of them is taken, used and dropped // inside one level's iteration, and never held across a consume. -#if MOBILEGL_PIPE_PUSH if (pushedStorage != nullptr) { // THE METADATA RESPECIFY, HONOURED (ID-18 M4, review M-2). BindMask and // ImageBindableHint are STICKY facts the client discovers AFTER allocation - a @@ -9150,7 +8440,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } } -#endif // First-level clean gate (see the member comment): three version compares and no // virtual shape walk. Every mutation the slower probe below would catch bumps one of @@ -9163,9 +8452,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // // LEGACY ARM ONLY from P4a on: the memos it reads are the pre-handle ones and the // record above answers the same question in one compare. -#if MOBILEGL_PIPE_PUSH if (pushedStorage == nullptr) -#endif if (m_isInitialized && m_syncedShapeContextId != 0 && MGB_CTX_LIVE && m_syncedShapeContextId == MGB_CTX->GetTextureContextId() && m_syncedShapeGeneration == MGB_CTX->GetSamplingResolutionGeneration() && @@ -9265,9 +8552,7 @@ namespace MobileGL::MG_Backend::DirectGLES { // IsComplete()/shape walk rather than after it - so this probe would only re-derive // an answer already given, out of the very frontend state the arm exists to stop // reading. -#if MOBILEGL_PIPE_PUSH if (pushedStorage == nullptr) -#endif if (m_isInitialized && stateTextureObject->GetStorageType() == TextureStorageType::Mipmap && m_syncedContentVersion != 0 && m_syncedContentVersion == stateTextureObject->GetContentVersion()) { @@ -9443,7 +8728,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // draw into it stayed masked. The first definition is not a redefinition and // bumps nothing; a redefinition that went through RecreateBackendTexture above // has already bumped. -#if MOBILEGL_PIPE_PUSH // PUSH BUILDS ONLY. This is Espryt code the pull build would share, and G1 // keeps the pull library byte-identical to the P4a baseline (the bump resized // this function and the renderbuffer twin's SyncToBackend: 0/0/2/0). So the @@ -9452,7 +8736,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (m_isInitialized && !m_backendStorageImmutable) { ++FramebufferImpl::g_attachmentBackendIdGeneration; } -#endif // Regenerate all mipmap levels GLenum glInternalFormat, glType, glFormat; @@ -9822,7 +9105,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // own rect model, exactly as before. Both spellings feed the same // three staging shapes and the same StageBlocksIntoUnpackRing, which // is byte-identical (G5). -#if MOBILEGL_PIPE_PUSH const MG_Pipe::MGPipeResourceRecord::PendingUpload* pendingUpload = pushedStorage != nullptr ? FindPipeTextureUpload(*pushedStorage, static_cast(uploadTarget), @@ -9854,9 +9136,6 @@ namespace MobileGL::MG_Backend::DirectGLES { IntVec3{box.X + static_cast(box.W), box.Y + static_cast(box.H), box.Z + static_cast(box.D)}}; }(); -#else - const auto dirtyRegion = textureMipmapObject->GetStorageDirtyRegion(uploadTarget, level); -#endif const SizeT texelCount = static_cast(texelSize.x()) * static_cast(texelSize.y()) * static_cast(std::max(texelSize.z(), 1)); @@ -9880,7 +9159,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // sends. The legacy arm keeps computing them from the level extent // and the bytes-per-texel it just derived - the same two numbers, // from the other side of the wire. -#if MOBILEGL_PIPE_PUSH // m-2: THE PITCH IS THE LEVEL'S (D-D3), so every region of one level // states the same one - and v1 read Regions.front() and would have // strided the rest at the first one's pitch, silently, if a record @@ -9987,10 +9265,6 @@ namespace MobileGL::MG_Backend::DirectGLES { break; } } -#else - const SizeT levelRowBytes = static_cast(texelSize.x()) * bpp; - const SizeT levelSliceBytes = static_cast(texelSize.y()) * levelRowBytes; -#endif const Uint8* regionPtr = static_cast(uploadData) + static_cast(dirtyRegion.lo.z()) * levelSliceBytes + @@ -10009,7 +9283,6 @@ namespace MobileGL::MG_Backend::DirectGLES { dirtyRects[MG_State::GLState::MipmapStorage::kMaxDirtyRects]; SizeT dirtyRectCount = 0; if (subRectEligible) { -#if MOBILEGL_PIPE_PUSH if (pendingUpload != nullptr) { // RegionCount == 0 is LEGAL and means "the union box is the // whole story" (D-D3), which is the same statement the @@ -10045,7 +9318,6 @@ namespace MobileGL::MG_Backend::DirectGLES { region.Z + static_cast(region.D)}}; } } else -#endif #if MOBILEGL_BUILD_DISAGGREGATED // tx: with an active transport the rect list is the record's (the // pendingUpload arm above) or nothing - the server's GPU-dirty mark @@ -10076,7 +9348,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const MG_State::GLState::MipmapDirtyRegion* uploadRects = dirtyRects; SizeT uploadRectCount = dirtyRectCount; if (m_driverMayHoldGpuWrites && regionsAddressable) { -#if MOBILEGL_PIPE_PUSH if (pendingUpload != nullptr) { // The handle arm's footprint is the record's region list, all // of it and in order (MGB_RECT_SRC_PTR indexes the regions by @@ -10090,7 +9361,6 @@ namespace MobileGL::MG_Backend::DirectGLES { region.Z + static_cast(region.D)}}); } } else -#endif #if MOBILEGL_BUILD_DISAGGREGATED // With an active transport and no record behind the level, the // server's own whole-level GPU-dirty mark is the whole story (the @@ -10135,16 +9405,12 @@ namespace MobileGL::MG_Backend::DirectGLES { // lambdas are mangled ...::$_N BY POSITION, so one more renumbers every one of them and moves // the PULL build's symbol set, whose admitted-change set is EMPTY. The pull expansion is the // pre-P4a call with one pair of parentheses. #undef'd with the rest. -#if MOBILEGL_PIPE_PUSH #define MGB_RECT_SRC_PTR(idx, rect) \ ((pendingUpload != nullptr && pendingOffsetsAgree && carriedLayoutApplies && \ static_cast(idx) < pendingUpload->Regions.size()) \ ? static_cast(uploadData) + \ static_cast(pendingUpload->Regions[static_cast(idx)].SrcOffset) \ : rectUploadPtr(rect)) -#else -#define MGB_RECT_SRC_PTR(idx, rect) (rectUploadPtr(rect)) -#endif // A shadow-grid box as the ES image addresses it, and the image height // that strides the source to match; they differ only for a 1D array // (layersAsRows), whose rows are ES layers of a one-texel-high image. @@ -10377,7 +9643,6 @@ namespace MobileGL::MG_Backend::DirectGLES { case TextureStorageType::Buffer: { auto* textureBufferObject = static_cast(stateTextureObject.get()); -#if MOBILEGL_PIPE_PUSH // P5e (tx2), scout R5 RESOLVED. THE BACKING BUFFER IS THE DESCRIPTOR'S, AND SO IS // ITS WINDOW - `Desc.BufferForTexBuffer` names the store and `Desc.BufOffset / // BufSize` name the range, so the frontend binding slot below is not read at all @@ -10417,9 +9682,6 @@ namespace MobileGL::MG_Backend::DirectGLES { const Bool texBufferByRecord = pushedStorage != nullptr && MGB_TEXTURE_HANDLE_ARM_OFF(*this) == false && MGB_TEXTURE_RECORD_ARM_SELECTED(); -#else - const Bool texBufferByRecord = false; -#endif static const SharedPtr kNoFrontendBuffer{}; auto& buffer = texBufferByRecord ? kNoFrontendBuffer : textureBufferObject->GetBufferBindingSlot().GetBoundObject(); @@ -10429,26 +9691,18 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } auto bufferIndex = buffer ? buffer->GetExternalIndex() : 0u; -#if MOBILEGL_PIPE_PUSH // The memo key is the HANDLE's slot on the handle arm: a GL name is never an // identity (section 4.2.1), and the record's Serial covers a slot recycled at a // new generation because a respecify moves it. currentTextureInfo.bufferExternalIndex = pushedStorage != nullptr ? static_cast(pushedTexBuffer.Slot) : bufferIndex; -#else - currentTextureInfo.bufferExternalIndex = bufferIndex; -#endif Bool needsRegeneration = !m_isInitialized || (currentTextureInfo != m_prevTextureInfo); // Need to sync texture buffer if not synced yet -#if MOBILEGL_PIPE_PUSH auto* backendBufferResource = pushedStorage != nullptr ? BufferImpl::EnsureBufferResourceForHandle(buffer, pushedTexBuffer) : BufferImpl::EnsureBufferResource(buffer); -#else - auto* backendBufferResource = BufferImpl::EnsureBufferResource(buffer); -#endif if (!backendBufferResource || backendBufferResource->id == 0) { MGLOG_E_ONCE("Failed to sync backing buffer for texture buffer with ID: %u", MGB_TEXTURE_DIAG_NAME(pushedStorage, stateTextureObject)); @@ -10511,7 +9765,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // whole-buffer forms report offset 0 and the buffer's current size, which // glTexBuffer expresses more directly (and works where the range entry point // is absent). -#if MOBILEGL_PIPE_PUSH // The WINDOW is carried: MGPResourceDesc::BufOffset / BufSize, with // kMGPipeWholeBuffer (~0) meaning "the whole store, resolved live" - which is // why the whole-buffer arm still asks the BUFFER for its size. That is the @@ -10535,12 +9788,6 @@ namespace MobileGL::MG_Backend::DirectGLES { : (pushedStorage->Desc.BufSize == MG_Pipe::kMGPipeWholeBuffer ? (buffer ? buffer->GetSize() : 0u) : static_cast(pushedStorage->Desc.BufSize)); -#else - const Bool wholeBufferRange = textureBufferObject->GetBufferRangeOffset() == 0 && - textureBufferObject->GetBufferRangeSizeInBytes() == buffer->GetSize(); - const SizeT rangeOffset = textureBufferObject->GetBufferRangeOffset(); - const SizeT rangeSize = textureBufferObject->GetBufferRangeSizeInBytes(); -#endif // Through CallTexBuffer/CallTexBufferRange rather than g_GLESFuncs directly: // the unsuffixed entry points are the ES 3.2 core spelling, and a driver // whose buffer textures come from EXT/OES_texture_buffer exports the @@ -10611,7 +9858,6 @@ namespace MobileGL::MG_Backend::DirectGLES { }); m_prevTextureInfo = currentTextureInfo; -#if MOBILEGL_PIPE_PUSH if (pushedStorage != nullptr) { // The handle arm's one stamp. Deliberately AFTER the switch, at the same // instant the legacy arm stamps its four keys, so a bail arm that returned @@ -10625,7 +9871,6 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedResourceSerial = pushedStorage->Serial; return; } -#endif // Everything dirty at entry is uploaded (or provably has no bytes to // upload); stamp the version so per-draw re-syncs short-circuit until // the next CPU-side mutation. @@ -10660,7 +9905,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #undef MGB_STAGED_TEXTURE_LIVE #endif -#if MOBILEGL_PIPE_PUSH // P5e (tx2), CONTRACT-P5E §5.2: THIS TWIN'S OWN RECORD. On the by-handle arm the handle // is already known - the caller resolved the record before it resolved this twin and // noted the handle on the twin itself - so the client allocator is not probed at all. @@ -10752,7 +9996,6 @@ namespace MobileGL::MG_Backend::DirectGLES { m_forceSamplerResync = false; return &cso->Params; } -#endif void BackendTextureObject::SyncBuiltinSamplerToBackend( const SharedPtr& stateTextureObject) { @@ -10781,7 +10024,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // text below the #else is the pre-P4a text token for token, so its object code // cannot move. Routing the pull path through a pointer it did not have before was // measured at -2 bytes on this function, which is a G1 failure. -#if MOBILEGL_PIPE_PUSH const SamplerParameters* pendingSamplerParams = nullptr; // P5e (tx2): resolved ONCE and shared with the target read below, which used to be // the frontend `GetTarget()` this arm was not allowed to make. @@ -10791,7 +10033,6 @@ namespace MobileGL::MG_Backend::DirectGLES { pendingSamplerParams = ResolvePushedBuiltinSampler(stateTextureObject, pushedDesc); if (pendingSamplerParams == nullptr) return; } else { -#if !MOBILEGL_PIPE_LEGACY_MEMOS // UNREACHABLE: ResolveTextureResourceSubsystemArm stops the process at its first // call when the bit is clear and the pre-handle arm is not compiled. Kept, and // kept loud, for the reason the vertex-input arm keeps its twin - this is what @@ -10801,44 +10042,12 @@ namespace MobileGL::MG_Backend::DirectGLES { "MOBILEGL_PIPE_LEGACY_MEMOS=0 removed the pre-handle built-in sampler " "sync, so this configuration has no arm at all"); return; -#else - auto* samplerObject = stateTextureObject->GetSamplerObject().get(); - Uint currentSamplerVersion = samplerObject->GetVersion(); - if (m_syncedSamplerVersion == currentSamplerVersion && !m_forceSamplerResync) { - MGLOG_D("Sampler parameters have not changed for texture ID: %u, skipping sync.", - m_backendTextureId); - return; - } - - m_syncedSamplerVersion = currentSamplerVersion; - m_forceSamplerResync = false; - pendingSamplerParams = &samplerObject->GetAllSamplerParameters(); -#endif - } -#else - auto* samplerObject = stateTextureObject->GetSamplerObject().get(); - Uint currentSamplerVersion = samplerObject->GetVersion(); - if (m_syncedSamplerVersion == currentSamplerVersion && !m_forceSamplerResync) { - MGLOG_D("Sampler parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId); - return; } - m_syncedSamplerVersion = currentSamplerVersion; - m_forceSamplerResync = false; -#endif - -#if MOBILEGL_PIPE_PUSH MGLOG_D("Syncing texture built-in sampler with backend ID %u to backend for state ID %u", m_backendTextureId, TextureDiagName(stateTextureObject, pushedDesc)); auto targetInternal = MGB_TEXPARAM_TARGET(pushedDesc, stateTextureObject); GLenum target = ConvertTextureTargetToBackendGLEnum(targetInternal); -#else - MGLOG_D("Syncing texture built-in sampler with backend ID %u to backend for state ID %u", - m_backendTextureId, stateTextureObject->GetExternalIndex()); - - GLenum target = ConvertTextureTargetToBackendGLEnum(stateTextureObject->GetTarget()); - auto targetInternal = stateTextureObject->GetTarget(); -#endif MGLOG_D(" Texture target for syncing is %s", MG_Util::ConvertTextureTargetToString(targetInternal).c_str()); if (!IsSupportedTextureTarget(targetInternal)) { @@ -10847,11 +10056,7 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } -#if MOBILEGL_PIPE_PUSH const SamplerParameters& samplerParams = *pendingSamplerParams; -#else - const auto& samplerParams = samplerObject->GetAllSamplerParameters(); -#endif if (TextureImpl::IsMultisampleTextureTarget(targetInternal)) { m_cacheSamplerParameters = samplerParams; return; @@ -10928,7 +10133,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #undef SYNC_TEX_SAMPLER_PARAM_IF_CHANGED } -#if MOBILEGL_PIPE_PUSH const MG_Pipe::MGPipeResourceRecord* BackendTextureObject::ResolvePushedTextureParams( const SharedPtr& stateTextureObject) { // P5e (tx2): the handle the caller adopted this twin with, and only failing that the @@ -10958,7 +10162,6 @@ namespace MobileGL::MG_Backend::DirectGLES { m_forceTextureParamsResync = false; return record; } -#endif // P4a (D-E1): the six values SyncTextureParamsToBackend pushes, spelled once per arm. // MACROS, for the reason MGB_LEVEL_NEEDS_UPLOAD gives one function up: in the PULL build @@ -10971,7 +10174,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // only a READ-framebuffer attachment reaches SyncMipmapsToBackend and nothing else. The // FORMAT comes from the descriptor beside them, and the BORDER comes from the built-in // sampler's CSO (D-F4), because a border colour is sampler state. -#if MOBILEGL_PIPE_PUSH #define MGB_TEXPARAM_LEVEL_RANGE \ (pushedRecord != nullptr ? UintVec2{static_cast(pushedRecord->Params.BaseLevel), \ static_cast(pushedRecord->Params.MaxLevel)} \ @@ -11005,16 +10207,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (pushedBorder != nullptr ? pushedBorder->borderColorUI : stateTextureObject->GetBorderColorUI()) #define MGB_TEXPARAM_BORDER_FORM \ (pushedBorder != nullptr ? pushedBorder->borderColorForm : stateTextureObject->GetBorderColorForm()) -#else -#define MGB_TEXPARAM_LEVEL_RANGE stateTextureObject->GetLevelRange() -#define MGB_TEXPARAM_FORMAT stateTextureObject->GetFormat() -#define MGB_TEXPARAM_SWIZZLE stateTextureObject->GetAllSwizzleParams() -#define MGB_TEXPARAM_DS_MODE stateTextureObject->GetDepthStencilTextureMode() -#define MGB_TEXPARAM_BORDER_F stateTextureObject->GetBorderColor() -#define MGB_TEXPARAM_BORDER_I stateTextureObject->GetBorderColorI() -#define MGB_TEXPARAM_BORDER_UI stateTextureObject->GetBorderColorUI() -#define MGB_TEXPARAM_BORDER_FORM stateTextureObject->GetBorderColorForm() -#endif void BackendTextureObject::SyncTextureParamsToBackend( const SharedPtr& stateTextureObject) { @@ -11033,7 +10225,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // Null on the handle arm means "nothing to do" and is NEVER a fall-back to the // frontend; the legacy arm keeps the params-version pair verbatim, token for token, // because the PULL build's object code may not move (D-P). -#if MOBILEGL_PIPE_PUSH const MG_Pipe::MGPipeResourceRecord* pushedRecord = nullptr; const SamplerParameters* pushedBorder = nullptr; // Whether the four border comparands can be READ at all this sync. On the handle arm @@ -11062,46 +10253,18 @@ namespace MobileGL::MG_Backend::DirectGLES { pushedRecord->Params.BuiltinSampler.Gen); } } else { -#if !MOBILEGL_PIPE_LEGACY_MEMOS // UNREACHABLE, and kept loud: see the twin note in SyncBuiltinSamplerToBackend. MGLOG_E_ONCE("MGPipe: the texture-resource subsystem bit is clear and " "MOBILEGL_PIPE_LEGACY_MEMOS=0 removed the pre-handle texture-parameter " "sync, so this configuration has no arm at all"); return; -#else - Uint16 currentTextureParamsVersion = stateTextureObject->GetTextureParamsVersion(); - if (m_syncedTextureParamsVersion == currentTextureParamsVersion && !m_forceTextureParamsResync) { - MGLOG_D("Texture parameters have not changed for texture ID: %u, skipping sync.", - m_backendTextureId); - return; - } - m_syncedTextureParamsVersion = currentTextureParamsVersion; - m_forceTextureParamsResync = false; -#endif } -#else - Uint16 currentTextureParamsVersion = stateTextureObject->GetTextureParamsVersion(); - if (m_syncedTextureParamsVersion == currentTextureParamsVersion && !m_forceTextureParamsResync) { - MGLOG_D("Texture parameters have not changed for texture ID: %u, skipping sync.", m_backendTextureId); - return; - } - m_syncedTextureParamsVersion = currentTextureParamsVersion; - m_forceTextureParamsResync = false; -#endif -#if MOBILEGL_PIPE_PUSH MGLOG_D("Syncing texture params with backend ID %u to backend for state ID %u", m_backendTextureId, TextureDiagName(stateTextureObject, pushedRecord)); auto targetInternal = MGB_TEXPARAM_TARGET(pushedRecord, stateTextureObject); GLenum target = ConvertTextureTargetToBackendGLEnum(targetInternal); -#else - MGLOG_D("Syncing texture params with backend ID %u to backend for state ID %u", m_backendTextureId, - stateTextureObject->GetExternalIndex()); - - GLenum target = ConvertTextureTargetToBackendGLEnum(stateTextureObject->GetTarget()); - auto targetInternal = stateTextureObject->GetTarget(); -#endif MGLOG_D(" Texture target for syncing is %s", MG_Util::ConvertTextureTargetToString(targetInternal).c_str()); if (!IsSupportedTextureTarget(targetInternal)) { @@ -11120,11 +10283,7 @@ namespace MobileGL::MG_Backend::DirectGLES { const Bool isMultisampleTarget = TextureImpl::IsMultisampleTextureTarget(targetInternal); if (isMultisampleTarget) { m_cacheLodRange = MGB_TEXPARAM_LEVEL_RANGE; -#if MOBILEGL_PIPE_PUSH if (borderColorReadable) m_cacheBorderColor = MGB_TEXPARAM_BORDER_F; -#else - m_cacheBorderColor = stateTextureObject->GetBorderColor(); -#endif } Bind(target); @@ -11225,20 +10384,14 @@ namespace MobileGL::MG_Backend::DirectGLES { // float one: two integer borders that differ above 2^24 (16777216 and 16777217, say) // collapse onto the same float, so a float-only comparison would skip the second sync and // leave the driver holding the first value forever. -#if MOBILEGL_PIPE_PUSH // m-3: GATED, because on the handle arm an unreadable border means the CSO record is // missing and the block below is skipped with the refusal already named - so v1's // unconditional initialiser was a live frontend read on a switched-over path whose // value nothing then used. The value a skipped block sees is the cache's own, which // cannot make the condition true. const auto borderColorForm = borderColorReadable ? MGB_TEXPARAM_BORDER_FORM : m_cacheBorderColorForm; -#else - const auto borderColorForm = MGB_TEXPARAM_BORDER_FORM; -#endif if (!isMultisampleTarget && -#if MOBILEGL_PIPE_PUSH borderColorReadable && -#endif g_GLESCapabilities.SupportsTextureBorderClamp && (m_cacheBorderColor != MGB_TEXPARAM_BORDER_F || m_cacheBorderColorI != MGB_TEXPARAM_BORDER_I || @@ -11353,7 +10506,6 @@ namespace MobileGL::MG_Backend::DirectGLES { backendObj->NoteDriverSideWrite(); } -#if MOBILEGL_PIPE_PUSH // P5e (id), CONTRACT-P5E §4.1. See Managers.h for the contract. BackendTextureObject* ResolveTextureTwin(MG_Pipe::MGPipeHandle res) { if (MG_Pipe::MGPipeHandleIsNull(res)) return nullptr; @@ -11395,7 +10547,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (void)storeFollowsTheWrite; #endif } -#endif #if MOBILEGL_BUILD_DISAGGREGATED Bool FollowCopyImageInStagedStore(MG_Pipe::MGPipeHandle source, Uint32 sourceLevel, const IntVec3& sourceOrigin, MG_Pipe::MGPipeHandle destination, Uint32 destinationLevel, @@ -11550,7 +10701,7 @@ namespace MobileGL::MG_Backend::DirectGLES { g_fboSyncedSlotVersions = {0}; g_fboSyncedObjectVersions = {0}; g_fboSyncedObjects = {}; -#if MOBILEGL_PIPE_PUSH && MOBILEGL_ESPRYT_FBO_HANDLE_ARM_MEMOS_LINKED +#if MOBILEGL_ESPRYT_FBO_HANDLE_ARM_MEMOS_LINKED // E's MAJOR-4 / A9: the handle arm's own memos say the same thing about the same // targets, so they are invalidated HERE rather than at each of the nine call sites - // six in DirectGLES.cpp and three in SanityTest.cpp, and it was the three that were @@ -11583,14 +10734,12 @@ namespace MobileGL::MG_Backend::DirectGLES { // Every attachment version is invalidated above, so the next walk re-attaches // everything regardless; stamp the generation so it does not re-arm twice. m_syncedBackendIdGeneration = g_attachmentBackendIdGeneration; -#if MOBILEGL_PIPE_PUSH // The record memos are the gate the PIPE_PUSH arms' attachment walks actually read - // the handle arm has nothing narrower under its key - so leaving them standing here // would let a re-sync of the same record skip the re-attach this function exists to // force. 0 is never a live hash, so a zeroed memo is a guaranteed miss. m_syncedRecordHashes = {0}; m_syncedAttachmentRecordHash = 0; -#endif } static Bool SyncAttachmentObject(GLenum glFBOTarget, @@ -11821,7 +10970,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return false; } -#if MOBILEGL_PIPE_PUSH // THE FOUR CROSS-OBJECT MASKS, ANSWERED FROM THE RECORD (ID-12 DV-5, review M-3 / DV-5). // // All four reduce to (internal format, TEXTURE TARGET) for a texture attachment and to @@ -11900,9 +11048,7 @@ namespace MobileGL::MG_Backend::DirectGLES { } return IsIntegerColorFormat(static_cast(surface.InternalFormat)); } -#endif -#if MOBILEGL_PIPE_PUSH // The record's surface for an attachment POINT, or null when this record does not // describe that point at all. MGPFramebufferState carries Color[8] + Depth + Stencil // (D-C1), which is every point a framebuffer can hold on the handle arm: D-C3 refuses @@ -12116,7 +11262,6 @@ namespace MobileGL::MG_Backend::DirectGLES { surface.Res.Slot, surface.Res.Gen, surface.Kind); return false; } -#endif Uint32 ComputeAlphaWidenedDrawBufferMask(const MG_State::GLState::FramebufferObject& fbo) { using FBO = MG_State::GLState::FramebufferObject; @@ -12184,7 +11329,6 @@ namespace MobileGL::MG_Backend::DirectGLES { return false; } -#if MOBILEGL_PIPE_PUSH const MG_Pipe::MGPFramebufferState* PushedFramebufferRecord(MG_Pipe::MGPipeHandle fbo) { // FramebufferRecordFor answers null for the null handle and for a slot nothing has // described (both silent - that is every framebuffer before its first emission), and @@ -12218,9 +11362,7 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(FramebufferAttachmentType::Color0) + index); } } -#endif -#if MOBILEGL_PIPE_PUSH // P5e (fb, §5.4): the record half of SyncReadBufferToBackend, lifted out of it so the // by-handle sync can run it WITHOUT a frontend object. Nothing inside reads one: the // frontend index was only ever a diagnostic, and it is passed as a number now @@ -12301,14 +11443,12 @@ namespace MobileGL::MG_Backend::DirectGLES { } ApplyReadBufferFromRecord(*record, 0); } -#endif // MOBILEGL_PIPE_PUSH void BackendFramebufferObject::SyncReadBufferToBackend( const SharedPtr& stateFBOObject) { if (!stateFBOObject) { return; } -#if MOBILEGL_PIPE_PUSH // P4a (D-C2): the READ buffer is answered from the RESOLVED read surface of the READ // framebuffer's own record, which is what structurally closes the read-buffer // shared-FBO defect class. The comment two lines below - "when this is reached from @@ -12352,7 +11492,6 @@ namespace MobileGL::MG_Backend::DirectGLES { ApplyReadBufferFromRecord(*record, stateFBOObject->GetExternalIndex()); return; } -#endif auto frontendReadBuf = stateFBOObject->GetReadBuffer(); if (frontendReadBuf == m_frontendReadBuffer) { return; @@ -12472,7 +11611,6 @@ namespace MobileGL::MG_Backend::DirectGLES { stateFBOObject->GetExternalIndex(), (asTarget == FramebufferTarget::Draw ? "DRAW" : "READ")); GLenum glFBOTarget = MG_Util::ConvertFramebufferTargetToGLEnum(asTarget); -#if MOBILEGL_PIPE_PUSH // P4a (D-C2 as corrected by ID-19): THE RECORD OF THIS FRAMEBUFFER OBJECT, resolved // BEFORE the driver framebuffer is bound. // @@ -12527,17 +11665,12 @@ namespace MobileGL::MG_Backend::DirectGLES { } DecodePushedDrawBuffers(*pushedRecord, pushedDrawBuffers.data()); } -#endif Bind(asTarget); // -------------------- Connect attachments (set buffers) ----------------------- // 1. Remap draw buffers -#if MOBILEGL_PIPE_PUSH const FramebufferObject::FramebufferAttachmentArray& stateDrawBuffers = pushedRecord != nullptr ? pushedDrawBuffers : stateFBOObject->GetDrawBuffers(); -#else - auto& stateDrawBuffers = stateFBOObject->GetDrawBuffers(); -#endif Bool drawBufferClean = false; if (memcmp(m_frontendDrawBuffers, stateDrawBuffers.data(), FramebufferObject::MAX_DRAW_BUFFERS * sizeof(FramebufferAttachmentType)) == 0) { @@ -12598,7 +11731,6 @@ namespace MobileGL::MG_Backend::DirectGLES { frontendBuf > FramebufferAttachmentType::Color31) { continue; } -#if MOBILEGL_PIPE_PUSH // ID-12 DV-5 / M-3: on the handle arm the four masks are answered from the // record's own surface for the point this draw buffer names, and the frontend // attachment object below is never touched - the whole arm returns here. @@ -12630,7 +11762,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } continue; } -#endif const auto& attachmentObject = stateFBOObject->GetAttachment(frontendBuf); if (IsSnormFallbackAttachment(attachmentObject)) { snormClampOutputMask |= (1u << i); @@ -12670,7 +11801,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(~0u)); m_syncedBackendIdGeneration = g_attachmentBackendIdGeneration; } -#if MOBILEGL_PIPE_PUSH // P4a (D-C4): the record's ContentHash is what says this framebuffer's resolved state // moved, and it REPLACES the frontend attachment versions AS A KEY. It covers every // field the record carries, so an attachment set that moved, a draw-buffer array @@ -12697,7 +11827,6 @@ namespace MobileGL::MG_Backend::DirectGLES { static_cast(~0u)); m_syncedRecordHashes[SizeT(asTarget)] = pushedRecord->ContentHash; } -#endif const auto& attachments = stateFBOObject->GetAllAttachmentObjects(); const auto& attachmentVersions = stateFBOObject->GetAllFramebufferAttachmentVersions(); for (SizeT i = 0; i < attachments.size(); ++i) { @@ -12725,7 +11854,6 @@ namespace MobileGL::MG_Backend::DirectGLES { frontendType <= FramebufferAttachmentType::Color31 && (static_cast(frontendType) - static_cast(FramebufferAttachmentType::Color0)) < g_GLESCapabilities.MaxColorAttachments; -#if MOBILEGL_PIPE_PUSH // P5e (fb, §5.4): ON THE RECORD ARM THE EMPTY POINT IS THE RECORD'S, and it // is the SAME test SyncAttachmentSurface attaches on - `Kind == None || // Res null`. Asking the frontend here and the record there is what left @@ -12739,13 +11867,9 @@ namespace MobileGL::MG_Backend::DirectGLES { MG_Pipe::MGPipeHandleIsNull(s->Res); }() : attachmentObject.IsEmpty(); -#else - const Bool pointIsEmpty = attachmentObject.IsEmpty(); -#endif if (isColorPoint && pointIsEmpty && glBackendAttachment != GL_NONE) { g_GLESFuncs.glFramebufferRenderbuffer(glFBOTarget, glBackendAttachment, GL_RENDERBUFFER, 0); } -#if MOBILEGL_PIPE_PUSH // M-3: the ATTACHMENT RESOLUTION is the record's on the handle arm. The walk // itself still runs over the frontend's 41 points, because that is what says // which points EXIST and it is also what carries the per-attachment version @@ -12780,11 +11904,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (attachmentSynced) { m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i]; } -#else - if (SyncAttachmentObject(glFBOTarget, attachmentObject, glBackendAttachment)) { - m_syncedFrontendAttachmentVersions[i] = attachmentVersions[i]; - } -#endif } #if MOBILEGL_LOG_ACTIVE_LEVEL <= MOBILEGL_LOG_LEVEL_DEBUG else { @@ -12864,7 +11983,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } -#if MOBILEGL_PIPE_PUSH // ---- P5e (fb, CONTRACT-P5E.md §5.4): the reverse index, texture -> framebuffers ------ // // WHY IT EXISTS. ScopedDetachedTextureFramebufferAttachments used to answer "which @@ -13119,7 +12237,6 @@ namespace MobileGL::MG_Backend::DirectGLES { SyncToBackendByHandle(fbo, asTarget); } } -#endif // MOBILEGL_PIPE_PUSH GLenum BackendFramebufferObject::GetBackendAttachmentType(FramebufferAttachmentType frontendAtt) const { // Only colour attachments are ever relocated; depth/stencil, the default framebuffer's @@ -13498,7 +12615,6 @@ namespace MobileGL::MG_Backend::DirectGLES { constexpr Int kMaxDrainedProgramErrors = 32; TwinRegistry g_backendProgramObjects; -#if MOBILEGL_PIPE_PUSH // ---- P5e (pg): the source, both ways round --------------------------------------- Int ProgramArchiveSource::GetUniformLocation(const String& name) const { @@ -13733,7 +12849,6 @@ namespace MobileGL::MG_Backend::DirectGLES { if (!*slot) *slot = MakeShared(); return slot->get(); } -#endif BackendProgramObjectImpl::BackendProgramObjectImpl() { #ifdef TRACY_ENABLE @@ -13795,7 +12910,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } } -#if MOBILEGL_PIPE_PUSH // P5e (pg). ON A PUSH BUILD THE SIGNATURE IS THE SOURCE'S, TAKEN VERBATIM, and it is not // recomputed here for a reason worth stating: on the handle arm the number the DRAW PATH // compares against is MGPipeShaderCsoRecord::Signature - the CLIENT's commutative hash, @@ -13837,31 +12951,6 @@ namespace MobileGL::MG_Backend::DirectGLES { } return signature; } -#else - Uint64 ComputeShaderStorageBlockBindingSignature(const ProgramBuildSource& src) { - const auto& overrides = src.GetShaderStorageBlockBindingOverrides(); - if (overrides.empty()) return 0; // the overwhelming majority of programs - // Order-independent on purpose: the source is an UnorderedMap, so any signature that - // depended on iteration order would differ between two identical override sets and - // rebuild the program for nothing. - // - // Built from the VALUES, not from a change counter, so re-setting a block to the - // binding it already carries produces the same signature and forces no rebuild - an - // application that calls glShaderStorageBlockBinding every frame with unchanged - // arguments must not retranspile every frame. - Uint64 signature = 0; - for (const auto& [blockName, binding] : overrides) { - if (binding < 0) continue; // never rebound; the declared qualifier still stands - Uint64 entry = std::hash{}(blockName); - // Mixed rather than merely summed with the name hash: name and binding must not - // be able to trade places between two entries and cancel out. - entry ^= (static_cast(static_cast(binding)) + 0x9e3779b97f4a7c15ull + - (entry << 6) + (entry >> 2)); - signature += entry; // commutative combine - } - return signature; - } -#endif namespace { // The GL internal format bound to an image unit right now. GL_NONE for a unit @@ -14967,22 +14056,9 @@ namespace MobileGL::MG_Backend::DirectGLES { // archive, and SyncToBackendByHandle(cso) wraps the RECORD's. That is the whole of this // family's rule F: after this, nothing in a program build dereferences a frontend // object, and the forty accessor calls below read memory the server owns. -#if MOBILEGL_PIPE_PUSH void BackendProgramObjectImpl::SyncToBackendFromSource(const ProgramBuildSource& src) { #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif -#else - void BackendProgramObjectImpl::SyncToBackend( - const SharedPtr& stateProgramObject) { -#ifdef TRACY_ENABLE - ZoneScopedC(TRACY_ZONECOLOR_BACKEND); -#endif - if (!stateProgramObject) { - MGLOG_E_ONCE("State program object is null, skipping backend sync."); - return; - } - const ProgramBuildSource& src = *stateProgramObject; #endif // Recorded before either early return below, so Use() can always name the GL // program a no-op draw belongs to - including the "linked but not drawable" exit. @@ -15981,16 +15057,11 @@ namespace MobileGL::MG_Backend::DirectGLES { // driver used as the ES backend. AFTER the link either way, because it needs the // driver's linked interface. ReseedShaderStorageBlockBindings(m_backendProgramId, src); -#if !MOBILEGL_PIPE_PUSH - m_syncedLinkVersion = src.GetLinkVersion(); - m_syncedImageUnitVersion = src.GetImageUnitVersion(); -#endif m_isInitialized = true; MGLOG_D("Program sync completed. backend ID %u", m_backendProgramId); } -#if MOBILEGL_PIPE_PUSH // ---- the two public heads (P5e pg) ----------------------------------------------- // // THE CLEAN KEYS ARE STAMPED HERE AND NOT IN THE WORKER, because which key is @@ -16084,7 +15155,6 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedShaderCsoSerial = record->Serial; m_syncedBindingsSerial = record->BindingsSerial; } -#endif namespace { // The GL name of the array element that lives at `location`, given the reflection @@ -16295,31 +15365,22 @@ namespace MobileGL::MG_Backend::DirectGLES { m_backendSamplerId = 0; } -#if MOBILEGL_PIPE_PUSH void BackendSamplerObject::SyncToBackend( const SharedPtr& stateSamplerObject, MG_Pipe::MGPipeHandle pushedCso) { -#else - void BackendSamplerObject::SyncToBackend( - const SharedPtr& stateSamplerObject) { -#endif #ifdef TRACY_ENABLE ZoneScopedC(TRACY_ZONECOLOR_BACKEND); #endif if (!stateSamplerObject) { -#if MOBILEGL_PIPE_PUSH // A CSO TWIN HAS NO FRONTEND OBJECT (P4a fable seam F-4, ResolveSamplerCsoTwin): // the content-addressed handle is its identity and the applier's record its // only authority, so a null object beside a live handle is the record arm and // not the pre-P4a error. Everything below that names the object is guarded on // it; the pull build's text is the three lines the #if brackets. if (MG_Pipe::MGPipeHandleIsNull(pushedCso)) { -#endif MGLOG_E_ONCE("State sampler object is null, cannot sync to backend."); return; -#if MOBILEGL_PIPE_PUSH } -#endif } // P4a (D-F1): a SamplerObject is a pure 100-byte value with no driver-side per-object @@ -16331,7 +15392,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // // The whole arm choice is a preprocessor #if/#else so the PULL build's text is the // pre-P4a text token for token (D-P). -#if MOBILEGL_PIPE_PUSH const SamplerParameters* pushedParams = nullptr; // The GL name for the two log lines below, or 0 for a CSO twin, which has no object // to name (F-4): the handle in the same line is its name. @@ -16412,48 +15472,17 @@ namespace MobileGL::MG_Backend::DirectGLES { // below; stated as a return rather than assumed, because that body dereferences // it. if (!stateSamplerObject) return; -#if !MOBILEGL_PIPE_LEGACY_MEMOS // UNREACHABLE: ResolveSamplerSubsystemArm stops at its first call when the bit is // clear and the pre-handle arm is not compiled. Kept, and kept loud. MGLOG_E_ONCE("MGPipe: the sampler subsystem bit is clear and " "MOBILEGL_PIPE_LEGACY_MEMOS=0 removed the pre-handle sampler-version " "memo, so this configuration has no arm at all"); return; -#else - Uint currentSamplerVersion = stateSamplerObject->GetVersion(); - if (m_isInitialized && m_syncedSamplerVersion == currentSamplerVersion) { - MGLOG_D("Sampler parameters have not changed for sampler ID: %u, skipping sync.", - stateSamplerObject->GetExternalIndex()); - return; - } - - m_syncedSamplerVersion = currentSamplerVersion; - pushedParams = &stateSamplerObject->GetAllSamplerParameters(); -#endif - } -#else - Uint currentSamplerVersion = stateSamplerObject->GetVersion(); - if (m_isInitialized && m_syncedSamplerVersion == currentSamplerVersion) { - MGLOG_D("Sampler parameters have not changed for sampler ID: %u, skipping sync.", - stateSamplerObject->GetExternalIndex()); - return; } - m_syncedSamplerVersion = currentSamplerVersion; -#endif - -#if MOBILEGL_PIPE_PUSH MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId, samplerName); -#else - MGLOG_D("Syncing sampler with backend ID %u to backend for state ID %u", m_backendSamplerId, - stateSamplerObject->GetExternalIndex()); -#endif -#if MOBILEGL_PIPE_PUSH const SamplerParameters& samplerParams = *pushedParams; -#else - const auto& samplerParams = stateSamplerObject->GetAllSamplerParameters(); -#endif #define SYNC_SAMPLER_PARAM_IF_CHANGED(internalName, glName, type) \ if (m_cacheSamplerParameters.internalName != samplerParams.internalName) { \ @@ -16565,7 +15594,6 @@ namespace MobileGL::MG_Backend::DirectGLES { Array g_boundSamplersCache; TwinRegistry g_backendSamplerObjects; -#if MOBILEGL_PIPE_PUSH // P4a fable seam F-4. THE TWIN FOR A CONTENT-ADDRESSED SamplerCso HANDLE, keyed by that // handle and synced from its record - see the declaration for why the identity-keyed // lookup it replaces could never hit. @@ -16599,7 +15627,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (*slot)->SyncToBackend(nullptr, cso); return slot->get(); } -#endif } // namespace SamplerImpl namespace RenderbufferImpl { @@ -16646,7 +15673,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // it the same discriminated MGPResourceDesc a texture gets, and this is where that pays: // the same four fields, read out of the same record type, with Desc.Target telling the // applier which of the three per-kind tables the record lives in. -#if MOBILEGL_PIPE_PUSH #define MGB_RBO_FORMAT \ (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.InternalFormat) \ : stateRBOObject->GetInternalFormat()) @@ -16655,12 +15681,6 @@ namespace MobileGL::MG_Backend::DirectGLES { (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.Height) : static_cast(stateRBOObject->GetHeight())) #define MGB_RBO_SAMPLES \ (pushedRecord != nullptr ? static_cast(pushedRecord->Desc.Samples) : static_cast(stateRBOObject->GetSamples())) -#else -#define MGB_RBO_FORMAT stateRBOObject->GetInternalFormat() -#define MGB_RBO_WIDTH static_cast(stateRBOObject->GetWidth()) -#define MGB_RBO_HEIGHT static_cast(stateRBOObject->GetHeight()) -#define MGB_RBO_SAMPLES static_cast(stateRBOObject->GetSamples()) -#endif void BackendRenderbufferObject::SyncToBackend( const SharedPtr& stateRBOObject) { @@ -16675,7 +15695,6 @@ namespace MobileGL::MG_Backend::DirectGLES { MGLOG_D("Syncing RBO with backend ID %u to backend for state ID %u", m_backendRBOId, stateRBOObject->GetExternalIndex()); -#if MOBILEGL_PIPE_PUSH const MG_Pipe::MGPipeResourceRecord* pushedRecord = nullptr; if (TextureResourceSubsystemEnabled()) { #if MOBILEGL_BUILD_DISAGGREGATED @@ -16702,32 +15721,13 @@ namespace MobileGL::MG_Backend::DirectGLES { return; } } else { -#if !MOBILEGL_PIPE_LEGACY_MEMOS // UNREACHABLE: ResolveTextureResourceSubsystemArm stops at its first call when // the bit is clear and the pre-handle arm is not compiled. Kept, and kept loud. MGLOG_E_ONCE("MGPipe: the texture-resource subsystem bit is clear and " "MOBILEGL_PIPE_LEGACY_MEMOS=0 removed the pre-handle renderbuffer " "four-field cache, so this configuration has no arm at all"); return; -#else - if (m_isInitialized && m_cacheInternalFormat == stateRBOObject->GetInternalFormat() && - m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight() && - m_cacheSamples == stateRBOObject->GetSamples()) { - MGLOG_D("RBO %u already initialized with matching parameters, skipping re-allocation.", - stateRBOObject->GetExternalIndex()); - return; - } -#endif } -#else - if (m_isInitialized && m_cacheInternalFormat == stateRBOObject->GetInternalFormat() && - m_cacheWidth == stateRBOObject->GetWidth() && m_cacheHeight == stateRBOObject->GetHeight() && - m_cacheSamples == stateRBOObject->GetSamples()) { - MGLOG_D("RBO %u already initialized with matching parameters, skipping re-allocation.", - stateRBOObject->GetExternalIndex()); - return; - } -#endif // A RE-STORAGE IS A REDEFINITION ON THE SAME DRIVER ID (P4a fable seam F-3, the // pre-handle half): glRenderbufferStorage below re-allocates behind the name the @@ -16736,13 +15736,11 @@ namespace MobileGL::MG_Backend::DirectGLES { // the widening masks of the storage the renderbuffer was attached with. Same // generation a texture re-mint takes, for the same reason; the first allocation is // not a redefinition. -#if MOBILEGL_PIPE_PUSH // PUSH BUILDS ONLY, for the texture twin's reason (G1: the pull library stays // byte-identical to the P4a baseline). if (m_isInitialized) { ++FramebufferImpl::g_attachmentBackendIdGeneration; } -#endif Bind(); @@ -16792,14 +15790,12 @@ namespace MobileGL::MG_Backend::DirectGLES { m_cacheWidth = width; m_cacheHeight = height; m_cacheSamples = samples; -#if MOBILEGL_PIPE_PUSH // Stamped in the same breath as the four cache members and AFTER the allocation, so // an allocation the driver refused with GL_OUT_OF_MEMORY above leaves the twin // describing what it actually holds. The deferred OOM report and its RecordError are // untouched: the error still lands on whatever entry point triggered the sync, which // is where the deferred model puts it. if (pushedRecord != nullptr) m_syncedResourceSerial = pushedRecord->Serial; -#endif m_isInitialized = true; MGLOG_D("RBO %u sync completed. backend ID %u", stateRBOObject->GetExternalIndex(), m_backendRBOId); @@ -16809,7 +15805,6 @@ namespace MobileGL::MG_Backend::DirectGLES { #undef MGB_RBO_HEIGHT #undef MGB_RBO_SAMPLES -#if MOBILEGL_PIPE_PUSH // P5e (fb, CONTRACT-P5E.md §5.4): the same allocation, keyed on the renderbuffer HANDLE. // // THE FOUR VALUES WERE ALREADY THE RECORD'S at P4a (D-D2) - what the object form still @@ -16886,13 +15881,11 @@ namespace MobileGL::MG_Backend::DirectGLES { m_syncedResourceSerial = pushedRecord->Serial; m_isInitialized = true; } -#endif // MOBILEGL_PIPE_PUSH TwinRegistry g_backendRenderbufferObjects; } // namespace RenderbufferImpl -#if MOBILEGL_PIPE_PUSH // ===================================================================================== // P5e SEAMS: DECLARED AND REFUSED HERE, BODIED BY THE FAMILY PACKAGES // (MG_Remote/CONTRACT-P5E.md §4.2; BRIEF-P5E §1's "each such seam is a declared signature @@ -17010,7 +16003,6 @@ namespace MobileGL::MG_Backend::DirectGLES { SyncMipmapsToBackend(kNoFrontendTexture); } -#if MOBILEGL_PIPE_PUSH // P5e (tx2), CONTRACT-P5E §5.2. See the declaration for the clause-by-clause derivation // and for why BOTH halves of each resync pair are read here. Bool BackendTextureObject::IsDrawSyncCleanByRecord(MG_Pipe::MGPipeHandle res, @@ -17058,7 +16050,6 @@ namespace MobileGL::MG_Backend::DirectGLES { // buffer texture's backing store can move without any serial above noticing. return static_cast(record.Desc.StorageKind) == TextureStorageType::Mipmap; } -#endif } // namespace TextureImpl // FramebufferImpl::BackendFramebufferObject::SyncToBackendByHandle and @@ -17072,5 +16063,4 @@ namespace MobileGL::MG_Backend::DirectGLES { // here would make the linker's answer depend on link order, which is the one failure this // block's own comment was written to prevent. -#endif // MOBILEGL_PIPE_PUSH } // namespace MobileGL::MG_Backend::DirectGLES diff --git a/MobileGL/MG_Backend/DirectGLES/Managers.h b/MobileGL/MG_Backend/DirectGLES/Managers.h index 1a906c1f..78e8bd6f 100644 --- a/MobileGL/MG_Backend/DirectGLES/Managers.h +++ b/MobileGL/MG_Backend/DirectGLES/Managers.h @@ -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 -#if MOBILEGL_PIPE_PUSH // P3a: the vertex-input payload views the handle arm of the VAO twin consumes. #include // 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 -#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 class StateBackendObjectRegistry { @@ -334,14 +328,12 @@ namespace MobileGL::MG_Backend::DirectGLES { using BackendMap = UnorderedMap; using iterator = typename BackendMap::iterator; using const_iterator = typename BackendMap::const_iterator; -#if MOBILEGL_PIPE_PUSH using SlotTable = BackendSlotTable; // 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; 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 using TwinRegistry = StateBackendObjectRegistry; -#else - template - using TwinRegistry = StateBackendObjectRegistry; -#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& 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& 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 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 - 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 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& 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& 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 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& SyncTextureObjectToBackend( const SharedPtr& 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& 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& 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& 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 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& 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 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& stateSamplerObject, MG_Pipe::MGPipeHandle pushedCso = MG_Pipe::kMGPipeNullHandle); -#else - void SyncToBackend(const SharedPtr& 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 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& 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 diff --git a/MobileGL/MG_Backend/DirectGLES/SlotTables.h b/MobileGL/MG_Backend/DirectGLES/SlotTables.h index ca1f093c..359b70be 100644 --- a/MobileGL/MG_Backend/DirectGLES/SlotTables.h +++ b/MobileGL/MG_Backend/DirectGLES/SlotTables.h @@ -17,9 +17,7 @@ // translation units that include it without copying Managers.h's include order. #include "DirectGLES.h" -#if MOBILEGL_PIPE_PUSH #include -#endif #if MOBILEGL_BUILD_DISAGGREGATED #include #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 diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index a4fcc049..b600d744 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -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; } diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp index bc050bc2..385e7ed6 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp @@ -21,14 +21,12 @@ #include #include #include -#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 #include #endif -#endif #include #include #include @@ -70,7 +68,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { SessionLocal 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. diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h index b091a291..c8c5ea13 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.h @@ -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 diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h index 962148f8..7a6dcb76 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/MagmaPipeArms.h @@ -10,13 +10,11 @@ #include #include -#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 #include -#endif #include @@ -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(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 diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp index ab45adbf..8be6d298 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/SwapchainObject.cpp @@ -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 -#endif #if defined(__has_include) #if __has_include() @@ -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(defaultFBOInfo->colorAttachment.get()); colorTex->AllocateStorage( diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp index 8738182a..06c7d40a 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.cpp @@ -12,10 +12,8 @@ #include "MG_Backend/DirectVulkan/DirectVulkanResourceState.h" #include "MG_State/GLState/Core.h" #include -#if MOBILEGL_PIPE_PUSH // P5c ev: the GPU-write announcement routes through the reverse channel (R2). #include -#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()) { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp index 91f89dd0..472a4ebd 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.cpp @@ -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(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; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.h index 42b8679d..c6ef477f 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VertexInputStateFactory.h @@ -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 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 diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index ecc46b0c..a7886223 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -19,10 +19,8 @@ #include "MG_State/GLState/Core.h" #include -#if MOBILEGL_PIPE_PUSH // P5c ev: the GPU-write announcement routes through the reverse channel (R2). #include -#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 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(m_config, m_physicalDevice.handle, m_pipeIdentity); -#else - m_vertexInputStateFactory = MakeUnique(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(reinterpret_cast(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(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(ResolveEffectiveSampleMask(rasterizationSamples))); - hash = CombinePipelineStateWord(hash, static_cast(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(std::bit_cast(p.PatchDefaultOuterLevel[i]))); - } - for (Uint32 i = 0; i < 2; ++i) { - hash = CombinePipelineStateWord(hash, - static_cast(std::bit_cast(p.PatchDefaultInnerLevel[i]))); - } - hash = CombinePipelineStateWord(hash, static_cast(p.PolygonModeFront)); - hash = CombinePipelineStateWord(hash, static_cast(p.CullFaceModeSetting)); - hash = CombinePipelineStateWord(hash, static_cast(p.DepthFunc)); - hash = CombinePipelineStateWord(hash, static_cast(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(stencil.FailOp) | - (static_cast(stencil.PassDepthPassOp) << 16) | - (static_cast(stencil.PassDepthFailOp) << 32) | - (static_cast(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(blend.SrcFactorRGB) << 8; - attachmentWord |= static_cast(blend.DstFactorRGB) << 16; - attachmentWord |= static_cast(blend.SrcFactorAlpha) << 24; - attachmentWord |= static_cast(blend.DstFactorAlpha) << 32; - attachmentWord |= static_cast(blend.ColorEquation) << 40; - attachmentWord |= static_cast(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(&vao) != snap.vao || vao.GetLifetimeId() != snap.vaoLifetimeId || vao.GetConfigVersion() != snap.vaoConfigVersion); -#else - const Bool vaoMoved = - static_cast(&vao) != snap.vao || vao.GetLifetimeId() != snap.vaoLifetimeId || - vao.GetConfigVersion() != snap.vaoConfigVersion; -#endif const auto& drawFbo = MGB_CTX->GetFramebufferBindingSlot(FramebufferTarget::Draw).GetBoundObject(); if (static_cast(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(&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(); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 9416fc1f..955b7197 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -32,11 +32,9 @@ #include #include #include -#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 -#endif #include #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 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. diff --git a/MobileGL/MG_Backend/MGPipe/PipeInputs.h b/MobileGL/MG_Backend/MGPipe/PipeInputs.h index 7326404d..3f3f3dee 100644 --- a/MobileGL/MG_Backend/MGPipe/PipeInputs.h +++ b/MobileGL/MG_Backend/MGPipe/PipeInputs.h @@ -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