2015-12-16 2 views
3

У меня есть данные изображения холста:Как передать canvas 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() принимает 17ms выполнить.

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

extern "C" { 

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

} 

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

+0

Какие характеристики браузера/ОС/системы работают? 17 мс немного длиннее для копирования изображения 640x480 в память ... –

+0

Chrome 46/Windows 7 64bit/Xeon E31235 @ 3.20 ГГц/8 ГБ. В firefox set() намного быстрее, но emcescript asm.js работает медленнее ... –

ответ

1

Просто сообщите C++, где данные находятся в памяти, и разрешите его изменить?

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

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

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

, а затем, изменив пример из explanation of split memory, скажите Emscripten использовать этот буфер как часть его пространства памяти

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

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

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

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

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