У меня есть плагин FireBreath, который окрашивается в окно 800 x 480 с частотой 10 Гц. Я хотел бы дублировать это окно на HTML-странице в виде миниатюр (что-то вроде 120 х 72). В идеале миниатюра будет обновляться с частотой 10 Гц, хотя 1 Гц будет приемлемой.Дублирование окна плагина в JavaScript
У меня есть рабочий код, но он слишком медленный, чтобы его можно было использовать.
Javascript начинает получать контекст холста и массив манипулировать (вдохновленный https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/):
var canvas = document.getElementById('thumbnail')
var context = canvas.getContext('2d');
var imgData = context.createImageData(120, 72);
var buf = new ArrayBuffer(imgData.data.length);
var buf8 = new Uint8ClampedArray(buf);
var data = new Uint32Array(buf);
В JavaScript я хотел бы сделать что-то вроде
for (n = 0; n < data.length; ++n) {
data[n] = 0xff0000ff; // paint pixel red
}
с последующим
imgData.data.set(buf8);
context.putImageData(imgData, 0, 0);
который выполняется очень быстро. Проблема в том, что я хочу передать ответственность за рисование миниатюры плагина. Поэтому вместо цикла JavaScript я делаю что-то вроде document.getElementById("plugin").paintThumbnail(data)
, переходя в Uint32Array data
в качестве параметра.
Реализация paintThumbnail
в плагин выглядит следующим образом:
void MyPluginAPI::paintThumbnail(const FB::JSObjectPtr& data) {
if (!data)
throw FB::invalid_arguments();
int size = data->GetProperty("length").convert_cast<int>();
/* method 1 - call "set" per pixel - slowest */
for (int n = 0; n < size; n++) {
FB::VariantList pixel = FB::variant_list_of(0xff0000ff);
data->Invoke("set", FB::variant_list_of(pixel)(n)); // paint the nth pixel red
}
/* -- */
/* method 2 - call "SetProperty" per pixel - faster */
for (int n = 0; n < size; n++) {
data->SetProperty(n, 0xff0000ff); // paint the nth pixel red
}
/* -- */
/* method 3 - write to array buffer then call "set" once - fastest */
uint32_t* vals = new uint32_t[size];
for (int n = 0; n < size; n++) {
vals[n] = 0xff0000ff; // paint the nth pixel red
}
std::vector<uint32_t> valVec(vals, vals + size);
FB::VariantList vars = FB::make_variant_list(valVec);
data->Invoke("set", FB::variant_list_of(vars));
/* -- */
}
(Очевидно, что как только я получаю эту работу я буду рисовать что-то интересное - не только красное.) Каждый из трех указанных выше способов для изменения Данные JSObjectPtr намного медленнее, чем прямой JavaScript, и нет, где почти достигнута частота кадров 10 Гц (тестирование было выполнено в Chrome).
Как я могу сделать код плагина быстрее? Есть ли другой способ добиться того же результата? Или это просто ограничение плагинов?
Спасибо @taxilian, что сделал трюк. – user1972265