掉帧问题——Native传输

  • Creator 版本:3.8.3

  • 目标平台:Android

  • 重现方式:必现

  • 问题原因:使用Cocos与Android传输数据,但是数据量巨大,通过官方的方法(使用 JsbBridge 实现 JavaScript 与 Java 通信 | Cocos Creator
    需要将图片类型uint8Arrary类型转码为字符串类型,再以字符串类型进行传输,导致数据过大,每一帧都传输,传输数据40w,转码与传输的过程,导致帧率特别低,最多FPS只有10。
    目的是传输Cocos渲染出来的图片,有什么办法能够优化这个方法?或者使用其他方法将Cocos渲染的图片传输到Android层也可以?
    跪求大佬解惑。

1赞

那就换个方式吧 原生里保存图片到某个地方 COCOS再去读取

正确方式,是共享buffer

安卓的bitmap可以开启映射,这样可以直接在c++操作(前后加锁)

在c++和v8里面,创建一个ArrayBuffer并传入内存地址,这样可以实现js和java共享操作一段内存

是的,但是typescript好像没有共享内存这种东西吧。没有办法传指针什么的啊?大佬

但是这样感觉很慢,Cocos渲染每一帧,IO保存,然后Android再去调用,很麻烦

@haroel
没太理解啊,大佬。
这里面没有涉及到C++啊。目的是想Coco的渲染的场景图片 传给 编译完成的Android项目。

官方文档就有介绍怎么用,你搜下官网

是的,正确打开方式

好的,大佬。
我有个疑问哈,大佬,就是我现在是用Cocos编译成Android平台运行使用的,如果使用C++的话,是不是再添加个JNI层啊?就是Android与C++交互层?刚刚看了官方的共享内存,是原生平台C++与JS之间交互,说实话我现在有点懵 :sob:

js跟java交互必须过c++,引擎封装了很多东西让你觉得两个语言传数据怎么这么简单,但是引擎只能处理简单数据类型,而且还是拷贝传值。

就我了解到的跨语言高效传输只有让语言层面都共享内存这条方案
这部分门槛比较高,建议找找资料或者问AI

大致方案
Bitmap、AndroidBitmap_lockPixels、AndroidBitmap_unlockPixels

Android层通过上述JNI(AndroidBitmap_lockPixels)方式,可以拿到java层一个Bitmap对象内部真正持有的内存地址,接着可以C++用v8接口创建一段ArrayBuffer,把内存地址传给v8::ArrayBuffer

static void __buffer_delete(void* data, size_t length, void* deleter_data) {
    uint8_t* buffer = (uint8_t*)data;
// TODO Nothing
}

    uint32_t filesize = 
    uint8_t* buffer = bitmap_ptr;
    // 创建一个 BackingStore 对象
    auto allocator = v8::ArrayBuffer::NewBackingStore(buffer, filesize,
                                                      __buffer_delete, nullptr);
    auto arrayBuffer = v8::ArrayBuffer::New(isolate, std::move(allocator));

arrayBuffer直接挂在一个全局变量下面(推荐)或者call给js,这样就共享了

另外同步数据时需要注意锁和解锁,避免奇怪GC问题,毕竟同时叠加java的gc跟js的gc,出错查起来很麻烦。

1赞

好的,大佬,非常感谢解惑 :kissing_heart:

大佬,我今天试了试,这一步还是不太清楚。
C++写的这个arrayBuffer,怎么能够让js调用到啊?
我是把这个代码写在了native\engine\common\Classes中的game.cpp文件中的。并且挂载了全局变量中,
如下:

unsigned char mBuffer[mLength];
se::Object *object;
v8::Local<v8::Object> jsobj;
  int Game::init() {
  mMemoryShared.initialize(mBuffer, mLength);
  object = mMemoryShared.getSharedArrayBufferObject();
  jsobj = object->_getJSObject();
  }

已经解决了大佬,感谢感谢 :star_struck:

楼主,实操可以分享一下吗

可以的,等我整理整理,然后发出来哈

3x的渲染数据不是本来就在c++层吗?为什么要通过ts中转,直接c++和java交互,慢是java和c++语言中间的交互通道慢吗

他现在是共享不是中转

“ 3x的渲染数据不是本来就在c++层吗?”

你是说Cocos渲染的纹理数据可以直接通过C++层获取到吗?大佬,这一点我不太懂的。
因为我的需求是从Cocos渲染的场景,利用RTT将渲染的场景绘制到一张纹理中,然后再将这个纹理传回Java端,如果能够直接从C++层获取到Cocos绘制的这张纹理那就更好了。
慢的原因是:纹理uint8Arrary转string类型,然后Cocos提供的jsb只能传输string类型,导致每一帧都传输40w这么大量的字符串,帧率特别低。

这是在做录屏吗,要不换个思路,直接在Java层读SurfaceView的数据呢。