Подтвердить что ты не робот

Эффективность холста HTML при рисовании множества строк

В настоящее время я пишу приложение, которое отображает много, и я имею в виду много 2D-путей (из сотен, тысяч крошечных сегментов) на холсте HTML5. Как правило, несколько миллионов баллов. Эти точки загружаются с сервера в двоичный ArrayBuffer.

Я, вероятно, не буду использовать столько очков в реальном мире, но я заинтересован в том, как улучшить производительность. Вы можете назвать это любопытством, если хотите;)

В любом случае, я протестировал следующие решения:

  • Использование gl.LINES или gl.LINE_STRIP с WebGL и вычисление всего в шейдерах на графическом процессоре. В настоящее время самый быстрый, может отображать до 10M сегментов, не дрогнув на моем Macbook Air. Но есть очень строгие ограничения для двоичного формата, если вы хотите избежать обработки вещей в JavaScript, что происходит медленно.

  • Используя Canvas2D, нарисуйте огромный путь со всеми сегментами в одном вызове stroke(). Когда я прохожу 100 тыс. Точек, страница замерзает на несколько секунд до обновления холста. Итак, не работаем здесь.

  • Использование Canvas2D, но нарисуйте каждый путь со своим собственным вызовом stroke(). Несмотря на то, что другие говорили в Интернете, это намного быстрее, чем рисовать все за один звонок, но все же намного медленнее, чем WebGL. Все начинает ухудшаться, когда я достигаю сегментов 500 тыс..

Два решения Canvas2D требуют прокрутки всех точек всех путей в JavaScript, так что это довольно медленно. Знаете ли вы какой-либо метод (ы), который может улучшить скорость итерации JavaScript в ArrayBuffer или скорость обработки вообще?

Но, что странно, экран не обновляется сразу после завершения всех обращений рисования на холсте. Когда я перехожу к пределу производительности, между окончанием вызовов рисования и обновлением холста существует заметная задержка. У вас есть идея, откуда это происходит, и есть ли способ уменьшить его?

4b9b3361

Ответ 1

Во-первых, WebGL был хорошей идеей, но объем обработки, требуемый для декодирования и отображения двоичных данных, просто не работает в шейдерах, поэтому я исключил его.

Вот основные узкие места, с которыми я столкнулся. Некоторые из них довольно распространены в общем программировании, но это хорошая идея запомнить их:

  • Лучше всего использовать несколько маленьких for циклов
  • Создать переменные и блокировки на самом высоком уровне, не создавать их внутри циклов for
  • Извлеките свои данные в куски и используйте setTimeout, чтобы запланировать следующий фрагмент через несколько миллисекунд: таким образом, пользователь все равно сможет использовать пользовательский интерфейс
  • Объекты и массивы JavaScript бывают быстрыми и дешевыми, используйте их. Лучше всего читать/записывать их в последовательном порядке, от начала до конца.
  • Если вы не записываете данные последовательно в массив, используйте объекты (поскольку несекретные чтения-записи дешевы для объектов) и нажмите индексы в массив индексов. Я использовал реализацию SortedList, чтобы отсортировать индексы, которые я нашел здесь. Накладные расходы были минимальными (около 10-20% от времени рендеринга), и в итоге это было хорошо.

Что обо всем, что я помню. Если я найду что-то еще, я обновлю этот ответ!