Используя emscripten, как получить массив C ++ uint8_t в JS Blob или UInt8Array - PullRequest
0 голосов
/ 04 декабря 2018

В emscripten C ++ у меня есть

class MyClass {
public:
   MyClass() {}
   std::shared_ptr<std::vector<uint8_t>> buffer;
   int getPtr() {
      return (int)(buffer->data());
   }
   int getLength() {
      return buffer->size();
   }
};
EMSCRIPTEN_BINDINGS() {
    class_<MyClass>("MyClass").constructor()
      .function("getLength",&MyClass::getLength)
      .function("getPtr",&MyClass::getPtr,
                allow_raw_pointers());
}

Я могу вызвать getLength () и getPtr () из JS, но я не знаю, как заставить JS рассматривать его как ArrayBuffer для загрузкикак BLOB-объект.

Как я могу получить данные буфера в JS в форме, где я могу затем загрузить их, используя код, подобный https://github.com/kennethjiang/js-file-download/blob/master/file-download.js.

1 Ответ

0 голосов
/ 04 декабря 2018

В настоящее время WebAssembly определяет только основные типы номеров для связи между JS и WASM.Здесь нет ни типов объектов, ни типов массивов. Это цель разработки WebAssembly. Emscripten сделал несколько хаков для создания привязок JS класса C ++ <=>, но они не соответствуют стандарту WASM.

WebAssembly.Memory ()

НО есть способ получить массив.JS имеет прямой доступ к внутренней памяти модуля WASM, даже без API.WASM имеет линейную модель памяти, а линейная память связана через WebAssembly.Memory().WebAssembly.Memory() - это единственный ArrayBuffer WebAssembly.Memory.buffer, где ваш модуль WASM использует в качестве области динамической памяти и где происходит выделение памяти (например, malloc()).

1.Доступ к нему как UInt8Array

Что это значит?Это означает, что указатель (целое число на стороне JS), получаемый от getPtr(), фактически является смещением WebAssembly.Memory.buffer.

Emscripten автоматически генерирует JS (это генерируется из шаблона с именем preamble.js ) код, который создает WebAssembly.Memory().Вы можете выполнить поиск в сгенерированном Emscripten коде и найти строку, аналогичную этой строке :

Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });

Таким образом, вы можете получить доступ к ArrayBuffer, используемому вашим модулем WASM, через Module['wasmMemory'].buffer:

let instance = new Module.MyClass();

// ... Do something

let ptr = instance.getPtr();
let size = instance.getLength();
// You can use Module['env']['memory'].buffer instead. They are the same.
let my_uint8_buffer = new Uint8Array(Module['wasmMemory'].buffer, ptr, size);

2.Emscripten HEAPU8

В качестве альтернативы Emscripten предлагает официальный способ доступа к области памяти кучи в виде типизированных массивов : HEAPU8, HEAPU16, HEAPU32 и т. Д., Как определено здесь .Таким образом, вы можете сделать это следующим образом:

let instance = new Module.MyClass();

// ... Do something

let ptr = instance.getPtr();
let size = instance.getLength();
let my_uint8_buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, size);

Использование HEAPU8 будет безопаснее, поскольку HEAPU8 задокументировано, тогда как имя атрибута Module['wasmMemory'] довольно недокументировано и может быть изменено;но они делают то же самое.

3.Использование emscripten::val (только C ++)

Emscripten также предоставляет класс под названием emscripten::val для разработчиков C ++ для взаимодействия между JS и C ++.Это абстрагирует любые типы JS / C ++ для удобства.Вы можете получить массив, используя это.

Это пример, взятый из документации и комментария Гленна:

#include <emscripten/bind.h>
#include <emscripten/val.h>

emscripten::val getBytes() {
    return emscripten::val(
       emscripten::typed_memory_view(buffer->size(),
                                     buffer->data()));
}

EMSCRIPTEN_BINDINGS() {
    function("getInt8Array", &getInt8Array);
}

Затем вы можете вызвать getInt8Array() в JSсторона, чтобы получить типизированный массив.

Заключение

Здесь есть 3 варианта, чтобы получить массив из WASM.В любом случае, я думаю, вы должны понимать концепции WebAssembly.Memory и особенности, лежащие в основе варианта 1, потому что это самый низкий уровень для получения массива из WASM, и, что наиболее важно, это неуправляемый и небезопасный доступ к памяти, поэтомучто данные легко повредить, когда объект освобожден или изменен на стороне C / C ++;Для этого конкретного случая требуется знание последствий низкого уровня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...