3.8.8 BUG RenderTexture在安卓端报错 'blendState'

我用的3.8.7版本,参考此pr让ai写了个构建脚本,修改构建后的cc.js,至少不会报错了,但是似乎治标不治本?rtMat不存在,或者rtMat.passes.length为0是正常情况吗?

protected _updateBuiltinMaterial (): Material {

    let mat = super._updateBuiltinMaterial();

    if (this.spriteFrame && this.spriteFrame.texture instanceof RenderTexture) {

        const rtMatName = `rt-${mat.name}`;

        let rtMat = builtinResMgr.get(rtMatName) as Material | null;

        if (!rtMat || !rtMat.passes.length) {

            rtMat = new Material(rtMatName);

            rtMat.copy(mat, { defines: { SAMPLE_FROM_RT: true } });

            builtinResMgr.addAsset(rtMatName, rtMat);

        }

        mat = rtMat;

    }

    return mat;

}

有重新赋值的。

这边发现回滚这次提交就正常了

用GLM5.2给出的分析:

根本原因分析

该 Bug 出在 Cocos 的 JSB(原生)实现中,具体是关于缓存的 rt- 材质及其 _passes JS 缓存的工作方式:

  1. _updateBuiltinMaterialsprite.ts:565 通过 builtinResMgr.addAsset() 缓存了一个名为 rt-ui-sprite-material 的材质。该材质具有 SAMPLE_FROM_RT: true
  2. 在原生平台上 ( material.jsb.ts:283 ), passes 属性是一个 缓存的 JS 数组 ,仅通过 _onPassesUpdated 回调进行更新。该回调由原生的 emit<PassesUpdated>() 触发,它只在 Material::update() (创建 passes)和 Material::doDestroy() (清除 passes)中触发。
  3. 在 Web 平台上 ( material.ts ), _passes 是一个普通的数组,总是从 _effectAsset 中重新派生,因此不存在缓存陈旧的问题。
  4. 关键问题 :当第一个截图精灵被销毁时,rt- 材质的 JS 包装器可能会失去其唯一的 JS 引用( _materials[0] 被置空)。原生对象通过 builtinResMgr 的原生 IntrusivePtr 存活,但 _passes 的 JS 缓存可能变陈旧或失效。在第二次调用时, builtinResMgr.get() 回落到原生的 getAsset() (因为它只通过原生的 addAsset 添加,而不是 JS 的 _resources ),返回一个可能带有陈旧/空 _passes 缓存的包装器。当 _updateBlendFunc ( ui-renderer.ts:603 ) 访问 passes[0] 时,数组为空 → 导致崩溃。

感谢反馈,这边会再跟进。

请参考这个PR的修改