Added a frame timing statistics window to the Qt tools. Allows user to enable frame timing statistical calculations and view the output on a window in realtime. Is used to verify emulator is getting the proper clock interrupts from the OS and thus check that emulation timing is deterministic.
This commit is contained in:
parent
4f08d7a8cc
commit
afaea86abd
|
@ -435,6 +435,7 @@ set(SRC_DRIVERS_SDL
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GamePadConf.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/HotKeyConf.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/TimingConf.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/FrameTimingStats.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/PaletteConf.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/GuiConf.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/drivers/Qt/MoviePlay.cpp
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "Qt/MoviePlay.h"
|
#include "Qt/MoviePlay.h"
|
||||||
#include "Qt/MovieOptions.h"
|
#include "Qt/MovieOptions.h"
|
||||||
#include "Qt/TimingConf.h"
|
#include "Qt/TimingConf.h"
|
||||||
|
#include "Qt/FrameTimingStats.h"
|
||||||
#include "Qt/LuaControl.h"
|
#include "Qt/LuaControl.h"
|
||||||
#include "Qt/CheatsConf.h"
|
#include "Qt/CheatsConf.h"
|
||||||
#include "Qt/GameGenie.h"
|
#include "Qt/GameGenie.h"
|
||||||
|
@ -654,6 +655,14 @@ void consoleWin_t::createMainMenu(void)
|
||||||
|
|
||||||
toolsMenu->addAction(ramWatchAct);
|
toolsMenu->addAction(ramWatchAct);
|
||||||
|
|
||||||
|
// Tools -> Frame Timing
|
||||||
|
act = new QAction(tr("Frame Timing ..."), this);
|
||||||
|
//act->setShortcut( QKeySequence(tr("Shift+F7")));
|
||||||
|
act->setStatusTip(tr("Open Frame Timing Window"));
|
||||||
|
connect(act, SIGNAL(triggered()), this, SLOT(openTimingStatWin(void)) );
|
||||||
|
|
||||||
|
toolsMenu->addAction(act);
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// Debug
|
// Debug
|
||||||
debugMenu = menuBar()->addMenu(tr("Debug"));
|
debugMenu = menuBar()->addMenu(tr("Debug"));
|
||||||
|
@ -1303,6 +1312,17 @@ void consoleWin_t::openTimingConfWin(void)
|
||||||
tmConfWin->show();
|
tmConfWin->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void consoleWin_t::openTimingStatWin(void)
|
||||||
|
{
|
||||||
|
FrameTimingDialog_t *tmStatWin;
|
||||||
|
|
||||||
|
//printf("Open Timing Statistics Window\n");
|
||||||
|
|
||||||
|
tmStatWin = new FrameTimingDialog_t(this);
|
||||||
|
|
||||||
|
tmStatWin->show();
|
||||||
|
}
|
||||||
|
|
||||||
void consoleWin_t::openMovieOptWin(void)
|
void consoleWin_t::openMovieOptWin(void)
|
||||||
{
|
{
|
||||||
MovieOptionsDialog_t *win;
|
MovieOptionsDialog_t *win;
|
||||||
|
|
|
@ -183,6 +183,7 @@ class consoleWin_t : public QMainWindow
|
||||||
void openPaletteConfWin(void);
|
void openPaletteConfWin(void);
|
||||||
void openGuiConfWin(void);
|
void openGuiConfWin(void);
|
||||||
void openTimingConfWin(void);
|
void openTimingConfWin(void);
|
||||||
|
void openTimingStatWin(void);
|
||||||
void openMovieOptWin(void);
|
void openMovieOptWin(void);
|
||||||
void openCodeDataLogger(void);
|
void openCodeDataLogger(void);
|
||||||
void openTraceLogger(void);
|
void openTraceLogger(void);
|
||||||
|
|
|
@ -0,0 +1,265 @@
|
||||||
|
// FrameTimingStats.cpp
|
||||||
|
//
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QCloseEvent>
|
||||||
|
|
||||||
|
#include "Qt/main.h"
|
||||||
|
#include "Qt/dface.h"
|
||||||
|
#include "Qt/input.h"
|
||||||
|
#include "Qt/config.h"
|
||||||
|
#include "Qt/keyscan.h"
|
||||||
|
#include "Qt/throttle.h"
|
||||||
|
#include "Qt/fceuWrapper.h"
|
||||||
|
#include "Qt/FrameTimingStats.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
FrameTimingDialog_t::FrameTimingDialog_t(QWidget *parent)
|
||||||
|
: QDialog( parent )
|
||||||
|
{
|
||||||
|
QVBoxLayout *mainLayout, *vbox;
|
||||||
|
QHBoxLayout *hbox;
|
||||||
|
QGroupBox *frame;
|
||||||
|
QTreeWidgetItem *item;
|
||||||
|
QPushButton *resetBtn;
|
||||||
|
struct frameTimingStat_t stats;
|
||||||
|
|
||||||
|
getFrameTimingStats( &stats );
|
||||||
|
|
||||||
|
setWindowTitle("Frame Timing Statistics");
|
||||||
|
|
||||||
|
resize( 512, 512 );
|
||||||
|
|
||||||
|
mainLayout = new QVBoxLayout();
|
||||||
|
vbox = new QVBoxLayout();
|
||||||
|
frame = new QGroupBox( tr("Timing Statistics") );
|
||||||
|
frame->setLayout( vbox );
|
||||||
|
|
||||||
|
tree = new QTreeWidget();
|
||||||
|
vbox->addWidget( tree );
|
||||||
|
|
||||||
|
tree->setColumnCount(4);
|
||||||
|
|
||||||
|
item = new QTreeWidgetItem();
|
||||||
|
item->setText( 0, tr( "Parameter" ) );
|
||||||
|
item->setText( 1, tr( "Target" ) );
|
||||||
|
item->setText( 2, tr( "Current" ) );
|
||||||
|
item->setText( 3, tr( "Minimum" ) );
|
||||||
|
item->setText( 4, tr( "Maximum" ) );
|
||||||
|
item->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
item->setTextAlignment( 1, Qt::AlignCenter);
|
||||||
|
item->setTextAlignment( 2, Qt::AlignCenter);
|
||||||
|
item->setTextAlignment( 3, Qt::AlignCenter);
|
||||||
|
item->setTextAlignment( 4, Qt::AlignCenter);
|
||||||
|
|
||||||
|
tree->setHeaderItem( item );
|
||||||
|
tree->header()->setSectionResizeMode( QHeaderView::Stretch );
|
||||||
|
tree->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
|
||||||
|
|
||||||
|
frameTimeAbs = new QTreeWidgetItem();
|
||||||
|
frameTimeDel = new QTreeWidgetItem();
|
||||||
|
frameTimeWork = new QTreeWidgetItem();
|
||||||
|
frameTimeIdle = new QTreeWidgetItem();
|
||||||
|
frameTimeWorkPct = new QTreeWidgetItem();
|
||||||
|
frameTimeIdlePct = new QTreeWidgetItem();
|
||||||
|
frameLateCount = new QTreeWidgetItem();
|
||||||
|
|
||||||
|
tree->addTopLevelItem( frameTimeAbs );
|
||||||
|
tree->addTopLevelItem( frameTimeDel );
|
||||||
|
tree->addTopLevelItem( frameTimeWork );
|
||||||
|
tree->addTopLevelItem( frameTimeIdle );
|
||||||
|
tree->addTopLevelItem( frameTimeWorkPct );
|
||||||
|
tree->addTopLevelItem( frameTimeIdlePct );
|
||||||
|
tree->addTopLevelItem( frameLateCount );
|
||||||
|
|
||||||
|
frameTimeAbs->setFlags( Qt::ItemIsEnabled | Qt::ItemNeverHasChildren );
|
||||||
|
frameTimeDel->setFlags( Qt::ItemIsEnabled | Qt::ItemNeverHasChildren );
|
||||||
|
|
||||||
|
frameTimeAbs->setText( 0, tr("Frame Period ms") );
|
||||||
|
frameTimeDel->setText( 0, tr("Frame Delta ms") );
|
||||||
|
frameTimeWork->setText( 0, tr("Frame Work ms") );
|
||||||
|
frameTimeIdle->setText( 0, tr("Frame Idle ms") );
|
||||||
|
frameTimeWorkPct->setText( 0, tr("Frame Work %") );
|
||||||
|
frameTimeIdlePct->setText( 0, tr("Frame Idle %") );
|
||||||
|
frameLateCount->setText( 0, tr("Frame Late Count") );
|
||||||
|
|
||||||
|
frameTimeAbs->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameTimeDel->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameTimeWork->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameTimeIdle->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameTimeWorkPct->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameTimeIdlePct->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
frameLateCount->setTextAlignment( 0, Qt::AlignLeft);
|
||||||
|
|
||||||
|
for (int i=0; i<4; i++)
|
||||||
|
{
|
||||||
|
frameTimeAbs->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameTimeDel->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameTimeWork->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameTimeIdle->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameTimeWorkPct->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameTimeIdlePct->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
frameLateCount->setTextAlignment( i+1, Qt::AlignCenter);
|
||||||
|
}
|
||||||
|
|
||||||
|
hbox = new QHBoxLayout();
|
||||||
|
timingEnable = new QCheckBox( tr("Enable Timing Statistics Calculations") );
|
||||||
|
resetBtn = new QPushButton( tr("Reset") );
|
||||||
|
|
||||||
|
timingEnable->setChecked( stats.enabled );
|
||||||
|
|
||||||
|
hbox->addWidget( timingEnable );
|
||||||
|
hbox->addWidget( resetBtn );
|
||||||
|
|
||||||
|
connect( timingEnable, SIGNAL(stateChanged(int)), this, SLOT(timingEnableChanged(int)) );
|
||||||
|
connect( resetBtn , SIGNAL(clicked(void)) , this, SLOT(resetTimingClicked(void)) );
|
||||||
|
|
||||||
|
mainLayout->addLayout( hbox );
|
||||||
|
mainLayout->addWidget( frame );
|
||||||
|
|
||||||
|
setLayout( mainLayout );
|
||||||
|
|
||||||
|
updateTimingStats();
|
||||||
|
|
||||||
|
updateTimer = new QTimer( this );
|
||||||
|
|
||||||
|
connect( updateTimer, &QTimer::timeout, this, &FrameTimingDialog_t::updatePeriodic );
|
||||||
|
|
||||||
|
updateTimer->start( 200 ); // 5hz
|
||||||
|
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
FrameTimingDialog_t::~FrameTimingDialog_t(void)
|
||||||
|
{
|
||||||
|
printf("Destroy Frame Timing Window\n");
|
||||||
|
updateTimer->stop();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
printf("Frame Timing Close Window Event\n");
|
||||||
|
done(0);
|
||||||
|
deleteLater();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::closeWindow(void)
|
||||||
|
{
|
||||||
|
//printf("Close Window\n");
|
||||||
|
done(0);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::updateTimingStats(void)
|
||||||
|
{
|
||||||
|
char stmp[128];
|
||||||
|
struct frameTimingStat_t stats;
|
||||||
|
|
||||||
|
getFrameTimingStats( &stats );
|
||||||
|
|
||||||
|
// Absolute
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeAbs.tgt * 1e3 );
|
||||||
|
frameTimeAbs->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeAbs.cur * 1e3 );
|
||||||
|
frameTimeAbs->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeAbs.min * 1e3 );
|
||||||
|
frameTimeAbs->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeAbs.max * 1e3 );
|
||||||
|
frameTimeAbs->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Delta
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeDel.tgt * 1e3 );
|
||||||
|
frameTimeDel->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeDel.cur * 1e3 );
|
||||||
|
frameTimeDel->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeDel.min * 1e3 );
|
||||||
|
frameTimeDel->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeDel.max * 1e3 );
|
||||||
|
frameTimeDel->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Work
|
||||||
|
sprintf( stmp, "lt %.3f", stats.frameTimeWork.tgt * 1e3 );
|
||||||
|
frameTimeWork->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeWork.cur * 1e3 );
|
||||||
|
frameTimeWork->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeWork.min * 1e3 );
|
||||||
|
frameTimeWork->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeWork.max * 1e3 );
|
||||||
|
frameTimeWork->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Idle
|
||||||
|
sprintf( stmp, "gt %.3f", stats.frameTimeIdle.tgt * 1e3 );
|
||||||
|
frameTimeIdle->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeIdle.cur * 1e3 );
|
||||||
|
frameTimeIdle->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeIdle.min * 1e3 );
|
||||||
|
frameTimeIdle->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.3f", stats.frameTimeIdle.max * 1e3 );
|
||||||
|
frameTimeIdle->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Work %
|
||||||
|
sprintf( stmp, "lt %.1f", 100.0 * stats.frameTimeWork.tgt / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeWorkPct->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.cur / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeWorkPct->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.min / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeWorkPct->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeWork.max / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeWorkPct->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Idle %
|
||||||
|
sprintf( stmp, "gt %.1f", 100.0 * stats.frameTimeIdle.tgt / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeIdlePct->setText( 1, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.cur / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeIdlePct->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.min / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeIdlePct->setText( 3, tr(stmp) );
|
||||||
|
|
||||||
|
sprintf( stmp, "%.1f", 100.0 * stats.frameTimeIdle.max / stats.frameTimeAbs.tgt );
|
||||||
|
frameTimeIdlePct->setText( 4, tr(stmp) );
|
||||||
|
|
||||||
|
// Late Count
|
||||||
|
sprintf( stmp, "%u", stats.lateCount );
|
||||||
|
frameLateCount->setText( 1, tr("0") );
|
||||||
|
frameLateCount->setText( 2, tr(stmp) );
|
||||||
|
|
||||||
|
tree->viewport()->update();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::updatePeriodic(void)
|
||||||
|
{
|
||||||
|
updateTimingStats();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::timingEnableChanged(int state)
|
||||||
|
{
|
||||||
|
setFrameTimingEnable( state != Qt::Unchecked );
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
void FrameTimingDialog_t::resetTimingClicked(void)
|
||||||
|
{
|
||||||
|
resetFrameTiming();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------
|
|
@ -0,0 +1,55 @@
|
||||||
|
// FrameTimingStats.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QFrame>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QTreeWidget>
|
||||||
|
#include <QTreeWidgetItem>
|
||||||
|
|
||||||
|
#include "Qt/main.h"
|
||||||
|
|
||||||
|
class FrameTimingDialog_t : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
FrameTimingDialog_t(QWidget *parent = 0);
|
||||||
|
~FrameTimingDialog_t(void);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
|
|
||||||
|
QTimer *updateTimer;
|
||||||
|
QCheckBox *timingEnable;
|
||||||
|
QTreeWidgetItem *frameTimeAbs;
|
||||||
|
QTreeWidgetItem *frameTimeDel;
|
||||||
|
QTreeWidgetItem *frameTimeWork;
|
||||||
|
QTreeWidgetItem *frameTimeWorkPct;
|
||||||
|
QTreeWidgetItem *frameTimeIdle;
|
||||||
|
QTreeWidgetItem *frameTimeIdlePct;
|
||||||
|
QTreeWidgetItem *frameLateCount;
|
||||||
|
|
||||||
|
QTreeWidget *tree;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateTimingStats(void);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void closeWindow(void);
|
||||||
|
private slots:
|
||||||
|
void updatePeriodic(void);
|
||||||
|
void resetTimingClicked(void);
|
||||||
|
void timingEnableChanged(int state);
|
||||||
|
|
||||||
|
};
|
|
@ -238,7 +238,7 @@ InputConfDialog_t::~InputConfDialog_t(void)
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void InputConfDialog_t::closeEvent(QCloseEvent *event)
|
void InputConfDialog_t::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
printf("Hot Key Close Window Event\n");
|
printf("Input Config Close Window Event\n");
|
||||||
done(0);
|
done(0);
|
||||||
deleteLater();
|
deleteLater();
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
|
@ -19,8 +19,12 @@ static const double Normal = 1.0; // 1x speed (around 60 fps on NTSC)
|
||||||
static uint32 frameLateCounter = 0;
|
static uint32 frameLateCounter = 0;
|
||||||
static double Lasttime=0, Nexttime=0, Latetime=0;
|
static double Lasttime=0, Nexttime=0, Latetime=0;
|
||||||
static double desired_frametime = (1.0 / 60.099823);
|
static double desired_frametime = (1.0 / 60.099823);
|
||||||
static double frameDeltaMin = 99999.0;
|
static double frameDeltaCur = 0.0;
|
||||||
|
static double frameDeltaMin = 1.0;
|
||||||
static double frameDeltaMax = 0.0;
|
static double frameDeltaMax = 0.0;
|
||||||
|
static double frameIdleCur = 0.0;
|
||||||
|
static double frameIdleMin = 1.0;
|
||||||
|
static double frameIdleMax = 0.0;
|
||||||
static bool keepFrameTimeStats = false;
|
static bool keepFrameTimeStats = false;
|
||||||
static int InFrame = 0;
|
static int InFrame = 0;
|
||||||
double g_fpsScale = Normal; // used by sdl.cpp
|
double g_fpsScale = Normal; // used by sdl.cpp
|
||||||
|
@ -87,7 +91,7 @@ static void setTimer( double hz )
|
||||||
|
|
||||||
Lasttime = getHighPrecTimeStamp();
|
Lasttime = getHighPrecTimeStamp();
|
||||||
Nexttime = Lasttime + desired_frametime;
|
Nexttime = Lasttime + desired_frametime;
|
||||||
Latetime = Nexttime + desired_frametime;
|
Latetime = Nexttime + (desired_frametime*0.50);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -110,6 +114,61 @@ int setTimingMode( int mode )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setFrameTimingEnable( bool enable )
|
||||||
|
{
|
||||||
|
keepFrameTimeStats = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getFrameTimingStats( struct frameTimingStat_t *stats )
|
||||||
|
{
|
||||||
|
stats->enabled = keepFrameTimeStats;
|
||||||
|
stats->lateCount = frameLateCounter;
|
||||||
|
|
||||||
|
stats->frameTimeAbs.tgt = desired_frametime;
|
||||||
|
stats->frameTimeAbs.cur = frameDeltaCur;
|
||||||
|
stats->frameTimeAbs.min = frameDeltaMin;
|
||||||
|
stats->frameTimeAbs.max = frameDeltaMax;
|
||||||
|
|
||||||
|
stats->frameTimeDel.tgt = 0.0;
|
||||||
|
stats->frameTimeDel.cur = frameDeltaCur - desired_frametime;
|
||||||
|
stats->frameTimeDel.min = frameDeltaMin - desired_frametime;
|
||||||
|
stats->frameTimeDel.max = frameDeltaMax - desired_frametime;
|
||||||
|
|
||||||
|
stats->frameTimeIdle.tgt = desired_frametime * 0.50;
|
||||||
|
stats->frameTimeIdle.cur = frameIdleCur;
|
||||||
|
stats->frameTimeIdle.min = frameIdleMin;
|
||||||
|
stats->frameTimeIdle.max = frameIdleMax;
|
||||||
|
|
||||||
|
stats->frameTimeWork.tgt = desired_frametime - stats->frameTimeIdle.tgt;
|
||||||
|
stats->frameTimeWork.cur = desired_frametime - frameIdleCur;
|
||||||
|
stats->frameTimeWork.min = desired_frametime - frameIdleMax;
|
||||||
|
stats->frameTimeWork.max = desired_frametime - frameIdleMin;
|
||||||
|
|
||||||
|
if ( stats->frameTimeWork.cur < 0 )
|
||||||
|
{
|
||||||
|
stats->frameTimeWork.cur = 0;
|
||||||
|
}
|
||||||
|
if ( stats->frameTimeWork.min < 0 )
|
||||||
|
{
|
||||||
|
stats->frameTimeWork.min = 0;
|
||||||
|
}
|
||||||
|
if ( stats->frameTimeWork.max < 0 )
|
||||||
|
{
|
||||||
|
stats->frameTimeWork.max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetFrameTiming(void)
|
||||||
|
{
|
||||||
|
frameLateCounter = 0;
|
||||||
|
frameDeltaMax = 0.0;
|
||||||
|
frameDeltaMin = 1.0;
|
||||||
|
frameIdleMax = 0.0;
|
||||||
|
frameIdleMin = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
/* LOGMUL = exp(log(2) / 3)
|
/* LOGMUL = exp(log(2) / 3)
|
||||||
*
|
*
|
||||||
* This gives us a value such that if we do x*=LOGMUL three times,
|
* This gives us a value such that if we do x*=LOGMUL three times,
|
||||||
|
@ -177,23 +236,24 @@ SpeedThrottle(void)
|
||||||
return 0; /* Done waiting */
|
return 0; /* Done waiting */
|
||||||
}
|
}
|
||||||
double time_left;
|
double time_left;
|
||||||
double cur_time;
|
double cur_time, idleStart;
|
||||||
double frame_time = desired_frametime;
|
double frame_time = desired_frametime;
|
||||||
|
double halfFrame = 0.500 * frame_time;
|
||||||
double quarterFrame = 0.250 * frame_time;
|
double quarterFrame = 0.250 * frame_time;
|
||||||
|
|
||||||
cur_time = getHighPrecTimeStamp();
|
idleStart = cur_time = getHighPrecTimeStamp();
|
||||||
|
|
||||||
if (Lasttime < 1.0)
|
if (Lasttime < 1.0)
|
||||||
{
|
{
|
||||||
Lasttime = cur_time;
|
Lasttime = cur_time;
|
||||||
Latetime = Lasttime + frame_time;
|
Latetime = Lasttime + 2.0*frame_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InFrame)
|
if (!InFrame)
|
||||||
{
|
{
|
||||||
InFrame = 1;
|
InFrame = 1;
|
||||||
Nexttime = Lasttime + frame_time;
|
Nexttime = Lasttime + frame_time;
|
||||||
Latetime = Nexttime + frame_time;
|
Latetime = Nexttime + halfFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_time >= Nexttime)
|
if (cur_time >= Nexttime)
|
||||||
|
@ -266,30 +326,40 @@ SpeedThrottle(void)
|
||||||
{
|
{
|
||||||
if ( keepFrameTimeStats )
|
if ( keepFrameTimeStats )
|
||||||
{
|
{
|
||||||
double frameDelta;
|
|
||||||
|
|
||||||
frameDelta = (cur_time - Lasttime);
|
frameDeltaCur = (cur_time - Lasttime);
|
||||||
|
|
||||||
if ( frameDelta < frameDeltaMin )
|
if ( frameDeltaCur < frameDeltaMin )
|
||||||
{
|
{
|
||||||
frameDeltaMin = frameDelta;
|
frameDeltaMin = frameDeltaCur;
|
||||||
}
|
}
|
||||||
if ( frameDelta > frameDeltaMax )
|
if ( frameDeltaCur > frameDeltaMax )
|
||||||
{
|
{
|
||||||
frameDeltaMax = frameDelta;
|
frameDeltaMax = frameDeltaCur;
|
||||||
|
}
|
||||||
|
|
||||||
|
frameIdleCur = (cur_time - idleStart);
|
||||||
|
|
||||||
|
if ( frameIdleCur < frameIdleMin )
|
||||||
|
{
|
||||||
|
frameIdleMin = frameIdleCur;
|
||||||
|
}
|
||||||
|
if ( frameIdleCur > frameIdleMax )
|
||||||
|
{
|
||||||
|
frameIdleMax = frameIdleCur;
|
||||||
}
|
}
|
||||||
//printf("Frame Delta: %f us min:%f max:%f \n", frameDelta * 1e6, frameDeltaMin * 1e6, frameDeltaMax * 1e6 );
|
//printf("Frame Delta: %f us min:%f max:%f \n", frameDelta * 1e6, frameDeltaMin * 1e6, frameDeltaMax * 1e6 );
|
||||||
//printf("Frame Sleep Time: %f Target Error: %f us\n", time_left * 1e6, (cur_time - Nexttime) * 1e6 );
|
//printf("Frame Sleep Time: %f Target Error: %f us\n", time_left * 1e6, (cur_time - Nexttime) * 1e6 );
|
||||||
}
|
}
|
||||||
Lasttime = Nexttime;
|
Lasttime = Nexttime;
|
||||||
Nexttime = Lasttime + frame_time;
|
Nexttime = Lasttime + frame_time;
|
||||||
Latetime = Nexttime + frame_time;
|
Latetime = Nexttime + halfFrame;
|
||||||
|
|
||||||
if ( cur_time >= Nexttime )
|
if ( cur_time >= Nexttime )
|
||||||
{
|
{
|
||||||
Lasttime = cur_time;
|
Lasttime = cur_time;
|
||||||
Nexttime = Lasttime + frame_time;
|
Nexttime = Lasttime + frame_time;
|
||||||
Latetime = Nexttime + frame_time;
|
Latetime = Nexttime + halfFrame;
|
||||||
}
|
}
|
||||||
return 0; /* Done waiting */
|
return 0; /* Done waiting */
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,3 +3,44 @@ int SpeedThrottle(void);
|
||||||
void RefreshThrottleFPS(void);
|
void RefreshThrottleFPS(void);
|
||||||
int getTimingMode(void);
|
int getTimingMode(void);
|
||||||
int setTimingMode(int mode);
|
int setTimingMode(int mode);
|
||||||
|
|
||||||
|
|
||||||
|
struct frameTimingStat_t
|
||||||
|
{
|
||||||
|
|
||||||
|
struct {
|
||||||
|
double tgt;
|
||||||
|
double cur;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
} frameTimeAbs;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
double tgt;
|
||||||
|
double cur;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
} frameTimeDel;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
double tgt;
|
||||||
|
double cur;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
} frameTimeWork;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
double tgt;
|
||||||
|
double cur;
|
||||||
|
double min;
|
||||||
|
double max;
|
||||||
|
} frameTimeIdle;
|
||||||
|
|
||||||
|
unsigned int lateCount;
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
void resetFrameTiming(void);
|
||||||
|
void setFrameTimingEnable( bool enable );
|
||||||
|
int getFrameTimingStats( struct frameTimingStat_t *stats );
|
||||||
|
|
Loading…
Reference in New Issue