Огромная разница в производительности при использовании drawImage с IMG против CANVAS


8

Я собрал пару простых тестов, которые отображают изображение на холсте. Один визуализируется из IMG, а другой - из закадрового CANVAS. Вы можете увидеть код и результаты здесь: http://jsperf.com/canvas-rendering/2

В большинстве браузеров рендеринг с изображения выполняется намного быстрее, чем с холста, за исключением Chrome, где ситуация обратная. Кто-нибудь может объяснить причину различий? В конце концов, мы рендерим одни и те же данные пикселей в одном и том же месте назначения.


2
Я не совсем уверен, что это вопрос или хотя бы один, на который мы могли бы ответить. Помимо этого, хотя, глядя на ваш тест, кажется, что только другие действительно медленнее рендерит объекты canvas, а не Chrome, что необычно для медленного рендеринга изображений.
Мэтт Кемп

Но почему вообще есть разница, когда в обоих случаях они представляют одни и те же данные? И тот факт, что по крайней мере один крупный браузер имеет противоположную характеристику производительности, означает, что нам нужно реализовать два пути кода в наших средствах визуализации.
Alekop

Не могли бы вы добавить в тестовый рендеринг без buffercanvas и тега img? Было бы интересно посмотреть.
justanotherhobbyist

@hustlerinc: Вы имеете в виду рендер с холста на себя? Что это докажет? Вся графика игры загружается из изображений, поэтому вы должны использовать изображение в какой-то момент процесса.
Alekop

@alekop Нет, я имею в виду пропуск закадрового холста и использование только одного холста. Я думаю, что в Интернете это должно ускорить рендеринг, но у меня нет доказательств этого. И слишком ленив / неопытен, чтобы сделать тест самостоятельно.
justanotherhobbyist

Ответы:


9

Хорошо, я понял это. Почти. Это на самом деле довольно очевидно, и я чувствую себя немного глупо, что не заметил этого сразу. При вызове drawImage(src, 0, 0)без указания ширины / высоты он рисует всю область src, которая в этом случае намного больше (холст 320x420 по сравнению с img 185x70). Так что в случае холста браузер делает гораздо больше работы, что объясняет более низкую производительность. Я все еще озадачен более высоким счетом Chrome с большим SRC.

dest.drawImage(src, x, y) // bad
dest.drawImage(src, x, y, w, h, destX, destY, w, h) // good

Я опубликовал обновленную версию, которая использует те же регионы, и различия гораздо ближе. http://jsperf.com/canvas-rendering/5

Я до сих пор не могу объяснить, почему есть разница, но сейчас она настолько мала, что мне все равно.


В Chrome 43 с Windows 8 и Intel Graphics HD происходит сбой при первом запуске теста. Когда тест заканчивается, drawImage (img) становится явным победителем, drawImage (canvas) на 94% медленнее.
Шербан

Firefox 38 работает гладко, никаких проблем нет, и оба теста близки.
Шербан

Если вы масштабируете свои изображения, это также снижает производительность @alekop ( developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/… )
Джерш,

4

Chrome, скорее всего, будет использовать аппаратное ускорение.

Создайте холст 240x240 и запустите эксперимент в Chrome, затем создайте холст 300x300 и повторите его. Я ожидаю, что больший холст будет быстрее из-за того, что аппаратное ускорение включится после 256x256, а Chrome использует программное обеспечение, когда размеры меньше.

Также стоит отметить, что -webkit-transform: translateZ (0) отключает аппаратное ускорение.

Я не проверял ничего из вышеперечисленного; Я знаю это только из-за того, что один из инженеров Chrome прокомментировал ошибку, о которой я сообщил в chrome, когда вы пересекаете аппаратный и программный порог, динамически изменяя размер холста от большего к меньшему, чем граница 256x256 или наоборот. Решением этой ошибки было отключение ускорения с помощью translateZ, как упомянуто выше.

В моем случае я просто не позволял пользователям изменять размер менее 256x256.


Повороты прочь аппаратное ускорение? Разве это не включается?
Гилберт-v

1

Иногда изображения могут быть загружены в память графического процессора и холст в памяти хоста. В этом случае, когда вы рисуете с изображения на холст, данные изображения должны быть сначала скопированы в память хоста, а затем в холст.

Я заметил такое поведение с Chrome, когда писал проект, который загружает изображения размером более 100 миллионов пикселей, а затем читает их части на небольшом холсте размером 256x256 ( http://elhigu.github.io/canvas-image-tiles/ ).

В этом проекте, если я рисовал непосредственно из тега изображения на холст в Chrome, память всегда переходила к ~ 1,5 ГБ, когда началось рисование, а затем, когда рисование заканчивалось, память снова освобождалась, даже исходное изображение размером 250 мегапикселей все время отображалось на странице.

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


0

Не могу объяснить различия, но я не согласен с

И тот факт, что по крайней мере один крупный браузер имеет противоположную характеристику производительности, означает, что нам нужно реализовать два пути кода в наших средствах визуализации. - алекоп

Если вы посмотрите на результаты в js.pref, различия в chrome довольно тонкие. Я бы придерживался только рендеринга с изображения, когда это возможно.


Проблема в том, что я полагаюсь на закадровые полотна для создания сложных изображений. Например, я рендерил кадры анимации персонажа в закадровый буфер, а затем рендерил такие вещи, как одежда / броня / оружие сверху. Затем игра рендерится из составного холста, а не рендерит все эти детали для каждого персонажа, каждого кадра. Поскольку в браузерах, не поддерживающих Chrome, производительность «холст-холст» настолько низка, что мне придется визуализировать композит обратно в изображение. Это не конец света, но я надеялся, что есть обходной путь.
Alekop

0

Размер изображения 185 * 70, но мы создаем холст с размером, я думаю, что это приведет к потере производительности, поэтому я установил размер внеэкранного холста так же, как изображение. И разница ближе.

var g_offscreenCanvas = createCanvas(185, 70);

http://jsperf.com/canvas-rendering/60

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.