Как 2D-чертежные структуры, такие как Pixi.js, делают рисование холста быстрее?

Я нашел bunnymark для холста Javascript здесь.

Теперь, конечно, я понимаю, что их рендеринг по умолчанию использует webGL, но пока меня интересует только собственная производительность 2D-контекста. Я отключил webGL на firefox и после нереста 16500 кроликов, счетчик показал FPS из 25. Я решил написать свой собственный очень простой цикл рендеринга, чтобы увидеть, сколько добавочных Pixi добавлено. К моему удивлению, я получил только FPS 20.

Мой примерно эквивалент JSFiddle.

Итак, я решил изучить здесь источник , и, похоже, это не волшебство в коде рендеринга:

do  
{
    transform = displayObject.worldTransform;
            ...
    if(displayObject instanceof PIXI.Sprite)
    {

        var frame = displayObject.texture.frame;

        if(frame)
        {
            context.globalAlpha = displayObject.worldAlpha;

            context.setTransform(transform[0], transform[3], transform[1], transform[4], transform[2], transform[5]);

            context.drawImage(displayObject.texture.baseTexture.source, 
                               frame.x,
                               frame.y,
                               frame.width,
                               frame.height,
                               (displayObject.anchor.x) * -frame.width, 
                               (displayObject.anchor.y) * -frame.height,
                               frame.width,
                               frame.height);
        }                      
    }

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

Мои знания заканчиваются здесь, к сожалению, и мне любопытно, сможет ли кто-нибудь пролить свет на происходящее.

Ответы

Ответ 1

Я считаю, на мой взгляд, что это сводится к тому, как "компилируемый" (кэшируемый) код. Как известно, Chrome и Firefox используют два разных компилятора JavaScript/engine, которые оптимизируют и кэшируют код по-разному.

Операции холста

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

Тип значений позиции может влиять на производительность, но значения float versus integer, но поскольку как ваша скрипка, так и PIXI, похоже, используют поплавки, это не является ключом здесь.

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

Кэширование переменных и свойств

(Я был непреднамеренно слишком сфокусирован на прототипном аспекте в первой версии этого ответа. Суть, на которую я пыталась попасть, была в основном перемещением объекта, поэтому здесь следующий текст немного переформулирован -)

PIXI использует свойства объекта в качестве скрипта, но эти пользовательские объекты в PIXI меньше по размеру, поэтому перемещение дерева объектов занимает меньше времени по сравнению с тем, что требуется для перемещения большего объекта, такого как холст или изображение (свойство, такое как width также будет в конце этого объекта).

Это известная классическая оптимизация для кэширования переменных из-за этой причины (время траверса). Эффект сегодня меньше, поскольку двигатели стали более умными, особенно V8 в Chrome, которые, похоже, могут предсказать/кэшировать это лучше внутри, в то время как в Firefox, похоже, все еще есть какое-то влияние, чтобы не кэшировать эти переменные в коде.

Имеет ли значение производительность? Для коротких операций очень мало, но при этом 16,500 кроликов на холст требуют и получают выгоду от этого (в FF), поэтому любая микро-оптимизация действительно учитывается в таких ситуациях.

Demos

Я прототипировал "средство визуализации", чтобы приблизиться к PIXI, а также к кешированию свойств объекта. Это дало пакет производительности в Firefox:
http://jsfiddle.net/AbdiasSoftware/2Dbys/8/

Я использовал медленный компьютер (чтобы увеличить удар), который запускал вашу скрипку примерно на 5 FPS. После кэширования значений он работал со скоростью 6-7 кадров в секунду, что на 20% больше, чем на этом компьютере, показывая, что это имеет эффект. На компьютере с большим кэшем команд процессора и т.д. Эффект может быть меньше, но он там, поскольку это связано с самим механизмом FF (отказ от ответственности: я не утверждаю, что это научный тест, но только указатель: )).

/// cache object properties
var lastTime = 0,
    w = canvas.width,
    h = canvas.height,
    iw = image.width,
    ih = image.height;

Эта следующая версия кэширует эти переменные как свойства объекта (самого себя), чтобы показать, что это также повышает производительность по сравнению с использованием больших глобальных объектов напрямую - результат примерно такой же, как и выше:
http://jsfiddle.net/AbdiasSoftware/2Dbys/9/

var RENDER = function () {
    this.width = canvas.width;
    this.height = canvas.height;
    this.imageWidth = image.width;
    this.imageHeight = image.height;
}

В заключение

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

Механизм FF кажется еще не таким "умным", как двигатель V8 в отношении перемещения объекта по дереву и ветвям, поэтому переменные кэширования оказывают влияние на FF, который появляется, когда отображается высокий спрос (например, когда рисунок 16 500 кроликов на "рамку" ).

Ответ 2

Одна разница, которую я заметил между вашей версией и Pixi, такова:

Вы выполняете изображение в определенных координатах, передавая x/y прямо в функцию drawImage:

drawImage(img, x, y, ...);

.. тогда как Pixi переводит весь контекст canvas, а затем рисует изображение в 0/0 (уже сдвинутого контекста):

setTransform(1, 0, 0, 1, x, y);
drawImage(img, 0, 0, ...);

Они также передают больше аргументов drawImage; аргументы, которые управляют "прямоугольником назначения" - dx, dy, dw, dh.

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

Но есть что-то еще...

Я подсчитал кроликов до 5000, отключил WebGL и Pixi на самом деле хуже работает, чем версия пользовательского скрипта.

Я получаю ~ 27 FPS на Pixi:

enter image description here

и ~ 32-35 FPS на скрипте:

enter image description here

Это все в Chrome 33.0.1712.4 dev, Mac OS X.

Ответ 3

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

Я нашел это в своем источнике...

// update the background color
if (this.view.style.backgroundColor != stage.backgroundColorString &&
    !this.transparent) {
    this.view.style.backgroundColor = stage.backgroundColorString;
}

Возможно, они установили, что холст непрозрачен для этой демонстрации (скрипка на самом деле не работает для меня, похоже, что большинство из bunnys выпрыгивают с чрезвычайно большим dt большую часть времени)?

Я не думаю, что это свойство доступа к объектам/компилятивности объекта: точка действительна, но я не думаю, что она может объяснить, что большая разница.