Журнал о программированнии на языках Blitz3D, BlitzPlus, BlitzMax

Реальный счетчик FPS

Материал из Blitz Et Cetera

Перейти к: навигация, поиск

Почему реальный? А потому, что он считает реальное количество ФПС, а не гипотетическое. Просматривая некоторые исходники, я заметил, что есть определенная тенденция считать предполагаемое, а не фактическое количество кадров. Такой подход, конечно, дает возможность наблюдать значение ФПС сразу после запуска, но нам ведь важно настоящее значение, а не предполагаемое (надеюсь что так).

Кратко о разнице в подходах (назову их расчетным и подсчетным):

  • Расчетный: Предполагаемое количество считается исходя из времени обработки кадра. Зная это время, мы можем определить количество кадров, которое у нас получится за больший промежуток.
  • Подсчетный: считается тупо подсчетом кадров за отрезок времени.

В чем недостатки расчетного метода: в связи с многозадачностью современных ОС, из-за параллельных процессов время от начала до завершения одного процесса будет разным, даже если выполняться будет одинаковая задача. Из-за этого происходят определенные колебания расчетного значения. Плюс получаемое значение можно отнести только к данному кадру, а для другого кадра, оно будет уже другим, что не дает общей картины производительности. Плюс этого метода один – расчетное значение можно получить уже после первого кадра. Недостаток подсчетного метода в том, что мы можем узнать количество ФПС только после какого-то промежутка времени.

Вот пример с классом счетчика ФПС:

Strict


Local bExit% = False
Const fBaseFPS# = 50
Const cTimeDelta%  = 1000/fBaseFPS '1000 - milisec in second / fps
Local fps:TFPSCounter = New TFPSCounter
Global  fSpeedMul# = 1;

    Graphics800 , 600 , 0 , fBaseFPS

    WhileNot bExit

        bExit = KeyDown(KEY_ESCAPE) | AppTerminate()

        Local startTime = MilliSecs();

        fps.start()

        DrawScene()

        'draw info

        DrawText"FPS: " + round(fps.fps,1) , 8 , 8
        DrawText"Min/Max: " + round(fps.fps_min,1) +"/" + round(fps.fps_max,1), 100, 8
        DrawText"Average: " + round(fps.fps_average,3), 300, 8

        'animate scene

        UpdateScene()

        'fps.finish()

        Flip -1 'by Graphics refresh rate

        fps.finish()

    Wend

Global x#=0, y#=300

Function UpdateScene()

    x :+ 0.5 * fSpeedMul
    If x > GraphicsWidth() Then x = 0
    'Delay(Rand(1,30))

EndFunction

Function DrawScene()

    Cls
    DrawOval(x,y, 50, 50)

EndFunction

End

Type TFPSCounter

    Field _fps_start#
    Field _fps_count#

    Field _avfps_start#
    Field _fps_average_count#

    Field fps#
    Field fps_average#

    Field fps_min# = 1000
    Field fps_max# = 0

    Method Start()

        Local ms# = MilliSecs()

        If _fps_start = 0 Then _fps_start = ms
        If _avfps_start = 0 Then _avfps_start = ms

    EndMethod

    Method Finish()

        Local millis# = MilliSecs()
        Local time# = millis - _fps_start

        _fps_count :+ 1

        If time > 1000

            fps = _fps_count*1000/time

            If fps < fps_min Then fps_min = fps
            If fps > fps_max Then fps_max = fps

            _fps_start = 0
            _fps_count = 0

        EndIf

        _fps_average_count :+ 1

        time = millis - _avfps_start

        If time > 1000
            fps_average = _fps_average_count * 1000 / time
        EndIf

    EndMethod

EndType

Function Round$(value#, nDecimals%=2)

    Local str$ = value
    Local pos% = Instr(str , ".")

    If nDecimals > 0
        str = str[..pos + nDecimals]
    Else
        str = str[..pos - 1]
    EndIf

    Return str

EndFunction

Комментарии к коду:

  • Можно поиграть с задержкой в UpdateScene.
  • Дополнена функция форматированного вывода плавающих чисел Round$.
  • И еще внимание на положение вызова метода Finish класса счетчика в коде. Если его поставить там, где он закомментирован (сразу после апдейта сцены), то количество кадров странным образом считается на 1 больше. А дело в том, что если его ставить до синхронизации (Flip -1), то получится, что последний кадр в отрезке времени посчитается до завершения самого отрезка времени. Поэтому надо ставить вызов fps.finish() после синхронизации, чтобы и временные интервалы и количество кадров считались правильно.

Автор: Oxid

Другие

Друзья