Files
MobileGL/docs/Disaggregated/notes/p7/magma-b2.md
T
swung0x48 c997ba9425 [docs] (P7): magma-b2.md carries review round 2 - where the flipped case asserts, the padded stride, one decision per blit, MsFlip1 - two new debt lines, and gates for this tree and the landed one
- §2.9 (new): the lane-marker/backend skips and their verified Skipped lines, the 4-byte row stride and its validation-layer red-once, the whole-call shape decision (the round-1 partial effect: a scaled or X-mirrored COLOR|DEPTH blit wrote its colour and then errored on its depth) with its red-once, the split once-sites, the empty-side decline, MsFlip1 and the exact-one parity tail check, each red-once as run.
- §2.6: MsFlip goes red on a device whose renderbuffer and texture D24S8 map to different VkFormats (cross-format Y decline); §5 item 2 says to check it on the Redmi.
- §2.8: the round-1 bufferRowLength=0 note and the per-aspect decline are marked superseded by §2.9.
- §6: item 1 cites VulkanRenderer.cpp:10066 (the vkCmdBlitImage; :10060 is the vkCmdResolveImage) and states the scale partial effect as closed; item 5 states the X/cross-format-Y partial effect as closed and that its INVALID_OPERATION is a rule I (a) refusal of a legal blit; item 4 counts six knob entries; new item 6 (monolith DirectVulkan flipped/scaled multisample depth blit, VulkanRenderer.cpp:9594/:9608, a wire-vs-monolith divergence where the wire arm is the correct one, P13/G1-bound) and item 7 (Espryt flipped/scaled multisample depth resolve, P3b/P4b); stale WireFramebuffer.inc line numbers refreshed.
- §7 is two labelled rows: this tree (p7/magma-b2@4442ea6d, measured) and the landed tree (pipe@3b66d1b1, integrator-measured), instead of numbers pinned to 5d896170, which is not an ancestor of the landed tree.
2026-09-22 20:49:45 -04:00

38 KiB
Raw Blame History

P7 wave 2-B2:Magma blit / copy / mip 簇里包 B 没有走完的部分(分支 p7/magma-b2)

规范见 CONTRACT-P7.md §0(规则 I / J)、 §3.2(multisample-blit-shape / -aspect 行)、§4.2(棘轮目标与 (B′) 路线)、§5.2; 前一包见 magma-b.md。基线 = feat/disaggregated 上 ~/w7/pipe 的头 ac8065a3(X1、F1、C、A、B 全部落地)。

主机口径与包 B 相同:WSL Arch + lavapipe(/usr/share/vulkan/icd.d/lvp_icd.json), build-split = Release / clang / ccache / DISAGGREGATED=ON INPROC=ON PIPE_PUSH=ON BUILD_INTEGRATION_TEST=ON。本树的 TCP 端口是 40917(MOBILEGL_ITEST_TCP_ENDPOINT): 包 B 用 40913、pipe 用默认的 40613,兄弟树同时在跑时端口会撞,TcpServer.Start 整条车道红。

基线门读数(本树实测,非引自包 B):integration-magma-split 88、-spawn 67、 -tcp 69、integration-magma-full-split 521、ctest -L unit 2420,全绿。 包 B 的报告写的是 84 / 63 / 65,差的四条不是「包 A 在它之后落地」——那句是错的, 审查round 已更正:包 A 在 B 之前落地(5a14e5a1..2f48ccf4 在 c5fa52f9 之前)且只有 +2 (magma-a.md:151-153),另外 +2 是包 C(magma-c.md:59-61)。本树的基线因此是 73 + 11(B)+ 2(A)+ 2(C)= 88 / 67 / 69。

0. 每片一条提交,每片至少一次 red-once

片 名 退役 / decline 提交
1 multisample-blit-shape@P7 缩放/翻转的多重采样颜色 blit 退役;多重采样目的地 decline c77c4f29
2 multisample-blit-aspect@P7 + 烘焙 (A) 第三对 无 resolve 扩展的深/模板 退役(烘焙 pass);改采样数 decline aba21e26
3 MagmaP7AllocatorDebtScope ×2 删除(先证明它们在非 monolith 传输下从不武装) 4bee1313
4 (B′):棘轮的 p7-magma 桶 monolith 臂在 disaggregated 构建里改走烘焙模块 见 §4

grep -rn "@P7" MobileGL/ --include=*.cpp --include=*.inc --include=*.h 在片 2 之后只剩注释 (19 行,全部是「某某退役了」或 red-once 的散文)。树上没有任何一条拒绝再带这个标记。


1. 片 1:multisample-blit-shape@P7

1.1 一个名字下面的两半,问题不是同一个

有臂的那一半:多重采样颜色 blit 的目的矩形与源矩形尺寸不同。vkCmdResolveImage 每侧只带 一个 extent 和一个 offset,既表达不了缩放也表达不了翻转——而这条臂本来就为了翻转先 resolve 进一张单采样 scratch、再对 scratch 做 vkCmdBlitImage。两个 width != |dx1-dx0| 子句 是唯一把缩放挡在同一条路线之外的东西,而 monolith 臂走的正是这条路线 (VulkanRenderer.cpp 的 regionWasTransformed 分支)。子句去掉;scratch 仍按源矩形定尺寸, 所以只有第二段看得见缩放。

顺带的一件事:filter 是从这次缩放起才有意义的——1:1 时 LINEAR 与 NEAREST 读同一个 texel, 所以在此之前没有人问过这个格式能不能被过滤。对 optimalTilingFeatures 缺 SAMPLED_IMAGE_FILTER_LINEAR 的格式传 VK_FILTER_LINEAR 是未定义行为;GL 本来也说多重采样 resolve 忽略 filter,所以回落是 NEAREST 而不是拒绝。

没有臂的那一半:多重采样目的地。vkCmdCopyImage 是唯一能写多重采样图像的命令,它只带一个 extent,而 GL 4.6 core 18.3.1 说任一侧多重采样时两个矩形尺寸不同就是 INVALID_OPERATION。 没有「正确结果」可言,所以按规则 I (a):MGLOG_E_ONCE 写出两个矩形与两个采样数、记 GL 错、 目的地原样不动、会话留下。

1.2 场景与车道

F1WireScenario.MultisampleColorBlitScalesAndFlipsThroughTheResolveScratch 与 …MultisampleBlitOntoAMultisampleDestinationDeclinesAndKeepsTheSession,三臂各两条,前缀 MsBlit.。

split-only,理由和包 B 的 in-place copy 一样、而且更强:monolith 臂对缩放的多重采样 blit 走 vkCmdResolveImage 1:1 落在目的偏移上——缩放被丢掉——所以没有可对照的 DirectVulkan. 读数, 两臂相等的断言等于断言 wire 臂也一样错。

缩放与翻转在同一条用例里、同一个源上,因为它们坏的方式不同:丢了缩放会把 8×4 的带子塞进 4×2 的 附件(驱动直接拒命令),丢了翻转会把对的两个颜色按错的顺序返回。第二次 blit 的期望就是第一次的 期望把两行调过来,所以谁也通不过对方的断言。

1.3 测出来的一件事:decline 的 GL 错晚到

decline 在执行 blit 的地方记错,也就是 server 的 apply 线程,而那个错是跟着后一次 reply 回到 client 队列的,不是跟着 blit 调用。第一次跑的时候它挂在二十行之下那次 1:1 resolve 上—— 一次没有任何毛病的调用。用例里的 glFinish() 因此是承重的,不是礼貌。

1.4 red-once(R-16,两条,均已执行并还原)

  1. 把两个尺寸相等子句放回去 → …ScalesAndFlipsThroughTheResolveScratch 死于 Fatal{UnmigratedVerb, "Magma:multisample-resolve-region"};
  2. 把 MagmaWireFatal("multisample-blit-shape@P7") 放回去 → …DeclinesAndKeepsTheSession 死于该名。

还原后三臂 6/6 绿。

1.5 门

integration-magma-split 90(+2)、-spawn 69(+2)、-tcp 71(+2)、 integration-magma-full-split 523(+2)、ctest -L unit 2420,全绿; fatal_census 79 abort 站点 / 44 家族词 / 0 无标记;link_ratchet --assert-monotone 186 不变; G1 pull .text 0xa52203、nm --defined-only 与 ~/w7/p7-before/pull-syms.txt 逐行相同 (30570 行,0 差异)。


2. 片 2:multisample-blit-aspect@P7 与第三对烘焙模块

2.1 vkCmdResolveImage 只做颜色

Vulkan 里不用 shader 把深度或模板 aspect resolve 下来的唯一办法,是带 depth/stencil resolve 附件的 render pass,它要 VK_KHR_create_renderpass2 和 VK_KHR_depth_stencil_resolve。两个都没有 的设备,在应用第一次 glBlitFramebuffer(GL_DEPTH_BUFFER_BIT)(这就是 GL 里每一次多重采样深度 resolve)时会死于 Magma:multisample-depth-resolve-capability。§3.2 的 aspect 行点了两条臂的名,这一片补上第二条。

WireMultisampleResolve.inc + 三个烘焙模块(一个顶点阶段,每个 aspect 一个片元阶段),取 样本零——和扩展臂要的 VK_RESOLVE_MODE_SAMPLE_ZERO_BIT 同一个样本,所以两条臂在同一台设备上 互换不会改变像素,车道也才断言得动。GL 4.6 core 18.3.1 对模板本来就要求选一个样本,对深度要求 结果落在该像素的 min/max 之间——样本零两边都满足,而平均不满足后者的精神(四个深度的均值是一个 哪里都不存在的表面)。

这条 pass 什么都不带。 scratch 与源同尺寸、同坐标系(两张都是原生图像,彼此不翻转),所以片元 阶段直接用 gl_FragCoord 取址,矩形交给 scissor。没有 push constant,没有 varying,没有前端对象。

模板那一半要扩展才存在:片元着色器没有 VK_EXT_shader_stencil_export 根本写不了模板 aspect。 没有它就 decline 模板(§3.2 原话),而且模块本身不创建——把带不支持 capability 的 SPIR-V 交给 vkCreateShaderModule 是未定义行为,不是一个能接住的错误。

两个能力判据不是同一个判据,差别是结构性的:subpass resolve 的是格式拥有的每一个 aspect, 所以每个都要有 mode;而上面这条 pass 只写这次 blit 要的那一个 aspect,scratch 其余部分留成未定义 ——安全,因为随后的 copy 读的正是那一个 aspect。

2.2 没有臂的那一半

采样数不同、且目的地是多重采样的那一侧:一个样本铺成 N 个,或 N 个降成 M 个。 vkCmdResolveImage 只写单采样目的地,vkCmdBlitImage 两侧都拒绝多重采样,vkCmdCopyImage 要求 两个数相等。decline。

2.3 场景与车道

用例是提拔来的,不是新写的。 DepthStencilReadbackMatrixScenario.AResolvedMultisampleDepth… 本来就拥有这个可观测(清一张 4× DEPTH24_STENCIL8、用 glBlitFramebuffer resolve 进单采样、两个 aspect 都读回、并检查只做深度的 resolve 没动目的地的模板、反之亦然),而且本来就在三条 Magma 臂 的信息档(…Full.)里跑。缺的只是一条 gating 条目。

MsResolve0. 在三臂都注册;MsResolve1. 只在 split 和 spawn(审查 round 的修正,见 §2.7)。 第二条是那条臂在此唯一可达的方式:lavapipe 两个 resolve 扩展都有,扩展臂会接下本机的每一次 resolve。MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE 丢掉扩展臂。 它在本机不 skip:lavapipe 也带 VK_EXT_shader_stencil_export,所以 shader 臂深度和模板都走通了。 新增的 F1 用例是那条 decline。

集成者交代里写的「可能在 lavapipe 上 SKIP(分离的 D24/S8 不支持)」本树没有发生: 提拔的这条用例用的是合并的 DEPTH24_STENCIL8,分离 D24/S8 是同一文件里另一条用例 (SeparateDepthAndStencilAttachmentsAreBothReadable)的事,没有提拔。

MOBILEGL_BAKED_INTERNAL_SHADERS 的表从 8 行涨到 11 行。

2.4 red-once(R-16,三条,均已执行并还原)

  1. shader 臂:把 MagmaWireFatal("multisample-depth-resolve-capability") 放回非扩展臂 → DirectVulkan.Split.MsResolve1.… 死于该名,而 MsResolve0(扩展臂)仍然绿——这同时是旋钮 确实改道的证明;
  2. aspect decline:把 MagmaWireFatal("multisample-blit-aspect@P7") 放回去 → DirectVulkan.Split.MsBlit.…FromASingleSampleSourceDeclines… 死于该名;
  3. 新鲜度门:把 WireMultisampleStencilResolve.frag 的取样索引从 0 改成 1(不需要重建—— 门在运行时读源)→ WireMultisampleStencilResolveFragment 在第 158 个字变红,并指名符号、 头文件与重新生成的命令。

还原后三臂 15/15 绿、新鲜度门 11/11 绿。

2.5 门

integration-magma-split 93(+3)、-spawn 72(+3)、-tcp 74(+3)、 integration-magma-full-split 524(+1)、ctest -L unit 2423(+3),全绿; bake_internal_shaders.py --check 五个头全新鲜;fatal_census 79 / 44 / 0; link_ratchet --assert-monotone 186 不变;G1 .text 0xa52203、符号表逐行相同。

上面这三个 +3 是片 2 落地当天的读数,那时 MsResolve1. 还注册在 tcp 上。审查 round 把它从 tcp 摘掉了(§2.7),tcp 的最终读数在 §7。

2.6 欠设备核对

shader resolve 臂正是手机在没有 VK_KHR_depth_stencil_resolve 时会走的那条,而本机只能经旋钮 到达它。它的几何要在 Redmi 上看一眼。

MsFlip. 在格式分叉的设备上会红(审查 round 2 补记):场景的多重采样源是 renderbuffer DEPTH24_STENCIL8,目的地是 texture DEPTH24_STENCIL8。本机两者都映射到 VK_FORMAT_D24_UNORM_S8_UINT,所以 Y 翻转走同格式的逐行 copy-out。一台把 renderbuffer 与 texture 的 D24S8 映射到不同 VkFormat 的设备(例如 texture 侧退到 D32_SFLOAT_S8_UINT)会在 DeclineWireDepthStencilResolveShape 的跨格式 Y 镜像 decline 上拿到 INVALID_OPERATION, MsFlip. / MsFlip1. 因此变红——那不是回归,是 §6 第 5 条那笔债在该设备上可见了。上 Redmi 前先看它的 两种映射是否相同。

2.7 审查 round:一个 server 端旋钮没有 tcp 臂

MGITEST_MAGMA_FORCE_* 三个旋钮都由 server 读(WireFramebuffer.inc 的三个 std::getenv 跑在 apply 线程上),而 ctest 的 ENVIRONMENT 属性只到达 ctest 启动的那个进程,也就是 client。 三条臂的 server 来处不同:

臂 server 从哪来 旋钮到得了吗
inproc 同进程的一个线程 到
spawn ServerSpawn.cpp:106 把 ::environ 复制进子进程 到
tcp 车道级 TcpServer.Start fixture,由 scripts/ci/tcp_server_fixture.py 用它自己的 os.environ 在任何用例之前启动一次,每个 Hello fork 一个会话子进程 到不了

所以一条 tcp 的旋钮条目跑的是默认臂,名字却宣称不是——对 ShaderMip 而言,这正是那条用例自己的 skip 文案说不许发生的事(「would assert the native blit twice over」)。

实测,不是推导:在三个 reader 里各放一个临时 fatal,五条 knob=1 条目在 split 全死、在 spawn 全死、在 tcp 五条全绿;五条 knob=0 的孪生条目三臂全绿。

修法用的是 ID-P7-14 MAGMA_INPROC_ONLY 的先例:scripts/ci/spawn_lane_parity.py 新增 MAGMA_SERVER_ENV_KNOB_NO_TCP,并给 compare_arms 加一个 no_tcp= 参数。它和 inproc_only= 不是同一个形状,这一点是承重的:inproc_only 把键从每一条非 split 臂的比较里拿掉,而这五条 必须在 spawn 上仍然被要求——spawn 才是它们干活最多的地方。受影响的五条是 .ShaderMip1. .ShaderMip2. .DepthMip. .DefaultBlitShape1. .MsResolve1.;knob=0 的 .DefaultBlitShape0. / .MsResolve0. 留在三臂,因为零就是默认值,那两条在三臂含义相同。

其中三条(ShaderMip1/2、DepthMip、DefaultBlitShape1)是包 B 既有的同种空转,一并修。

这是一笔债而不是一个结论:要让 tcp 车道也能带这些条目,fixture 得接受每用例的 server 环境 ——那是一个 supervisor 控制项,不是一个 ctest 属性。记在 §6。

2.8 审查 round:翻转和缩放的深/模板 resolve 不再带走会话

ResolveWireDepthStencil 的区域判据要求 sx1 > sx0 且 sy1 > sy0,否则 Magma:multisample-depth-resolve-region 带走会话。于是

glBlitFramebuffer(0, h, w, 0,  0, 0, w, h,  GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

从一个多重采样 framebuffer 出发时,颜色 blit 正确完成(颜色臂自 P5f 起就会翻转,本包又给了它 缩放),然后死在深度上。GL 4.6 core 18.3.1 要求的是尺寸相同而不是角点相同(Mesa 比的是 abs()),所以翻转是一次合法的 blit,欠一张镜像的图。

拆成三块:

  1. 缩放 → 规则 I (a) 具名 decline。18.3.1 说尺寸不同就是 INVALID_OPERATION,没有「正确结果」。
  2. Y 翻转、同格式 → 退役:copy-out 那一步本来就是「image → buffer → image」,而 buffer copy 是按行寻址的,所以每行一个 VkBufferImageCopy、倒着走,就是一次垂直镜像。(round 1 让 bufferRowLength 保持 0、行紧贴;那违反深/模板 copy 的 4 字节 bufferOffset 对齐,round 2 把行距 补齐到 4 字节,见 §2.9。)
  3. X 翻转,以及跨格式的 Y 翻转 → 具名 decline。横向镜像要一个 region 一个 texel,那已经 不是 copy 了;跨格式重编码走 BlitDepthAcrossFormats(与 monolith 臂共用),它也没有翻转。 两条都进 §6。 (round 1 的这两条 decline 与第 1 条的缩放 decline 都是在颜色 aspect 已经写完之后才决定的—— 一次部分生效,GL 不允许。round 2 把决定提到任何 aspect 之前,见 §2.9 第 3 条。)

span 从此是有符号的,下游一律用 min 角(sxMin/syMin/dxMin/dyMin),render pass 的 renderArea、 shader 臂的 scissor、buffer copy 的 imageOffset、BlitDepthAcrossFormats 的四个角全部跟着改。

场景:DepthStencilReadbackMatrixScenario.AFlippedMultisampleResolveMirrorsTheBandsAndAScaleDeclines, 三臂各一条,前缀 MsFlip.,不需要旋钮(两种形状都在能力问题之前由矩形决定)。 颜色和深度在同一次调用里,因为那正是让这件事显形的形状;两条带子深度不等(下 0.25 / 上 0.75), 并且颜色也断言了同一个方向——一次「假翻转」(比如只是把读回顺序倒过来)会让颜色和深度不一致。

red-once(R-16,三条,均已执行并还原,split + spawn 各一遍;审查 round 的第二个会话又亲手各跑了一遍):

  1. 把旧判据放回去(spanX <= 0 || spanY <= 0 || spanX != dstSpanX || spanY != dstSpanY → Fatal) → 两臂都死于 Fatal{UnmigratedVerb, "Magma:multisample-depth-resolve-region"};
  2. 只把缩放那条 decline 换回旧 Fatal(翻转路径不动)→ 翻转那一半通过,两臂都在缩放那一步死于 同一个名字——证明缩放 decline 是承重的,而不是被翻转那条红顺带盖住;
  3. 把 copy-out 的 if (!mirrorY) 改成恒真(即拿掉逐行倒序,其余一律不动)→ 两臂都活着但深度 带子上下颠倒:flipped resolve: the destination's bottom band: 768 of 768 depth values differ from 0.75; first bad value 0.25(顶带反之)。这一条才是对新代码的断言——它证明那张镜像的图 是逐行倒序产生的,不是别处的副作用。

2.9 审查 round 2:在哪些臂上断言、行距、以及「一次调用一个答案」

1. 用例只在 Magma wire 臂上断言。 DepthStencilReadbackMatrixScenario 整套被 monolith DirectVulkan. 臂和每一条 DirectGLES 臂发现,于是 round 1 的新用例在它们上面全红:monolith 拒绝 翻转的深度 blit(VulkanRenderer.cpp:9594「depth blits with flipped rectangles are not supported yet」,目的地保持清屏值、无错误)并缩放一次 GL 说是 INVALID_OPERATION 的多重采样深度 blit (:9608);Espryt(monolith 与 split 一样)翻转时什么也不写、也不报错,缩放时也不报错。用例先按 Gl().BackendName() != "DirectVulkan" 跳过(Espryt 文案,P3b/P4b),再按 SplitLane::IsSplitLane() 跳过(monolith 文案,P13/G1)。实测: DirectVulkan.DepthStencilReadbackMatrixScenario.AFlipped… 与 DirectGLES.{,ForcedDepthStencilEmulation.}DepthStencilReadbackMatrixScenario.AFlipped… 均为 Skipped,理由即上;三条 DirectVulkan.{Split,Spawn,Tcp}.MsFlip. 仍然武装并通过。两笔差异进 §6 第 6、7 条。(行号是 pipe 上的。)

2. copy-out 的行距补齐到 4 字节。 深/模板目的地的 buffer→image copy 要求每个 bufferOffset 是 4 的倍数(VUID-vkCmdCopyBufferToImage-dstImage-07978,旧层叫 pRegions-07978)。§2.8 的逐行 镜像把第 r 行放在 r * width * texelSize:模板 aspect(1 字节)宽度不是 4 的倍数、或 D16(2 字节) 宽度为奇数时,第一行之后的每一行都违规——而 BlitWireFramebuffers 的 scissor 裁剪恰好产生任意宽度。 改为 paddedWidth = AlignUp(width, 4 / texelSize),buffer 取 paddedWidth * height * texelSize, 两次 copy 都以 paddedWidth 作 bufferRowLength,第 r 行从 r * paddedWidth * texelSize 开始。 场景加一条模板腿:源的模板带 11 / 99,一次 29×32、从 (5, 8) 到 (20, 4) 的翻转 GL_STENCIL_BUFFER_BIT blit,目的地每个模板值都按镜像带或原封的 3 核对。

red-once(split + spawn,VK_LOADER_LAYERS_ENABLE=*khronos_validation):lavapipe 不强制这条 VU, 未补齐的代码读回的模板字节是对的,所以红的是校验层——每臂 10 条 pRegions[1].bufferOffset (29) must be a multiple 4 if using a depth/stencil format (VK_FORMAT_D24_UNORM_S8_UINT);补齐之后校验层零错误(任何 VUID)。

3. 一次调用一个答案。 颜色 lambda 先跑,所以 round 1 的形状 decline 是逐 aspect 决定的: 一次缩放的 COLOR|DEPTH 多重采样 blit 先把颜色缩放写进去,然后在深度上记 INVALID_OPERATION;一次 X 镜像的则镜像了颜色、留下深度不动、再报一个 GL 本不会报的错。18.3.1 说出错的 blit 什么也不写。修法(本 round 做了,不是记债):形状判据搬进 DeclineWireDepthStencilResolveShape,BlitWireFramebuffers 在任何 aspect 之前对 mask 里每个 会走多重采样 resolve 臂的深/模板 aspect 问一次,decline 则整个调用返回;ResolveWireDepthStencil 为其它调用者也问一次。默认 read/draw framebuffer 留给 lambda(默认 read 从不是多重采样;默认 draw 在多重采样 read 后面本就是 region Fatal,提前解析它还会挪动写索引)。 顺带:X 与跨格式 Y 两种 decline 各有自己的 MGLOG_E_ONCE(原来共用一个,首次 X 之后跨格式 Y 不再 留痕);只有一侧为空的矩形(64×48 → 0×48)走缩放 decline 报 INVALID_OPERATION,不再静默返回。

4. MsFlip1.。 无旋钮时 lavapipe 的每次 resolve 都走扩展臂,shader 臂在翻转下的 min 角矩形 从未执行。DirectVulkan.{Split,Spawn}.MsFlip1. 带 MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE=1, 只在 split + spawn(§2.7 的理由),列入 MAGMA_SERVER_ENV_KNOB_NO_TCP;spawn_lane_parity.py 现在要求每个 tail 恰好命中一条 split 键,死 tail 或过宽 tail 都让门失败。

red-once(均已执行并还原,split + spawn,外加 tcp 的 MsFlip.):

  1. 关掉预检 → 五条 MsFlip./MsFlip1. 全红:the declined COLOR|DEPTH scale must not have written its colour either(读到 {255,0,0,255},要 {0,0,255,255});
  2. 放回 round 1 的「一侧为空就静默返回」→ 五条全红在空目的地腿上(错误 0,要 1282);
  3. 给 shader 臂传 sx0/sy0 而不是 min 角 → 只有 MsFlip1. 两臂红(768 of 768 depth values differ from 0.75;928 of 3072 stencil values are wrong; first at (20, 4): got 255, want 99), MsFlip. 保持绿——证明这条孪生条目确实走到了 shader 臂的矩形;
  4. 往 tail 表里加一个死的 .MsFlip2. → parity RC 1,matches 0 split entrie(s)。

两个拆开的 once 站点没有车道级 red-once:跨格式 Y decline 需要 renderbuffer 与 texture 的 D24S8 映射到不同 VkFormat 的设备(§2.6),lavapipe 不是。


3. 片 3:两处 MagmaP7AllocatorDebtScope

3.1 债是真的,但它早就没有对象了

隐藏的 blit 程序、它的两个采样器和隐藏的深度 mip 程序都是前端对象。在活动传输下,server 后端在 apply 线程上创建它们、也在 apply 线程上销毁它们,而它们的析构函数会跑 client 死亡助手和那个 lifetime-id 探针——所以 P5c 给这两处 teardown 一个具名豁免,P5e 裁定 12 把它按债重命名。

退役它的不是一个新豁免,而是对象不存在。 P5f fv 早已给 InitializeBlitResources 和 InitializeDepthMipmapResources 加了非 monolith 传输的 early return,所以在 monolith 臂之外 m_blitResources 从不持有任何东西,= {} 什么也不销毁。这两个 scope 自那天起就是罩在一条跑不到的 路径上的标记。

3.2 证明,不是论证

两处 teardown 里放一个临时探针:在非 monolith 传输下任一资源非空就按名结束会话。武装着跑: integration-magma-split 93、-spawn 72、-tcp 74、integration-magma-full-split 524、 -full-spawn 524、integration-split 187、integration-magma-buffers 21,全绿,它一次都没响。

负对照才让这成为测量:把探针的传输判据去掉,每一条 monolith DirectVulkan. 条目都在 teardown 时死了(8/8 abort,而且用例本身先 PASS 了),split 条目照样绿。

integration-magma-full-tcp 在探针下的那一条红是 CONTRACT-P7 §2.5 记过名的 StreamLink × Magma 曝光 texel(IterationRPProgram203Scenario),不是探针的死亡——它 Failed,不是 aborted。

3.3 对着 P5e 裁定 12 的「四笔债」重数

裁定 12 点了四处 Magma 站点(VulkanRenderer.cpp ×3、ResourceTracker.h ×1)。其中两处在 P7 开始前就没了——git log -S 把 ResourceTracker.h 那处记在 P5f fv(4f3d2d6b)、第三处 VulkanRenderer.cpp 记在 P5f fm(036c3a3d)——所以 P7 基线 78b7d6be 上只剩两处,就是本片 删掉的这两处。Magma 的 apply 线程分配器债现在是零处。

3.4 类型留下,并且写明了为什么

MG_Test/Wire/RemoteClientTest 的 RemoteGuards.BarrieredLegacyScopesCannotExemptAllocator 与 .BarrieredFrontendRegistryMembersRefuseBothLegacyScopes 拿它当负对照:在 apply 线程上构造它, 然后断言分配器照样拒绝。那是 P5f (fr) 立下的性质,删掉类就删掉了唯一钉住它的用例。 后端已无任何使用点。


4. 片 4:(B′),棘轮的 p7-magma 桶

4.1 做了什么

在 disaggregated 构建里,monolith 臂也改走烘焙模块:

  • InitializeBlitResources / InitializeDepthMipmapResources → return true(无事可做);
  • TryBlitToDefaultFramebufferWithShader → 把两个 BlitImageBinding 转成 WireImage 后调 BlitWireColorToDefault(WireColorBlit.inc);
  • GenerateDepthMipmapWithShader → 逐级调 GenerateWireDepthMipLevel(WireDepthMipmap.inc), 收尾一次 TransitionWireImage 把图像交回调用方承诺的 finalLayout;
  • GetOrCreateBlitPipeline、三段 GLSL 文本、八个 kHidden* id、BlitResources / DepthMipmapResources 的前端成员:#if !MOBILEGL_BUILD_DISAGGREGATED。

为什么是 #if 而不是运行时分支,这正是 §4.2 的全部内容:P5f fv 的 early return 让符号仍然被 引用,棘轮不管那条分支跑不跑。把构造编译掉才让它们掉下来。而成员也得走,不只是构造: SharedPtr 成员的析构本身就是一次对 ~ProgramObject 的引用。

#else 分支逐语句原样,G1 钉住的就是它。

4.2 桶表:前 / 后

bucket before after a6 含义
p6-core 11 11 6 没有后端对象引用:传输/applier 自己的账
p7-magma 101 88 101 只被 DirectVulkan 引用:P7 的账
p3b-p4b-espryt 13 18 14 只被 DirectGLES 引用
both-backends 61 56 60 两个后端都引用
合计 186 173 184

p3b-p4b-espryt 的 +5 不是变坏:那 5 个符号从 both-backends 移了过去,因为 DirectVulkan 不再 引用它们,只剩 DirectGLES。掉的是 13 个,合计 186 → 173。

掉下来的 13 个(--assert-monotone 逐条列名,随本片 --write-baseline 重基线,7 条 # P13 注解原样带过):

  • ProgramObject::{AllocateLifetimeId, AttachShader(...), Link(bool), ~ProgramObject}(4)
  • SamplerObject::{SetLodRange, SetWrapR, SetWrapS, SetWrapT}(4)
  • ShaderObject::{Compile, DropCompileNode, JoinPendingCompile, ReleaseCompileNode, SetShaderSource}(5)

即 §4.2 点名的那三个前端类的全部构造面。

4.3 剩下的 88 个:逐个引用对象点名,以及为什么它们不是 (B′) 的

§4.2 写的「降到 0」按实测不成立,而且差距不在 (B′) 做没做完,在于桶里绝大多数符号根本不是 隐藏程序引来的。逐引用对象:

引用对象 数量 是什么,为什么还在
Renderer/UniformManager.cpp.o 62 monolith 描述符绑定器对应用自己的 GL 纹理对象的遍历:TextureObjectBase 35、TextureObjectWithOneMipmap 20(含其 vtable / typeinfo)、四个 TextureObject{1D,2D,2DCube,3D} 各 1、MGPipeNoteAggregate 1。split 下 SetupDraw 分支到 SetupWireDraw,这条路一行都不跑——但那是运行时分支(ID-P7-5 明确把它留在优化阶段),所以符号仍被引用。清它要对 UniformManager 的 monolith 臂做和 (B′) 同形的 #if,是 wave 3 的活,不是本片的
Renderer/VkSamplerManager.cpp.o 9 SamplerObject::Get{BorderColor,BorderColorI,BorderColorUI,CompareMode,MinLod,SamplerCompareFunc,WrapR,WrapS,WrapT}——同上,monolith 采样器缓存读应用的 SamplerObject
UniformManager.cpp.o + VkSamplerManager.cpp.o 5 SamplerObject::Get{MagFilter,MaxAnisotropy,MaxLod,MinFilter,MipmapMode},同一条路的两个读者
Renderer/VulkanRenderer.cpp.o 3 GLImpl::CopyTextureImageToClientOrPBO_State(monolith 回读打包)、PipeInputs::HasOpenTransformFeedbackSpan、FramebufferAttachmentObject::IsValid
Renderer/VkTextureManager.cpp.o 3 PipeInputs::GetTextureObject、MGPipeTextureLegacyArmScope::{ctor,dtor}——legacy 臂的具名 scope,P3b/P4b 的
BackendObject_DirectVulkan.cpp.o 1 PipeInputs::InvalidateCompileEnv
UniformManager.cpp.o + VulkanRenderer.cpp.o 1 BufferObject::EnsureGpuResidentStorage
VkClearManager + VkRenderPassManager + VulkanRenderer 1 FramebufferAttachmentObject::GetSize
VkRenderPassManager + VulkanRenderer 1 FramebufferAttachmentObject::IsComplete
Renderer/VkRenderPassManager.cpp.o 1 RenderbufferObject::IsAllocated
DirectVulkan.cpp.o + VulkanRenderer.cpp.o 1 VertexArrayObject::GetIndexBufferBindingSlot

没有一个标 # P13,而这是有意的:§4.2 的 # P13 是给「不动 pull .text 就消不掉」的符号准备 的,上面没有一个证明了这一点——UniformManager / VkSamplerManager 的 monolith 臂是pull 构建 自己的代码,对它们做 #if MOBILEGL_BUILD_DISAGGREGATED 与本片对 VulkanRenderer.cpp 做的是同一件 事,pull 构建逐字节不动。它们是 wave 3 的工作量,不是 P13 的边界问题。把它们提前标成 P13 会把一 件没人试过的事记成一件试过做不到的事。

4.4 门

integration-gpu 1705(monolith DirectVulkan. 条目都在里面)、integration-magma-split 93、-spawn 72、-tcp 74、integration-magma-full-split 524、 ctest -L unit 2423,全绿。

link_ratchet --assert-monotone 对重基线后的文件:173 不变,RC 0。

retrace(本片的关键读数,因为 monolith 臂在 disaggregated 构建里换了实现):

case ssim mismatchPixels
OpenRA.DirectVulkan(monolith) 1.000000 0
OpenRA.DirectVulkan.SPLIT 1.000000 0

整条 DirectVulkan 矩阵:monolith 39/40 绿、SPLIT 38/39 绿,两边红的是同一条 minecraft-1.21.4-fabric-iris-iterationrp-in-world(ssim 0.027915)。已核实是既有的:在包 B 的 树(~/w7/p7-magma-b/build-retrace,本分支的父提交)上同一条用例同样红。它要 CONTRACT-P7 §2.4 说的 三个 iterationRP 旋钮,而那三个是 CI 作业导出的、不是 ctest 条目自带的。

G1 pull .text 0xa52203、nm --defined-only 与 ~/w7/p7-before/pull-syms.txt 逐行相同 (30570 行,0 差异)——本片改的每一行要么在 #if MOBILEGL_BUILD_DISAGGREGATED 里,要么在 #if !MOBILEGL_BUILD_DISAGGREGATED 里而那一侧逐语句未动。

4.5 欠设备核对

monolith 臂在 Android 的 disaggregated 包里现在跑的是烘焙 blit。旋转(ROTATE_90/180/270)的 几何只有真机能看:BlitWireColorImage 的 quarterTurn 归一化与它替换掉的 TryBlitToDefaultFramebufferWithShader 的 dstNormWidth/dstNormHeight 是同一个算式,但本机每一个 表面都是 IDENTITY,这条等式没有被执行过。


5. 要手机的清单(本包全部的设备债)

  1. 片 1:旋转表面上的缩放多重采样 blit(本机只有 identity)。
  2. 片 2:没有 VK_KHR_depth_stencil_resolve 的设备上的 shader 深/模板 resolve——本机只能经 MGITEST_MAGMA_FORCE_SHADER_DEPTH_RESOLVE 到达。Adreno 830 是否带这两个扩展本身也要看一眼: 带,则这条臂在真机上同样只有旋钮可达;不带,则它是真机的默认臂。另看 renderbuffer 与 texture 的 D24S8 是否映射到同一个 VkFormat:不同则 MsFlip. 在跨格式 Y decline 上红(§2.6)。
  3. 片 4:ROTATE_90/180/270 下 monolith 臂的烘焙 blit 几何(§4.5)。
  4. 包 B 遗留、本包未碰:非恒等旋转下的 default-color-blit-shape scratch 臂,以及 OpenRA 三次 pm clear 冷跑的 1.0 验收。

6. 记录债(写给 CONTRACT-P7 §12 的几行)

  1. 缩放后的第二段没有裁剪(WireFramebuffer.inc:932-946,round 2 之后本树行号)。多重采样颜色 resolve 的第二段 vkCmdBlitImage 把目的矩形原样交给驱动;一个越出目的图像的矩形是 VUID-vkCmdBlitImage-dstOffset-00248/00249,不是一张被裁过的图。这条与 monolith 臂共有 (VulkanRenderer.cpp:10066 的 vkCmdBlitImage 同样不裁;:10060 是它前面的 vkCmdResolveImage,行号是 pipe 上的),所以它不是分离缺陷,也不该由本包单独改; 两条臂一起裁是一件独立的活。 部分生效(审查 round 2,已关):同一个缩放,mask 若是 COLOR|DEPTH,round 1 先由这条臂把颜色 缩放写进目的地,再由深度臂记 INVALID_OPERATION——出错的调用留下了一半效果,18.3.1 不允许。 现在缩放形状在任何 aspect 之前由 DeclineWireDepthStencilResolveShape 决定,整个调用报错、 什么也不写(§2.9 第 3 条,red-once 已做)。剩下的债只是上面的「不裁」。
  2. MagmaWireFatal("multisample-resolve-region")(WireFramebuffer.inc:878)仍然对 源矩形越出读缓冲的 blit 带走会话。GL 对这种形状的承诺是「那些像素的值未定义」,不是一个 错误——所以正确的收口是 decline 或钳制,不是 Fatal。本包没有改它,因为它不带 @P7、也不是 §3.2 点名的行;记在这里。
  3. 1 → N 的等矩形 decline(WireFramebuffer.inc:1095-1125)拒绝的是一个合法形状: 18.3.1 说单采样源写进多重采样目的地是样本复制。本包 decline 它,是因为 Vulkan 没有命令能 表达它,而 monolith 臂对同一形状的「可观测」是一次 VU 违规(vkCmdBlitImage 的两侧都必须是 单采样)——即没有一个正确的对照读数可抄。要真的实现它需要一条以目的地采样数建管线的 draw, 也就是 resolve 机器反过来再写一遍。
  4. tcp 车道带不了 server 端测试旋钮(§2.7)。六条 knob 条目(round 2 加了 MsFlip1.)因此只注册在 split + spawn,并在 spawn_lane_parity.py 里具名。要收回这条,tcp_server_fixture.py 得接受每用例的 server 环境——一个 supervisor 控制项。
  5. X 镜像与跨格式 Y 镜像的深/模板 resolve(§2.8)decline。前者要逐 texel 的 region,后者要 BlitDepthAcrossFormats(与 monolith 共用)长出翻转。两者都不是一个片的体量。这两条 decline 拒绝的是合法的 blit,所以它们的 INVALID_OPERATION 是规则 I (a) 的具名拒绝,不是 GL 的答案。 部分生效(审查 round 2,已关):round 1 在颜色 aspect 已经镜像写完之后才 decline 深度——颜色 镜像了、深度没动、再报一个 GL 不会报的错。现在 decline 在任何 aspect 之前决定,整个调用什么也 不写(§2.9 第 3 条)。两种 decline 各有自己的 once 站点。跨格式那条在 renderbuffer 与 texture 的 D24S8 映射到不同 VkFormat 的设备上会让 MsFlip. 变红(§2.6)。
  6. monolith DirectVulkan 臂的翻转 / 缩放多重采样深度 blit(VulkanRenderer.cpp:9594、:9608, pipe 行号):翻转被拒(「depth blits with flipped rectangles are not supported yet」,目的地保持 清屏值、无错误),缩放被执行(GL 说是 INVALID_OPERATION)。这是一处 wire 与 monolith 的 分歧,且 wire 臂是更正确的一方;AFlippedMultisampleResolve… 在 monolith 条目上以具名理由 Skipped。monolith 的修正归 P13 / G1(G1 期间 pull 构建的 .text 不许动)。
  7. Espryt(DirectGLES,monolith 与 split 一样)的翻转 / 缩放多重采样深度 resolve:翻转什么也不写 且不报错,缩放不报 INVALID_OPERATION。同一用例在 DirectGLES 条目上以具名理由 Skipped。 这是 P3b / P4b 的债。

7. 审查 round 的门(两行:本树与落地树)

round 1 的这一节把每个读数都记在「5d896170」上,而 5d896170 不是落地树的祖先(三条提交是被 cherry-pick 到 pipe 上的)。所以这里分两行,各自点名量的是哪棵树:

  • 本树(合并前):p7/magma-b2@4442ea6d,即 round 2 的三条代码提交之顶;本节所在的文档提交只动 这份笔记。
  • 落地树:pipe@3b66d1b1,由 integrator 实测,= round 1 的三条提交 + 一条临时的「按后端名跳过」 提交(那条已从 pipe 撤下,由本 round 的 lane-marker 跳过取代)。integrator 在本 round 合入后重量, 并更新这里的 SHA。

两棵树的 integration-{split,spawn,tcp} 与 unit 读数不可互比:pipe 上多了本分支没有的注册 (例如 DirectGLES.{Split,Spawn,Tcp}.ForcedDs.*)。

门 本树 p7/magma-b2@4442ea6d 落地树 pipe@3b66d1b1
ctest -L unit 2423,全绿 2429
integration-split 187,全绿 304
integration-spawn 103,全绿 220
integration-tcp 106,全绿 223
integration-magma-split 95(94 + MsFlip1.),全绿 96
integration-magma-spawn 74(73 + MsFlip1.),全绿 75
integration-magma-tcp 70(MsFlip1. 不上 tcp),全绿 72
integration-magma-full-split 525,全绿 535
monolith DirectVulkan.…AFlipped… / DirectGLES.…AFlipped… 均 Skipped,具名理由(§2.9 第 1 条) —(临时跳过只按后端名)
spawn_lane_parity.py build-split RC 0;gated 档点名 6 条 MAGMA_SERVER_ENV_KNOB_NO_TCP 条目,每个 tail 恰好命中一条 RC 0(parity 0)
fatal_census 79 / 44 / 0,RC 0 79,RC 0
link_ratchet --assert-monotone 173 不变,RC 0 173
G1 pull 构建 RC 0,.text 0xa52203,nm --defined-only 与 ~/w7/p7-before/pull-syms.txt 0 增 0 减 RC 0,.text 0xa52203,0 / 0
@P7 19 行,全是注释 19

scripts/data/link_ratchet_baseline.txt 的 base commit 头注释指 6af422b3——173 是在那棵树上量出来的, 不是在 4bee1313 上;本 round 没有动它。