Files
2026-09-10 17:29:24 +08:00

4.1 KiB
Raw Permalink Blame History

UIEffect 降 DC 改动总结

提交:fa5f0cdb 降低DC的操作(2026-08-26) 涉及目录:unity/my_libs/unityLib/UIEffect-main/Packages/src/Runtime/

一、背景与目标

UI_Effect 插件原本每个 UIEffect 组件都会生成独立的材质实例(缓存 key 使用 effectId,即组件的 GetInstanceID(),每个实例唯一),导致:

  • 相同配置的特效无法共享材质 → 无法参与动态合批 → Draw Call 偏高;
  • 批量刷 UI 时材质创建开销大,伴随帧率波动。

目标:让相同配置的 UIEffect 共享同一材质,从而参与合批,降低 DC。

二、方案选型

方案 说明 结论
UIEffectReplica + Preset 业务代码逐个改为副本组件,指向共享 preset 需要改动大量业务文件、创建 preset 资产,侵入性大
configId 配置指纹(最终采用) 在插件内部按"配置内容哈希"共享材质 业务代码零改动,同配置自动共享合批

三、具体改动

1. UIEffectContext.cs(新增约 121 行)

核心:新增 configId 属性——特效配置的"稳定指纹"。

  • 反射字段缓存:s_ConfigFields 为 static readonly FieldInfo[],GetFields 只在类型加载时执行一次,运行时无反射类型发现开销,避免批量刷新时的 GC 尖峰(这是此前"帧率不稳"问题的根因与修复点)。
  • 内容哈希 HashValue:
    • null → 0;
    • UnityEngine.Object → GetInstanceID()(引用同一资产即同哈希);
    • Gradient → GradientHash 按 colorKeys / alphaKeys 逐 key 做内容哈希(不同实例但内容相同的渐变得到相同指纹);
    • 基元/枚举 → GetHashCode();嵌套值类型(Color、Vector、MinMax01 等)→ HashFields 逐字段展开(s_FieldCache 按类型缓存)。
  • 雪崩混淆:FNV-1a 混合后追加 MurmurHash3 终混,让相近配置散列开,降低哈希碰撞概率。

2. UIEffectBase.cs(GetModifiedMaterial)

材质缓存 key 由 effectId 改为配置指纹:

var configId = context.configId;
var rootId = context.useViewMatrix && transitionRoot ? (uint)transitionRoot.GetInstanceID() : 0u;
var hash = new Hash128((uint)baseMaterial.GetInstanceID(), configId, samplingScaleId, rootId);

要点:

  • rootId 仅在特效需要视图矩阵时(transition / gradation / detail / shiny)才参与哈希,普通灰度(ToneFilter)等不受 root 影响,可共享范围更大;
  • Hash128(baseMaterial, configId, samplingScaleId, rootId) 相同 → 命中 MaterialRepository 中同一材质实例 → 参与动态合批。

3. ShaderVariantRegistry.cs(Profiler 采样修复)

RegisterVariant / GetVariant 的所有提前 return 分支均补上 Profiler.EndSample(),保证 BeginSample/EndSample 严格配对,修复控制台的:

Non-matching Profiler.EndSample (Every EndSample call must have a preceding BeginSample call...)

四、业务侧影响

  • 业务文件零改动:EquipBuffItem、MapBlockItem、PetItem、V_RechargeItem、FightLinkHeroItem、AvatarItem 等继续正常使用 UIEffect 控制灰度,无需迁移到 UIEffectReplica。
  • 同屏所有同配置灰度特效(如大量 ToneFilter.Grayscale 的图标)自动共享一个材质并合批。

五、效果

  • N 个相同配置的 UIEffect:N 个材质实例 → 1 个共享材质,可被 UGUI 动态合批;
  • DC 显著下降(受益程度取决于面板内同配置特效数量)。

六、注意事项与局限

  1. 配置不同的特效无法互相合批——每种不同配置组合仍各占一个材质/DC,属预期行为;
  2. configId 在画布重建时计算,字段遍历存在少量装箱开销,已通过静态缓存降到最低(普通 UI 不会每帧触发);
  3. 新增 UIEffectContext 公共字段会自动纳入指纹(遍历 public instance 字段),无需手动维护字段清单;
  4. 验证方式:打开 Frame Debugger / Profiler,确认同配置 UI 元素合并为同一批次;确认控制台不再出现 Non-matching Profiler.EndSample。