Files

24 KiB
Raw Permalink Blame History

P5f f0 普查(只读):进程级静态量中语义属于 per-context / per-session 的成员

基线:feat/disaggregated @ 8b68b92c(代码头 25fba0d5,其后提交仅动文档)。 范围:MobileGL/ 下 MG_Backend(DirectGLES / DirectVulkan / MGPipe)、MG_Impl、MG_Pipe、 MG_Remote、MG_State。方法:g_/s_ 前缀可变全局、函数级 static、inline X& = *new X() 单例、命名空间级非常量变量的全面 grep,再逐族读代码确认键控方式与重置时机。 本报告只读产生;未修改任何代码、未构建、未跑测试。

0. 判定框架

P5f 关心的是「换一个地址空间还成立吗」的一个变体:这个静态量的语义寿命跟谁走。

分类 含义
【A】P5f 必须按角色+世代分区 语义属于某个 GL context / session,且当前的重置时机挂在错误的钟上(或不挂任何钟),f1 双块演练下必须暴露
【B】进程级即可 拆进程后每个进程自然各有一份,且持有者在 spawn 后唯一(server 独有 / client 独有),或纯诊断/配置
【C】已是 per-context / per-session 已有世代键控自失效或已有 per-session 重置机制,只需 f1 确认
【D】未知 只读普查不足以判定,标出待 f1/后续包回答的问题

一条贯穿全报告的事实先记住:拆进程后 Espryt/Magma 后端代码只在 server 进程运行,MG_Impl 只在 client 进程运行(P5F-WIRE-COMPLETENESS.md §1.4:「MG_Impl 根本不在 server 进程里」)。所以 MG_Backend 下的静态量天然只需 server 一份、MG_Impl 下的天然只需 client 一份——单看拆进程, 绝大多数成员是安全的。真正的缺陷集中在两类:(1) 重置时机挂错钟(挂 server 自己的钟,而语义属于 client context 世代);(2) 静态量里存着 client 对象的指针/SharedPtr。

1. 已知成员的核实与重置时机

S1 g_syncedRenderStateParameters 家族 —— 【A】

  • 证据:MG_Backend/DirectGLES/DirectGLES.cpp:4584-4617,同族 g_syncedRenderStateVersion、 g_hasSyncedRenderState、g_syncedBackendViewport、g_syncedBackendScissorBox、 g_syncedSrgbFramebufferWrites、g_forceFullRenderStateResync、g_syncedColorMaskAlphaWidenMask、 g_dualSourceDeclinedBlendStates。
  • 语义:「后端 ES context 上当前已推下去的渲染状态」的影子,diff 对象是前端 RenderStateParameters 的版本与字节(DirectGLES.cpp:4629-4660)。即 per-(client context × server ES context) 的乘积状态。
  • 重置时机:RenderStateImpl::InvalidateSyncedRenderState()(DirectGLES.cpp:4618-4623,置 g_forceFullRenderStateResync=true 并清空四个影子)。调用点两个: (a) DirectGLES::MakeCurrent() 尾部(DirectGLES.cpp:15375)——每次 backend make-current; (b) viewport-routing 回放收尾(DirectGLES.cpp:7930)。注意 DestroyEGLContext() (DirectGLES.cpp:15896-15912)的清理清单不含它——靠「新 context 必经 MakeCurrent」兜底。
  • 今天为何能工作:inproc 单进程,ES context 与 client context 同在;ID-67 裁定「相同 tuple 的 make-current 跳过 native bind」,但 BackendObject_DirectGLES.cpp:40-42 的注释写明不同 virtual context 仍进 MakeCurrent,七个缓存在那里统一失效。
  • P5f 处置建议:拆进程后只有 server 持有、重置挂在 server 自己的 MakeCurrent 上,跨进程方向成立; 但 (1) f1 双块下必须把它归入 server 角色的块,使 push-monolith 臂与 server 臂不共享;(2) 待验证点: server ES context 换代(g_backendContextGeneration 在 DirectGLES.cpp:15912 自增)而 client tuple 不变时,MakeCurrent 是否仍被调用——若是则靠 :15375 兜住,若否则此家族缺一条挂 g_backendContextGeneration 的失效线。该点只读无法定论,标为待 f1 双块回答。

S2 ScopedDefaultUnpackState::s_synced 家族 —— 【A】(全清单里最弱的一个)

  • 证据:MG_Backend/DirectGLES/Managers.cpp:6258-6325。类内 static inline 成员: s_synced(:6319)、s_alignment/s_rowLength/s_skipRows/s_skipPixels/s_imageHeight/s_skipImages (:6320-6325)。
  • 语义:后端 ES context 的 GL_UNPACK_* 像素存储状态影子(纹理上传路径的 save/restore)。
  • 重置时机:没有。 s_synced 在 EnsureShadowSynced()(:6283-6300)里一次性置 true 后永不 清除;grep 确认它不在 DestroyEGLContext()(DirectGLES.cpp:15896-15912)的清理清单里, 也不在任何 Invalidate* 里(PixelStoreImpl::InvalidatePackStateCache (Managers.cpp:11565-11567)只动 PACK 侧的 g_packState)。
  • 今天为何能工作:两层巧合——(a) 本类是唯一写者且析构恒恢复到 resting default (4,0,0,0,0,0) (类注释 :6250-6257);(b) 新 ES context 的 GL 默认值恰好等于该 resting default,故 ES context 销毁重建后影子「恰好仍对」。CONTRACT-P5C.md:538-539 已把它与 S1 一起记为 P6 的债,P5f §2.4 收回。
  • P5f 处置建议:把 s_synced=false 挂进 DestroyEGLContext 的清理清单(或挂 g_backendContextGeneration 比较),这是「进程级静态无世代重置」的最小确定样本;f1 双块下归入 server 块。

2. 新发现

S3 后端 memo/影子大家族:键控 (client 上下文 id/serial, g_backendContextGeneration),自失效 —— 【C】

Espryt 的 per-draw memo 几乎全部自带双键:前端侧键(ContextId/ContextSerial/内容哈希)加 g_backendContextGeneration(DirectGLES.cpp:15912 处自增)。全部成员(grep 命中的完整枚举):

成员 位置 键 / 重置
g_observedUnitBindings 等 5 个 DirectGLES.cpp:2767-2771 (contextId, bind generation, maxUnit) 三重门,见 :2773-2782 注释
g_unitTextureSyncListByHandle* 7 个 DirectGLES.cpp:3002-3008 记录臂:(ContextSerial, ViewsSerial, g_backendContextGeneration),:3372/:3404
g_unitTextureSyncList* 7 个 DirectGLES.cpp:3010-3016 前端臂:(ContextId, epoch, generation),:3420/:3464
g_fboTextureSyncList* 8 个 DirectGLES.cpp:3046-3066 {Fbo, ContentHash, ContextSerial, g_backendContextGeneration},:3522/:3550
g_fboAttachmentSyncList* 6 个 DirectGLES.cpp:3073-3078 同上,:3231/:3236
g_readFboAttachmentSyncList* 6 个 DirectGLES.cpp:3082-3087 :3249/:3254
g_readFboTextureSyncList* 8 个 DirectGLES.cpp:3182-3189 :3299/:3330
g_imageSweep* 7 个 DirectGLES.cpp:4013-4024 记录臂三 serial + generation,:4074-4094;前端臂 :4088
g_unitSamplerWalk* 5 个 DirectGLES.cpp:6627-6631 (contextId, epoch, maxUnit, generation) + 行 memcmp,:6640/:6770
g_resolvedTextureBindingMemos + cursor DirectGLES.cpp:6859-6860 每 program 4 槽 round-robin memo,键含 lifetime id(:6921-6940)
g_fboSyncedSerials / g_fboRecordsTrusted DirectGLES.cpp:4137 / :4146 InvalidateFramebufferHandleArmMemos()(:4161-4164),挂 InvalidateFramebufferBindingCache(Managers.cpp:9726)→ MakeCurrent(:15367)与 DestroyEGLContext(:15903-15905)
broadcast memo 7 个 DirectGLES.cpp:5324-5350 PrgramImpl::InvalidateBroadcastMemo()(:5358),挂 MakeCurrent(:15364)与 DestroyEGLContext(:15909)
g_currentDrawFrontendProgram/g_currentDrawBackendProgram/g_currentDrawProgramHandle DirectGLES.cpp:5300-5313 每次 PrepareForDraw/Compute 顶部重写(:5291-5298 注释)
g_passes/g_passCount/g_routedProgram DirectGLES.cpp:7779-7780 每次 replay 收尾清零(:7915-7924)
  • 今天为何能工作:双键俱备且失效方向保守(键不符即重建);MGPipeApplierReset() 在 context 切换 时清空 applier 的记录表,令 ContextSerial/记录哈希侧的键同时移动(DirectGLES.cpp:1022-1029 的注释即此论证)。
  • P5f 处置建议:进程级即可,不新增机制。spawn 后只有 server 跑 Espryt;记录臂的键全部来自 applier 自己的 serial(APPLIER_DERIVED),不依赖 client 内存。f1 双块只需验证 client 角色下无人 读写它们(双块会把这种访问变成具名红)。

S4 纯 server-ES-context 状态(绑定影子 / scratch / 池 / 环 / EGL 句柄)—— 【B】

描述的是 server 自己的 ES context 或 renderer,不携带任何 client 身份。重置统一挂在 DestroyEGLContext()(DirectGLES.cpp:15896-15912,依次调 BufferImpl::OnBackendContextDestroyed (Managers.cpp:3146)、XfbImpl::OnBackendContextDestroyed(DirectGLES.cpp:2067-2074)、 MultiDrawImpl::OnBackendContextDestroyed(MultiDraw.cpp:1086)、OnRestartSubstitutionContextDestroyed、 ScratchFBOImpl::OnBackendContextDestroyed(Managers.cpp:11509)、ReleasePackedWordScratchTexture (DirectGLES.cpp:14150-14155))与 MakeCurrent() 的 Invalidate 序列(:15363-15375):

  • DirectGLES.cpp:g_Display/g_Context/g_Surface/g_Config(:14834-14837,后端唯一 ES context 句柄)、g_requestedSwapInterval(:15229,per-surface,surface 重建时重放)、 g_backendContextOwnerThread(:15289)、g_syncContextGeneration(:15295)、frame fence 环 (:15304-15312)、g_eglVerifiedFrameSerial/g_eglVerifiedContextGeneration(:15415-15416)、 resolve scratch(:9462-9467,自含世代守卫 :9488)、ReplicateBlitImpl(:9777-9789,守卫 :9851)、 DepthStencilSamplingReadImpl(:12876-12911,守卫 :12941)、packed-word scratch (:14101-14103)、restart scratch(:8395-8396)、g_writableImageBufferUnits/g_writableImageBufferUnitCount (:3605-3607)与 g_imageUnitHighWaterMark(:3633,自恢复语义见 :3600-3604 注释)。
  • Managers.cpp:g_backendContextGeneration(:68)、绑定影子(:811-822、:3777-3791、 :4790-4791、:9578-9582 g_activeTextureUnit/g_boundTexturesCache、:11520-11521 pack 影子)、 g_bufferContextGeneration(:826)、deferred releases(:852-857)、buffer pool(:873-875)、 三条 persistent ring(:1017-1039)、g_backendBufferResources(:2873)、g_bufferBackendIdGeneration (:3108)、g_backendSamplerViews(:4649)、g_pendingFetchBaseInstance(:4850)、alpha/integer mask(:9929-9930)、g_attachmentBackendIdGeneration(:11277)、scratch FBO(:11283-11287)、 program 影子(:11571-11574)。
  • MultiDraw.cpp:scratch 组(:329-344)、tier 解析(:464-466)、g_announcedTiers(:483)。
  • BackendObject_DirectGLES.cpp:54-58:native bind 影子,注释自述「Process-wide like the native state it mirrors; under split exactly one DirectGLES object exists (the server's)」。
  • 处置建议:进程级即可;唯一待办是 f1 双块下确认 client 角色不触碰(EsprytSlotTablesEnabled 等 latch 已在拆分臂下拒绝)。

S5 TwinLookupMemo 三件套 + g_fbSlotCache*(legacy 臂)—— 【B】,含一条 D

  • 证据:DirectGLES.cpp:143-152(g_vaoTwinLookupMemo/g_programTwinLookupMemo/g_fboTwinLookupMemo, 仅 MOBILEGL_PIPE_LEGACY_MEMOS 编译)、:167-168(g_fbSlotCacheContext/g_fbSlotCache,pull 或 legacy 臂编译)。
  • 语义:以前端对象地址为键的 memo——per-client-context 语义,因为键是 client 堆地址。
  • 今天为何能工作:memo 注释(:88-102)论证 registry 条目跨 ES context 存活、弱指针防地址复用; g_fbSlotCache 以 context 裸指针为键、指针比较即失效(:155-163)。
  • P5f 处置建议:拆进程后 server 进程没有 client 对象,这两条臂在 server 上根本不编译/不被选中 (句柄臂取代);进程级即可。但留一条【D】:push-monolith 构建下它们仍在运行,若 f1 双块让 monolith 臂与 server 臂同进程共存,这两个 memo 属于 client 角色块——f1 的归属判定要覆盖它们。

S6 XfbImpl 家族:map 里存 client 对象的 SharedPtr —— 【A】

  • 证据:g_xfbObjects(DirectGLES.cpp:1548)、g_currentXfbName/g_currentXfbState (:1549/:1558)、g_scatterBufferId/g_scatterBufferSize(:1545-1546)。XfbObjectState 持有 SharedPtr<MG_State::GLState::BufferObject> buffer(:1511)与 SharedPtr<MG_State::GLState::ProgramObject> scatterProgram(:1538)。
  • 语义:按前端 XFB 对象名键控的捕获状态——per-client-context 语义,且值里嵌着 client 对象指针。
  • 重置时机:XfbImpl::OnBackendContextDestroyed()(:2067-2074)清表——只随 server ES context 销毁走,不随 client context 世代走。
  • 今天为何能工作:同地址空间 + lockstep;P5c 已把 XFB scatter 的读改到 server staged shadow,但 这个 map 的 SharedPtr 成员本身仍在。
  • P5f 处置建议:此项同时落在 §2.6(反向通道触碰 client 内存)的 fv 包里;从静态量角度它必须 按角色+世代分区,且成员里的 SharedPtr 要在 spawn 前换成句柄或 server 侧对象——与 T5 同类的 跨角色持指针。

S7 g_rawDepthFetchSamplerState/g_rawDepthFetchSamplerBackend —— 【D】

  • 证据:DirectGLES.cpp:72-73;惰性构造于 GetRawDepthFetchSampler()(:301-313),无重置点。
  • 语义:raw-depth-fetch 替代的 server 自建 frontend SamplerObject 及其 backend twin(P4a D-F3 具名 保留,:284-300 注释)。
  • 今天为何能工作:内容是不可变常量(构造即定型),SyncToBackend 每次调用重同步。
  • P5f 处置建议:跨进程后 server 自建自持有,方向成立;但 BackendSamplerObject 内部是否持有 driver sampler id(若是,则 ES context 换代后失效无人清)只读未确认——未知,留给 fs 包顺手 回答(一行 grep BackendSamplerObject 的成员即可)。

S8 g_anyProgramRoutesViewportIndex —— 【B】,附注

  • 证据:Managers.cpp:87;置位点 :14028(program link),只升不降,无重置。
  • 语义:「本进程编译过的 program 里是否有任何一个路由 viewport index」的 latch。
  • 今天为何能工作:方向保守——latch 卡在 true 只会多做 viewport routing 检查,不会错画面。
  • P5f 处置建议:进程级即可(per-server-进程的程序集合属性);不需修,仅记录它是「无重置 latch」 家族的一员。

S9 g_bufferMutationEpoch —— 【C】(已被角色守卫钉在 server 侧)

  • 证据:Managers.cpp:834;bump 点全在 Ops_*Tracked 与 DirectGLES 的 6 处 (DirectGLES.cpp:1654/:1679/:1828/:12828/:14393/:14808);P5e 已加 Fatal{RoleViolation, "CurrentBufferMutationEpoch"} 守卫(Managers.cpp:2853)把 GL 线程 bump 钉死(仅 bring-up 例外,:2811-2830 注释),并有 g_bufferMutationEpochBumpsOffTheApplyThread (:2803)计数供测试断言为零。
  • 语义:memo 干净探针的跳过时钟;语义上「谁的 buffer 变了」是 client 事件,但 P5e 已裁定 bump 只 发生在 apply 线程(server 角色)。
  • P5f 处置建议:已是角色正确;进程级即可。f1 双块下它归入 server 块。

S10 Magma(DirectVulkan)—— 【B】

  • g_rendererGeneration(DirectVulkan.cpp:44):per-renderer 世代,renderer 重建时 BumpRendererGeneration()(:51-53);server 独有。
  • g_activeBufferManager(Renderer/VkBufferManager.cpp:56):当前 renderer 的 manager 指针; server 独有。
  • g_dynamicStateShadow(Renderer/VulkanRenderer.cpp:409):Vulkan 动态状态影子,per-renderer。
  • s_warnedHalfTessellatedPipeline(PipelineFactory.cpp:528)、s_warnedInstanceIndexUnsupported (ProgramFactory.cpp:2635):log-once,进程级。
  • 注:VulkanRenderer.h:718-730 的 s_vkResetQueryPool 等是类成员(无 static),不在普查范围。
  • 处置建议:进程级即可。Magma 臂的 lockstep 掩盖问题属 §2.2(fm 包),静态量本身无跨角色语义。

S11 MG_Impl/Pipe 的 client 侧单例群(16 个 Instance() 泄漏单例 + PipeFill 静态)—— 【B】

  • 证据:MG_Impl/Pipe/ 下 CompositeResolver.h:266、CsoCache.h:202、FramebufferEmit.h:656、 ImageEmit.h:194、PipeFill.cpp:1711(publication latch)、ProgramEmit.h:725、 ResourceTracker.h:550、SamplerEmit.h:522(cso cache)/:679(opaque units)/:1082、 SetHashSuppressor.h:130、ShaderBufferEmit.h:273、SlotAllocator.cpp:433、TextureEmit.h:1344、 Tracker.h:932、VertexInputEmit.h:441;CsoCache.h:129 s_hashForTest(测试钩子)。
  • PipeFill.cpp 的命名空间静态:g_lastFillWasBarriered(:486)、g_omission 三件套(:509-511, verify 旋钮)、g_snapshot/g_readScratch(:565-566,verify 双臂)、g_verify(:591)、 g_deferredDestroy*(:1166-1168)、g_fillPlan(:2822)、g_attribDefaultRepairs(:2942)、 g_attribDefaultLastHeader(:2949)、g_residualDue(:3152)、verify 探针 probe(:2664)。
  • 语义:per-client-context/session 的发射与追踪状态。
  • 重置时机:make-current 边沿(tracker.FreshlyPrimed(),PipeFill.cpp:2654-2667;该处同时是 applier_reset 记录的 producer,并做 client 侧的 CsoCache / hash suppressor / vertex-input emitter 重置,CONTRACT-P5C §5.1)。
  • 今天为何能工作:单 client、单 context/session(P5c 裁定每 session 恰一个 context)。
  • P5f 处置建议:进程级即可——spawn 后它们只存在于 client 进程;f1 双块时归入 client 块。多 context 是 P6+ 的形状,MGPApplierReset::ContextSerial 的注释(CONTRACT-P5C §1)已写明。

S12 MG_Impl/GLImpl 的 query/sync 注册表 —— 【B】,含一条多 context 语义债

  • 证据:GL_Query.cpp:55-66(g_queryObjectsMutex/g_liveQueryObjects/g_nextQueryId 与四个 active-query id + pipeline-statistics map)、GL_Sync.cpp:34-37(g_syncObjectsMutex/ g_liveSyncObjects)。
  • 语义:GL 对象(query/sync)按规范是 per-context 的,这里存成进程级注册表。
  • 今天为何能工作:单 context/单 session;mutex 防多 JVM 线程迁移(:50-54 注释)。
  • P5f 处置建议:拆进程后天然在 client 进程,进程级即可;但「语义 per-context、存储 per-process」 这一事实记入 P6+ 多 context 债(与 S11 同一形状)。

S13 MG_Remote 会话单例与跨角色标量 —— 混合

  • ClientSession::g_active(Client/ClientSession.cpp:48)、ServerSession::g_active (Server/ServerSession.cpp:349)、ServerLoop 单例(Server/ServerLoop.cpp:774):每进程一个 session 是设计本身——【B】。
  • g_applyThreadInsideApplier(Client/ClientSession.cpp:118):inproc 下 server 写、client 读的 跨角色共享原子,语义 per-session。CONTRACT-P5C §6(A1)已具名其为 barrier 簿记。拆进程后 client 那份恒 false,但它是 wait-rule 机制的一部分而非状态内容——【A】:f1 双块/角色分区时必须 按角色拆开,否则会漏掉「client 读自己那份永远 false」的假绿。同址的 thread_local g_inBarrierWait(:117)是 client 线程本地,【B】。
  • WireTables.cpp:91-104(g_emitted/g_declined/g_clientTablesUninstalled)、 WireTables.cpp:642(g_applierResetContextSerial,per-session 计数器,client 侧)、 EmitTables.cpp:91-96(drop 旋钮与 g_presentOrdinal/g_publishedMaxRecordBytes)、 EmitTables.cpp:1543(g_fenceMutex)、EmitTables.cpp:711(发射 scratch)、 CapsMirror.cpp:34-40(hook + 计数器)、CapsMirror.cpp:169(单例)、 GpuWritePending.cpp:171(producer marks)、PersistentMapTracker.cpp:85-136(SIGSEGV 追踪): 全部 client 侧,【B】。
  • PipeWireCodec.cpp:347 g_processResolverTable:本进程段表指针,每进程各一份即正确,【B】; 同文件 :355 的 t_activeDecoder 是 thread_local,已是 per-thread。
  • ServerLoop.h:126 g_applyThreadKey:server 线程身份戳,【B】。
  • StagedShadowStore 单例(Managers.cpp:1160-1165):server 侧暂存影子,注释自述「ONE PER PROCESS」,【B】。
  • Transport 的 g_spinItersPerUs(Doorbell.cpp:37)、g_shmCounter(ShmSegmentPosix.cpp:47)、 g_sectionCounter(ShmSegmentWin32.cpp:36):进程级校准/命名计数器,【B】。

S14 MG_Pipe 核心 —— 已知项定位

  • gPipeInputs(MG_Backend/MGPipe/PipeInputs.h:835):P5f §1 的主对象,双块机制(§4)就是为它造 的;不重述。
  • g_applier(MG_Pipe/PipeApply.cpp:433):server-private(CONTRACT-P5C §5.1 裁定),重置经 applier_reset 记录(opcode 77,MGPipeApplierReset(),PipeApply.cpp:1202-1300)——【C】 已是 per-session。
  • PipeRoute.cpp:63-69(g_arm/g_monolithScreen/g_monolithContext/g_monolithEscapes): 路由表与配置,【B】。
  • PipeInputs.cpp:55 g_residualPulls:诊断计数器(rsp),server 侧读,【B】。

S15 MG_State —— 【B】

  • 七个 lifetime-id 分配器(BufferObject.cpp:31、RenderbufferObject.cpp:25、 FramebufferObject.cpp:20、ProgramObject.cpp:27、SamplerObject.cpp:20、TextureObject.cpp:26、 VertexArrayObject.cpp:18)与 s_nextTextureStateContextId(TextureState.cpp:24):client 侧单调 分配器;spawn 后只存在于 client 进程,句柄经记录过线,进程级即可。
  • g_stateObjectDeathOps(StateObjectDeathNotice.h:52)、g_bufferBackendOps (BufferObject.cpp:79):进程级函数表,【B】。
  • g_textureLegacyArmScopeDepth(MipmapStorage.cpp:112)、g_magmaP7AllocatorDebtScopeDepth (SlotAllocator.cpp:118)、g_frontendKeyedRegistryScopeDepth(SlotAllocator.cpp:143):P5c 具名 豁免 scope 的深度计数,守卫簿记而非状态,【B】。
  • ProgramSpirvTask.cpp:35-36:log-once atomic_flag,【B】。
  • MG_Impl/NSOpenGLImpl/NSOpenGLImpl.cpp:32-33:macOS IMP 缓存,与拆分无关,【B】。

3. 汇总

分类 条目
【A】P5f 必须按角色+世代分区 S1(g_syncedRenderStateParameters 家族)、S2(s_synced 家族)、S6(XfbImpl)、S13 中的 g_applyThreadInsideApplier
【B】进程级即可 S4、S5(附一条 D)、S8、S10、S11、S12(附多 context 债)、S13 大部、S14 的 PipeRoute/rsp、S15
【C】已是 per-context/per-session S3(自失效双键)、S9(角色守卫已钉)、S14 的 g_applier
【D】未知 S7(BackendSamplerObject 是否持 driver id);S1 的「ES context 换代且 tuple 不变时 MakeCurrent 是否仍被调用」

最重要的三条结论:

  1. 两个已知成员里,ScopedDefaultUnpackState::s_synced 比 g_syncedRenderStateParameters 弱得多: 前者没有任何重置点(Managers.cpp:6319 一次置位永不清,不在 DestroyEGLContext 清单里),正确性 靠「新 ES context 的 GL 默认值恰好等于影子值」的巧合;后者有 MakeCurrent()(DirectGLES.cpp:15375) 的每次强制全量重推兜底,但兜底链条上「tuple 相同而 ES context 换代」一格只读无法确认(D 项)。
  2. Espryt 的 per-draw memo 大家族(S3)已经自带 (client 键, g_backendContextGeneration) 双键 自失效,是本普查中最大的一类,且全部不需要新机制——f1 双块对它们只需证明 client 角色不触碰。 P5f §2.4 的「完整清单未知」可以收口为:真正缺世代钟的只有 S2、S6、S7 三个小点。
  3. S6(g_xfbObjects 持有 client 对象 SharedPtr,DirectGLES.cpp:1511/:1538/:1548)是本次普查 新发现的、唯一一个「进程级 map 的值里嵌 client 指针」的成员,重置只挂 server ES context 销毁 (:2067-2074),同时属于 §2.6 fv 包的范畴——两个包的清单里都应有它。

附:普查方法的可复现性

grep -rn -E '^\s*(inline\s+)?(static\s+)?[A-Za-z_][A-Za-z0-9_:<>,\s\*&]*[ \*&](g_|s_)[A-Za-z_0-9]+\s*(=[^=]|\[|\{|;)' \
  MG_Backend MG_Impl MG_Pipe MG_Remote MG_State --include='*.cpp' --include='*.h'
# 加上 '= *new ' / 'Instance()' 单例模式的第二轮 grep;全部命中均已人工过目并归入上表。
# 3rdparty/ 子模块不在范围内(其 git 报错为既有噪音)。