解决了吗,我也遇到了
解决了么 我也遇到了
我也遇到一样的问题,有人解决吗
我这边也遇到了,其实就是创建了一个spriteFrame,并把对应的RenderTexture赋值给摄像机的targetTexture,跟帖子一样,首次进入是没问题的,第二次再次创建调用的时候,渲染出现材质损坏的问题,只有在原生端出现,有什么解决方案吗??
并且在3.8.2是没问题的,升级3.8.7才有的问题
能否提供可复现的demo ?
我用极简代码也复现了
这个PR会导致崩溃,以下是崩溃关键日志
05-29 15:46:05.629 4971 5007 E Cocos : 15:46:05 [ERROR]: [SE_ERROR] (C:/ProgramData/cocos/editors/Creator/3.8.8/resources/resources/3d/engine/native/cocos/bindings/jswrapper/v8/ScriptEngine.cpp, 1020): _onPassesUpdated is not a function: undefined
你好,可以提供下复现demo?
import { _decorator, Component, Node, Button, view, RenderTexture, Camera, director, Director, Sprite, SpriteFrame } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('test')
export class test extends Component {
btnCaputre!: Button
btnClose!: Button
start() {
this.btnCaputre = this.node.getChildByName("capture").getComponent(Button)
this.btnClose = this.node.getChildByName("close").getComponent(Button)
this.btnCaputre.node.on(Button.EventType.CLICK, () => {
this.capture();
})
this.btnClose.node.on(Button.EventType.CLICK, () => {
this.close();
})
}
async capture() {
const node = new Node("_capture");
const sprite = node.addComponent(Sprite);
node.setParent(this.node);
const renderTexture = new RenderTexture();
renderTexture.initialize({
width: Math.floor(view.getVisibleSize().width),
height: Math.floor(view.getVisibleSize().height)
});
const spriteFrame = new SpriteFrame();
spriteFrame.packable = false;
spriteFrame.texture = renderTexture;
const cameras = director.getScene().getComponentsInChildren(Camera).filter(camera => camera.node.activeInHierarchy);
for (const cam of cameras) {
cam.targetTexture = renderTexture;
}
await new Promise<void>((r, j) => director.once(Director.EVENT_AFTER_RENDER, r));
for (const cam of cameras) {
cam.targetTexture = null;
}
sprite.spriteFrame = spriteFrame;
}
close() {
const _capture = this.node.getChildByName("_capture")
if(!_capture || !_capture.isValid)
return;
const sprite = _capture.getComponent(Sprite)
if(!sprite || !sprite.isValid)
return;
const spriteFrame = sprite.spriteFrame;
sprite.spriteFrame = null;
const renderTexture = spriteFrame.texture;
spriteFrame.destroy();
renderTexture.destroy();
_capture.removeFromParent();
_capture.destroy();
}
}
弄两个按钮,然后来回点击,大概率复现。
这边实测,点击一次截图,再点击销毁,挂个1分钟,再点击截图就崩溃
你好,有下文吗?
是用388原始代码? android用什么机型?
我这边用388原始代码,在windows, android 都没复现。
是原始代码,打包到mumu模拟器12运行的,怀疑是v8那边的对象被GC了
我用的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 缓存的工作方式:
-
_updateBuiltinMaterial在sprite.ts:565通过builtinResMgr.addAsset()缓存了一个名为rt-ui-sprite-material的材质。该材质具有SAMPLE_FROM_RT: true。 -
在原生平台上 (
material.jsb.ts:283),passes属性是一个 缓存的 JS 数组 ,仅通过_onPassesUpdated回调进行更新。该回调由原生的emit<PassesUpdated>()触发,它只在Material::update()(创建 passes)和Material::doDestroy()(清除 passes)中触发。 -
在 Web 平台上 (
material.ts),_passes是一个普通的数组,总是从_effectAsset中重新派生,因此不存在缓存陈旧的问题。 -
关键问题 :当第一个截图精灵被销毁时,rt- 材质的 JS 包装器可能会失去其唯一的 JS 引用(
_materials[0]被置空)。原生对象通过builtinResMgr的原生IntrusivePtr存活,但_passes的 JS 缓存可能变陈旧或失效。在第二次调用时,builtinResMgr.get()回落到原生的getAsset()(因为它只通过原生的addAsset添加,而不是 JS 的_resources),返回一个可能带有陈旧/空_passes缓存的包装器。当_updateBlendFunc(ui-renderer.ts:603) 访问passes[0]时,数组为空 → 导致崩溃。
感谢反馈,这边会再跟进。