javascript - 在 emscripten 中的已知堆地址处创建数组

标签 javascript emscripten unity-webgl

我将几 kB 的数据(生成的 PNG 文件)从 Unity3D WebGL 上下文传递到 javascript,以便用户可以在不离开 WebGL 上下文的情况下下载 PNG 文件。 Unity使用emscripten并将js嵌入为jslib。这是我第一次查看 emscripten 或在 js 中使用指针,在 emscripten 文档中找不到基础知识。

它可以工作,但我认为这是一个糟糕的实现,代码如下:

mergeInto(LibraryManager.library, {
    JSDownload: function(filenamePointer, dataPointer, dataLength) {
        filename = Pointer_stringify(filenamePointer);
        var data = new Uint8Array(dataLength);
        for (var i = 0; i < dataLength; i++) {
            data[i]=HEAPU8[dataPointer+i];
        }
        var blob = new Blob([data], {type: 'application/octet-stream'});
        if(window.navigator.msSaveOrOpenBlob) {
            window.navigator.msSaveBlob(blob, filename);
        }
        else{
            var elem = window.document.createElement('a');
            elem.href = window.URL.createObjectURL(blob);
            elem.download = filename;        
            document.body.appendChild(elem);
            elem.click();        
            document.body.removeChild(elem);
        }
    }
});

令我困扰的是这样的单步执行数据,因为我已经有了地址和长度,所以我想在已知地址实例化“数据”数组,就像我在 C 中使用 * 和 & 一样,而不是复制它是一个字节一个字节地复制,或者如果我必须复制它,至少要一次点击而不是循环复制。我认为我最大的问题是不知道在哪里寻找文档。我通过查看 GitHub 上的随机项目发现了比这里更多的内容:https://emscripten.org/docs/api_reference/preamble.js.html

如有任何帮助,我们将不胜感激,谢谢。

最佳答案

所以你不喜欢这部分?

var data = new Uint8Array(dataLength);
for (var i = 0; i < dataLength; i++) {
    data[i]=HEAPU8[dataPointer+i];
}
var blob = new Blob([data], {type: 'application/octet-stream'});

你可以把它写成一行:

var blob = new Blob([HEAPU8.subarray(dataPointer, dataPointer + dataLength)], {type: 'application/octet-stream'});

// or this

var blob = new Blob([new Uint8Array(HEAPU8.buffer, dataPointer, dataLength)], {type: 'application/octet-stream'});

它们都应该比您的原始代码快得多,并且它们都应该具有完全相同的性能。这是因为他们直接从 HEAPU8 创建一个新的 Blob,而不像原始代码那样创建重复的数组。

HEAPU8 是一个 Uint8Array,TypedArray 系列之一。关于 TypedArray 的一件非常重要的事情是,它实际上不是缓冲区/数据,而是底层 ArrayBuffer(它是 HEAPU8.buffer)对象的一个​​“ View ”,该对象保存实际数据。请参阅ArrayBufferView .

所以HEAPU8HEAPU8.bufferArrayBuffer对象提供了一个接口(interface),具体来说WebAssembly.Memory.buffer在 Emscripten 中,看起来像一个 uint8_t 数组。 Emscripten 还提供了 HEAPU16、HEAPU32、HEAPF32 等,但它们具有相同的 ArrayBuffer 和不同的 View 。

.subarray(start, end)new Uint8Array(buffer, offset, size) 的作用是创建 ArrayBuffer 对象的新“ View ”指定范围内,不复制缓冲区。因此,您的性能损失将降至最低。

关于javascript - 在 emscripten 中的已知堆地址处创建数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60106899/

相关文章:

javascript - 使用 deck.gl 根据 slider 输入更改图层属性

c++ - 让 NetBeans 的 C++ 解析器与 Emscripten 一起工作

c# - 使用资源包在 unity webgl 中加载/卸载巨大的世界

unity3d - 在 Microsoft HoloLens 上查找网格中的固定点

javascript - 如何在不复制的情况下将 canvas imageData 传递给 emscripten c++ 程序?

unity3d - MS Edge 中与 Unity/WebGL 和 asm.js 相关的崩溃

php - 使用 Confirm() 在 Javascript 中执行 PHP 代码

javascript - Jquery 不适用于添加的表行(追加)

javascript - 何时使用 return,返回的数据会怎样?

c++ - emscripten 中的错误绑定(bind)属性和函数