Чтобы позволить новые текстуры транслироваться в WebGL без блокировки основной поток пользовательского интерфейса, мы скомпилировали как libjpeg, так и в реальном времени DXT-текстурный компрессор для javascript, используя emscripten с asm.js, и запускаем их как внутри одного веб-исполнителя.Как исправить ошибку «Недостаточно памяти» при попытке отправить данные из веб-мастера после обработки данных в программе на C++ Emscripten'а
На 6-летнем ноутбуке, работающем с изображениями исходного изображения 2048x2048 Jpeg, мы декодируем каждый jpeg примерно за 300 мс и затем сжимаем их до формата сжатой текстуры DXT1 примерно в 230 мс. Это более чем адекватная производительность для наших потребностей, хотя мы уверены, что она может быть улучшена несколько.
Однако проблема, с которой мы сталкиваемся, заключается в том, что десериализация возвращаемых данных из веб-сайта по-прежнему вызывает зависание основного потока пользовательского интерфейса. Что касается того, что каждый возвращаемый файл DTX1 равен 2 МБ, это совсем не удивительно. Чтобы исправить это, мы намеревались отправить данные обратно с использованием переносимых веб-сайтов объектов, позволяя получить ArrayBuffer
просто в основной поток без необходимости его копирования.
Однако, когда мы пытаемся это сделать, мы получаем ошибку InternalError: out of memory
на вызов postMessage
.
Это способ, которым мы вызываем компрессор DXT и отправляем обратно полученный результат typedArray
. (this.decoded
просто декодируются файл JPEG в качестве исходных данных RGBA в Uint8Array
и переменной STB
доступов версия emscripten'd нашего DXT компрессора)
ImageDecoder.prototype._compressDXT = function(){
console.log('COMPRESS DXT');
var start = Date.now();
var srcSize = this.decoded.length*this.decoded.BYTES_PER_ELEMENT;
var inputPtr = STB._malloc(srcSize);
var outputPtr = STB._malloc(srcSize/8);
var inputHeap = new Uint8Array(STB.HEAPU8.buffer, inputPtr, srcSize);
var outputHeap = new Uint8Array(STB.HEAPU8.buffer, outputPtr, srcSize/8);
//set inputHeap to jpeg decoded RGBA data
inputHeap.set(this.decoded);
//compress data to DXT1
STB.ccall('rygCompress', null, ['number', 'number', 'number', 'number'],
[outputPtr, inputPtr, 2048, 2048]);
var result = new Uint8Array(outputHeap.buffer, outputHeap.byteOffset, outputHeap.length);
STB._free(inputHeap.byteOffset);
STB._free(outputHeap.byteOffset);
console.log('FINAL SIZE: ' + result.length*result.BYTES_PER_ELEMENT);
console.log('compressed in: ' + (Date.now() - start) + 'ms');
//send back to main thread
postMessage({
complete: true,
result: result
}, [result.buffer]);
//perform clean up
this._cleanUp();
}
Второй убирают transferable
список и изменить postMessage
вызова следующее:
postMessage({
complete: true,
result: result
});
Тогда все работает как ожидалось. Я могу только предположить, что это сводится к нашей неопытности с emscripten и что мы делаем что-то не так с _malloc
, _free
и нашими typedArrays
и ArrayBuffers
. Но пока мы еще не смогли понять, в чем мы ошибаемся.
Любая помощь была бы принята с благодарностью.
Происходит ли ошибка в 'postMessage', а не' this._cleanUp() '? – zakki
Да, на '' 'postMessage'', однако я нашел причину и отвечу на мой собственный вопрос. – gordyr