Производительность HTML5 Canvas - подсчет циклов / кадров в секунду - PullRequest
14 голосов
/ 22 февраля 2011

Я знаю, что раньше задавалось несколько вопросов, таких как этот, например: Проверить FPS в JS? - который работал до некоторой степени, я смог выяснить, сколько времени занимает каждый циклдля завершения.

Хотя я ищу что-то более читаемое и контролируемое.Я хочу установить частоту обновления счетчика FPS, чтобы он был медленным, чтобы он был удобочитаемым или настолько быстрым, насколько может работать приложение, поэтому я могу использовать его на каком-то спидометре.

В любом случаевот код, который у меня есть прямо сейчас:

var lastLoop = new Date().getTime();

function updateStage()
{   
    clearCanvas();
    updateStageObjects();
    drawStageObjects();     

    var thisLoop = new Date().getTime(); 
    var fps = (thisLoop - lastLoop);

    $('#details').html(fps);

    lastLoop = thisLoop;
    iteration = setTimeout(updateStage, 1);
}
  1. Прав ли я, чтобы установить функцию setTimeout со скоростью 1 миллисекунда?Я думал, что это просто сделает цикл так быстро, как только возможно.

  2. Если я посчитаю каждые 100 кадров или около того, выясню, сколько миллисекунд потребовалось, чтобы запустить 100 кадров, а затем сделатьрасчет, чтобы узнать, сколько кадров он сделал бы, если бы миллисекунды были 1000?Каким будет этот расчет?

  3. Чтобы сделать результат более точным, я предполагаю, что мне нужно отобразить средние значения, поскольку один кадр может значительно варьироваться, как мне это сделать?

Любые советы приветствуются.

Спасибо.

Ответы [ 4 ]

23 голосов
/ 22 февраля 2011
  1. Обратите внимание, что чем быстрее вы обновите свой вывод, тем больше вы будете влиять на ваши измерения. Хотя это и минимально, я пытаюсь обновлять свой fps один раз в секунду или меньше, если нет необходимости идти быстрее.

  2. Мне нравится использовать фильтр низких частот для моих результатов, чтобы временный сбой не оказывал слишком сильного влияния на значения. Это легче вычислить и записать, чем скользящее среднее, и у него нет проблемы общего среднего, когда на «текущие» показания влияет общая производительность за весь прогон (например, аномальные показания во время запуска).

Соберите, вот как я обычно измеряю FPS:

var fps = 0, now, lastUpdate = (new Date)*1;

// The higher this value, the less the FPS will be affected by quick changes
// Setting this to 1 will show you the FPS of the last sampled frame only
var fpsFilter = 50;

function drawFrame(){
  // ... draw the frame ...

  var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
  if (now!=lastUpdate){
    fps += (thisFrameFPS - fps) / fpsFilter;
    lastUpdate = now;
  }

  setTimeout( drawFrame, 1 );
}

var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = fps.toFixed(1) + "fps";
}, 1000); 
3 голосов
/ 11 ноября 2011

Я что-то пробовал,

Если вы измените

lastUpdate = now

до

lastUpdate = now * 1 - 1;

Ваша проблема с NaN решена! Это также используется там, где определено значение lastUpdate. Возможно, потому что он не может конвертировать дату в метку времени Unix.

Новый результат будет:

var fps = 0, now, lastUpdate = (new Date)*1 - 1;

// The higher this value, the less the FPS will be affected by quick changes
// Setting this to 1 will show you the FPS of the last sampled frame only
var fpsFilter = 50;

function drawFrame(){
  // ... draw the frame ...

  var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
  fps += (thisFrameFPS - fps) / fpsFilter;
  lastUpdate = now * 1 - 1;

  setTimeout( drawFrame, 1 );
}

var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = fps.toFixed(1) + "fps";
}, 1000); 
2 голосов
/ 24 марта 2014

Я взял опубликованные решения и немного их улучшил.Посмотрите здесь - http://jsfiddle.net/ync3S/

  1. Я исправил эту ошибку NaN, используя Date.now () вместо того, чтобы каждый раз создавать новый объект даты и пытаться ссылаться на него.Это также предотвращает необходимость сбора мусора.
  2. Я немного подобрал имена переменных и функций и добавил некоторые дополнительные комментарии - не обязательно, но приятно иметь.
  3. Я включил некоторый код для рисования для тестирования.
  4. Я добавил fpsDesired в качестве тестовой переменной для цикла двигателя.
  5. Я запустил fpsAverage в fpsDesired, поэтому с fpsFilter он не работает с 0 до реального FPS, скорее, начиная стребуемый FPS и настройки оттуда.
  6. Рисование теперь блокирует, если это уже рисование, и это может использоваться для приостановки и других функций управления.

Основной блок выглядит следующим образом:

var fpsFilter = 1; // the low pass filter to apply to the FPS average
var fpsDesired = 25; // your desired FPS, also works as a max
var fpsAverage = fpsDesired;
var timeCurrent, timeLast = Date.now();
var drawing = false;

function fpsUpdate() {
    fpsOutput.innerHTML = fpsAverage.toFixed(2);
}

function frameDraw() {
    if(drawing) { return; } else { drawing = true; }

    timeCurrent = Date.now();
    var fpsThisFrame = 1000 / (timeCurrent - timeLast);
    if(timeCurrent > timeLast) {
        fpsAverage += (fpsThisFrame - fpsAverage) / fpsFilter;
        timeLast = timeCurrent;
    }

    drawing = false;
}

setInterval(fpsUpdate, 1000);
fpsUpdate();

setInterval(frameDraw, 1000 / fpsDesired);
frameDraw();

Собираюсь повозиться и посмотреть, смогу ли я придумать что-нибудь более плавное, так как эта тема находится на вершине в результатах поиска Google.

Давайте посмотрим, к чему все мы можем прийтив команде, и я думаю, что всегда полезно не использовать сторонние библиотеки, делая код переносимым для всех:)

-Platima

1 голос
/ 04 мая 2016

Просто установите интервал, который сбрасывает счетчик кадров в секунду каждую секунду.

var fpsOut, fpsCount;

var draw = function () {

    fpsCount++;

    ..Draw To Canvas..


    ..Get the fps value: fpsOut

    requestAnimationFrame(draw);

};
setInterval(function () {

    fpsOut = fpsCount;
    fpsCount = 0;

}, 1000);

draw();
...