Canvas API и его скорость

Доброго времени суток. Некоторое время назад наткнулся на интересную трёхмерную демонстрацию карты звёзд, в центре которой, естественно, Солнце. Эта работа занимательна многим, например, как 2 миллиона трёхмерных координат передаются по сети, но меня заинтересовала больше частота кадров от 40 до 60 в минуту, причём минимальный порог она достигала только при максимально отдалении.

2 миллиона точек это немного, тем более для графического процессора, но так как в последнее время занимаясь разного рода визуализацией на canvas, слово частота и количество элементов воспринимаются довольно остро. Одна из таких работ по визуализации, это отображение амплитуды колебаний звука на определённых частотах в виде изменяющихся в размере, положении и цвете трёхмерных объектов. «Движок» для универсальной работы с отображением объектов собственный и, что странно, узкое место в нём не мои функции просчёта проекций из трёхмерного пространства на экран, а «родные» для canvas функции выделения области и её заполнения (больше 2 тысяч полигонов при шестидесяти кадрах в секунду он выводить не может).

Используются методы: beginPath, lineTo, fill.

Все из них наверняка исполняются на ЦП (хотя можно было бы заполнением и на ГП заниматься, правда только при большом количестве необходимых к заливке областей, объединяя их, иначе скорость обмена данными между памятью и памятью ГП может стать узким местом).

Вернёмся к демонстрации.

Вспомнив о ней совсем недавно, решил реализовать нечто подобное примеру, в котором каждая звезда является неизменной в размерах точкой (пикселем).

Программа:

Запись координат точек велась в двухбайтный целочисленный одномерный массив, индексы которого по модулю 3 равные 0 соответствовали X, 1 — Y, 2 — Z. Запись координат точек на экране в такого же типа одномерный массив, короче в полтора раза.

Использование метода fillRect отмелось сразу, даже без тестирования. И за основу вывода были взяты getImageData / putImageData.

После некоторого времени отбрасывания всего и оставления только необходимого пришло время тестов. Начались они с тысячи точек, на что соответствующий счётчик показал любимые числа (60, 59). На увеличение до двух тысяч он никак не отреагировал. И так до 128 тысяч, потом Chrome начал потихоньку сбавлять обороты.

Надо сказать, что при развёртывании окна на весь экран (1920x1080), а не на половину, Chrome даже при отсутствии звёзд показывал 40 кадров в секунду (происходит это из-за «ручного» очищения imageData в каждом кадре).

    var data = IMGD.data;            // IMGD получен с помощью метода getImageData
    var len = data.length;             
    var color = 0, alpha = 255;   // поскольку цвет заливки чёрный (rgb(0,0,0))
                                                // то и поместим его в в одну переменную

                                                // в imageData цвет точки задаётся четырьмя байтами (rgba)
                                                // для задания прозрачности используем alpha
    for(var i=0; i<len; i+=4) {
        data[i] = data[i+1] = data[i+2] = color;
        data[i+3] = alpha;
    }

Видимо, вышеуказанный код медленный и браузеры умеют заливать быстрее, но при использовании их умения придётся каждый раз создавать новый imageData, а это ещё медленнее.
(это узкое место, но как следует оно не обдумывалось)

Производительность:

Несмотря на то, что в браузере отечественной компании у которой «найдётся всё», движок тоже webkit, частота кадров при половине экрана и 256 тысячах элементов — 60 гц.

Все тесты. В тестах использовались браузеры:

1. Google Chrome 54.0.2840.99 m
2. Yandex Browser 16.10.1.1114

Количество элементов (тыс.) Chrome Yandex браузер
128 60 60
256 50 60
512 35 45
1024 22 27

Таблица 1. Тесты производительности, при окне в половину экрана
Количество элементов (тыс.) Chrome Yandex браузер
128 32 60
256 28 47
512 22 34
1024 15 22

Таблица 2. Тесты производительности, при окне во весь экран

Если немного подумать, то средний результат не такой уж ошеломляющий (это просто работа с памятью), но разница по скорости обработки подобных данных на ГП всего в десять раз, что кажется весьма незначительным.
Метки:
javascript, html5, canvas, скорость выполнения