Как передать холст imageData в программу emscripten C ++, не копируя ее?

У меня есть данные изображения холста:

myImage = ctx.getImageData(0, 0, 640, 480);

Я понял, что я могу создавать новые Uint8Array и использовать set() скопировать imagedata. Это рабочий пример:

var numBytes = width * height * 4;
var ptr= Module._malloc(numBytes);
var heapBytes= new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
heapBytes.set(new Uint8Array(myImage.data));
_processImage(heapBytes.byteOffset, width, height);
myImage.data.set(heapBytes);

Но, к сожалению, каждый .set() операция выполняется намного медленнее, чем обработка изображения, а приведенный выше код работает медленнее, чем реализация JS!

Итак, я хочу обработать изображение, не копируя его. Я могу успешно читать и записывать данные прямо в кучу следующим образом:

Module.HEAPU8.set(myImage.data, myImage.data.byteOffset);
_processImage(myImage.data.byteOffset, width, height);
myImage.data.set(new Uint8ClampedArray(Module.HEAPU8.buffer , myImage.data.byteOffset , numBytes));

Это быстрее, но все еще первый .set() занимает 17 мс, чтобы выполнить.

Прототип функции c ++:

extern "C" {

int processImage(unsigned char *buffer, int width, int height)
{
}

}

Есть ли способ передать массив в C ++ без использования set()? Просто сказать С ++, где данные находятся в памяти, и разрешить их модифицировать?

4

Решение

Просто сказать С ++, где данные находятся в памяти, и разрешить их модифицировать?

Начиная с версии 1.34.12, Emscripten имеет SPLIT_MEMORY опция, где вы можете указать Emscripten использовать существующий буфер как часть его пространства памяти, которое разделено на куски одинакового размера

Вы могли бы, например, получить буфер с холста

var existingBuffer = myImage.data.buffer;
var bufferSize = existingBuffer.byteLength; // Must be equal to SPLIT_MEMORY

а затем, модифицируя пример из объяснение разделения памяти, скажите Emscripten использовать этот буфер как часть своего пространства памяти

var chunkIndex = 2; // For example
allocateSplitChunk(chunkIndex, existingBuffer);

и затем передайте указатель на блок вашей функции C ++.

var pointerToImageInGlobalMemorySpace = chunkIndex * bufferSize;
_processImage(pointerToImageInGlobalMemorySpace, width, height);

тем не мение есть проблемы и ограничения

  • Пространство памяти Emscripten должно быть разбито на куски точно такого же размера, как и буфер данных изображения холста.
  • Есть видимо серьезные последствия для производительности для всего кода, скомпилированного Emscripten, который может сделать это хуже, чем ваш исходный код.
2

Другие решения

Других решений пока нет …