1709 字
9 分钟

LWE Scene 纹理共享与失败回滚

10 月 13 日,LWE 把实验性 Scene 播放接进了桌面应用流程。画面能够出现以后,紧接着要处理的是另一组问题:切换时旧画面还在,候选画面也要占资源;保存可能失败;同一张图片可能被几个渲染器同时引用。它们决定了用户点下“应用”以后,失败能不能收场。

先分清哪些资源可以共享#

同一个 Scene 同时出现在多个输出,或者正处于当前、候选、回滚几代并存的阶段,都会用到相同的图片。分别上传容易理解,却会反复占用 GPU 资源。

共享范围先限定在同一个存活的 EGL 上下文内。只读图片可以共享,特效目标、历史缓冲、脚本状态和已经接纳的输出仍由各代自己持有。这样切换候选时,就不会顺手改掉旧画面需要的状态。

“同一张图”也不能只看路径。原路径可能换过内容,图片相同也可能使用不同的采样方式。资源准备阶段会把来源、实际读取和解码的内容、元数据与解码契约纳入身份;repeat 和 clamp 则使用不同的上传对象。绘制时不用来回修改共享纹理的采样状态。相关约束写在纹理所有权与预算记录里。

预算要覆盖切换的峰值#

只看新场景最终占多少内存,会漏掉切换过程中最拥挤的一刻。旧代还要负责回滚,候选已经开始准备,输出也可能等待初始化;调整尺寸时,旧布局必须留到替换布局分配成功。

这次保留了 512 MiB 的逻辑 GPU 预算。预检把各代引用的不可变上传做并集,同一份只读资源只计一次;每代的私有目标分别计入,尚未完成删除的资源继续占账。算术溢出、同一身份对应不同尺寸,或者完整计划超出上限,都会在候选分配前被拒绝。当前画面不会为了腾地方先被驱逐。

CPU 侧另有 512 MiB 保留分配上限,按实际 Vec 容量计费。共享 GPU 上传并不意味着两次独立解码产生的 CPU 存储也能合并。这里的数字只描述受管理的容量与预留,不能拿去当进程 RSS,也不能叫作显卡的实测 VRAM。

诊断也得沿用相同口径。每个输出都可能报告自己引用的共享图片,把这些数直接相加会重复计算。引擎级账本才负责区分存活上传、私有预留和等待删除的资源;当前计划的上界又只是快照,不能冒充历史峰值。共享以后,数字看起来更小之前,先要确认到底在数什么。

最后一个引用消失,还不能立刻删纹理#

CPU 引用计数归零时,未必正处于可以操作该纹理的 GL 上下文。直接在释放路径删除对象,容易把资源生命周期与当前线程、当前上下文绑错。

因此,最后一个 lease 释放时只把对象放入退役队列。所属上下文成为 current 后,再处理真正的删除;删除成功才撤掉计费。上下文本身也有生命周期标记,即使驱动后来复用了相同的 native handle,旧所有者也不会重新变成有效。无法确认的删除失败会隔离共享域,避免继续尝试一个含义已经不明确的数字 ID。这部分实现随共享纹理改动合入。

把应用壁纸当成一笔事务#

资源准备完成,只说明 CPU 侧输入已经通过检查。候选还得成功画出首帧,并在期限内被确认,才能进入提交阶段。此时旧代仍然保留,候选也仍可撤销。

随后才原子保存分配与用户选项。保存成功后 finalize,释放旧代的回滚资源;保存失败则撤销候选,恢复之前的分配与渲染器。这样磁盘上的配置和眼前的画面才能一起前进。协议的入口可以在实验性 Scene 播放改动中看到。

历史缓冲让回滚又多了一层难度。旧画面暂停以后,不能随便再跑一次脚本或累积一帧历史。后续实现冻结旧代时,会把私有历史读回受同一 CPU 预算管理的快照;全部读回成功才释放原 GPU 历史,恢复时也等上传全部成功后才放掉快照。

这个边界要说清楚:恢复的是此前接纳的画面和所需资源,并不声称能把任意 JavaScript 堆倒退。活动绘制或 swap 在私有状态推进后失败,该代会被隔离,后续不能再推进动画或调整尺寸。候选失败则由独立冻结的旧代接回来。图片、动画帧与历史缓冲记录保留了这些契约。

大图集不必先解成整张 RGBA#

动画资源还暴露了另一种峰值:一帧只需要图集中的矩形,整图解码却会先付完整图的代价。区域解码器先检查整个帧表、尺寸和压缩长度,再把相交的 BC3 块直接写进目标区域,保留作者原来的帧时长。

这里没有再开一套不受约束的内存池。编码数据、必要的解压块、元数据和输出区域都带分配租约,集成到引擎时继续合并计费。单独解出一帧也不能证明当前、候选、回滚同时存在时一定放得下。具体输入限制见时间图集资源记录。

验证分别回答了什么#

共享纹理改动的普通回归和软件 EGL 离屏检查,覆盖了身份、预算、共享对象、采样隔离、像素与失败清理,对应 Quality Check已通过。可见呈现和真实保存失败回滚的原生记录,来自前后的播放接入与完整场景流程,不是共享纹理改动新增的多输出验收。本文依据这些历史记录整理,没有重新运行上述实验。

这组结果主要确认同一 EGL 上下文内的资源共享、预算拒绝和失败清理。多输出共享的离屏结果仍需在实际多输出会话中确认,逻辑预算也不能代表驱动实际内存占用。

LWE Scene 纹理共享与失败回滚
https://blog.yangyus8.top/posts/lwe-scene-texture-budget-rollback/
作者
杨与S8
发布于
2026-10-13
许可协议
CC BY-NC-SA 4.0

评论