Factor out performance timers into separate files

This should make graphics.cpp somewhat easier to navigate/read.
GL_EXT_timer_query is also made optional, and if it's not present
dummy functions will be called instead.
This commit is contained in:
Jonas Kulla 2013-09-27 16:54:01 +02:00
parent 4ff563725b
commit 307eeb732d
4 changed files with 237 additions and 200 deletions

View File

@ -60,7 +60,8 @@ HEADERS += \
src/gl-util.h \
src/util.h \
src/config.h \
src/tileatlas.h
src/tileatlas.h \
src/perftimer.h
SOURCES += \
src/main.cpp \
@ -87,7 +88,8 @@ SOURCES += \
src/debuglogger.cpp \
src/etc.cpp \
src/config.cpp \
src/tileatlas.cpp
src/tileatlas.cpp \
src/perftimer.cpp
EMBED = shader/transSimple.frag \
shader/trans.frag \

View File

@ -33,187 +33,11 @@
#include "bitmap.h"
#include "etc-internal.h"
#include "binding.h"
#include "perftimer.h"
#include "SDL2/SDL_video.h"
#include "SDL2/SDL_timer.h"
#include "stdint.h"
#include "SFML/System/Clock.hpp"
struct TimerQuery
{
GLuint query;
static bool queryActive;
bool thisQueryActive;
TimerQuery()
: thisQueryActive(false)
{
glGenQueries(1, &query);
}
void begin()
{
if (queryActive)
return;
if (thisQueryActive)
return;
glBeginQuery(GL_TIME_ELAPSED, query);
queryActive = true;
thisQueryActive = true;
}
void end()
{
if (!thisQueryActive)
return;
glEndQuery(GL_TIME_ELAPSED);
queryActive = false;
thisQueryActive = false;
}
bool getResult(GLuint64 *result)
{
if (thisQueryActive)
return false;
GLint isReady = GL_FALSE;
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
if (isReady != GL_TRUE)
{
// qDebug() << "TimerQuery result not ready";
return false;
}
glGetQueryObjectui64v(query, GL_QUERY_RESULT, result);
if (glGetError() == GL_INVALID_OPERATION)
{
qDebug() << "Something went wrong with getting TimerQuery results";
return false;
}
return true;
}
GLuint64 getResultSync()
{
if (thisQueryActive)
return 0;
GLuint64 result;
GLint isReady = GL_FALSE;
while (isReady == GL_FALSE)
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
glGetQueryObjectui64v(query, GL_QUERY_RESULT, &result);
return result;
}
~TimerQuery()
{
if (thisQueryActive)
end();
glDeleteQueries(1, &query);
}
};
bool TimerQuery::queryActive = false;
struct GPUTimer
{
TimerQuery queries[2];
const int iter;
uchar ind;
uint64_t acc;
int32_t counter;
bool first;
GPUTimer(int iter)
: iter(iter),
ind(0),
acc(0),
counter(0),
first(true)
{}
void startTiming()
{
queries[ind].begin();
}
void endTiming()
{
queries[ind].end();
if (first)
{
first = false;
return;
}
swapInd();
GLuint64 result;
if (!queries[ind].getResult(&result))
return;
acc += result;
if (++counter < iter)
return;
qDebug() << " Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms";
acc = counter = 0;
}
void swapInd()
{
ind = ind ? 0 : 1;
}
};
struct CPUTimer
{
const int iter;
uint64_t acc;
int32_t counter;
sf::Clock clock;
CPUTimer(int iter)
: iter(iter),
acc(0),
counter(0)
{
}
void startTiming()
{
clock.restart();
}
void endTiming()
{
acc += clock.getElapsedTime().asMicroseconds();
if (++counter < iter)
return;
qDebug() << "Avg. CPU time:" << ((double) acc / (iter * 1000)) << "ms";
acc = counter = 0;
}
};
struct PingPong
{
TEXFBO rt[2];
@ -436,19 +260,6 @@ struct FPSLimiter
}
};
struct Timer
{
uint64_t lastTicks;
uint64_t acc;
int counter;
Timer()
: lastTicks(SDL_GetPerformanceCounter()),
acc(0),
counter(0)
{}
};
struct GraphicsPrivate
{
/* Screen resolution, ie. the resolution at which
@ -477,8 +288,8 @@ struct GraphicsPrivate
FPSLimiter fpsLimiter;
GPUTimer gpuTimer;
CPUTimer cpuTimer;
PerfTimer *gpuTimer;
PerfTimer *cpuTimer;
bool frozen;
TEXFBO frozenScene;
@ -495,10 +306,11 @@ struct GraphicsPrivate
frameCount(0),
brightness(255),
fpsLimiter(frameRate),
gpuTimer(frameRate),
cpuTimer(frameRate),
frozen(false)
{
gpuTimer = createGPUTimer(frameRate);
cpuTimer = createCPUTimer(frameRate);
TEXFBO::init(frozenScene);
TEXFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
TEXFBO::linkFBO(frozenScene);
@ -517,6 +329,9 @@ struct GraphicsPrivate
~GraphicsPrivate()
{
delete gpuTimer;
delete cpuTimer;
TEXFBO::fini(frozenScene);
TEXFBO::fini(currentScene);
@ -627,8 +442,8 @@ void Graphics::update()
{
gState->checkShutdown();
// p->cpuTimer.endTiming();
// p->gpuTimer.startTiming();
// p->cpuTimer->endTiming();
// p->gpuTimer->startTiming();
if (p->frozen)
return;
@ -636,8 +451,8 @@ void Graphics::update()
p->checkResize();
p->redrawScreen();
// p->gpuTimer.endTiming();
// p->cpuTimer.startTiming();
// p->gpuTimer->endTiming();
// p->cpuTimer->startTiming();
}
void Graphics::wait(int duration)

202
src/perftimer.cpp Normal file
View File

@ -0,0 +1,202 @@
#include "perftimer.h"
#include "SDL2/SDL_timer.h"
#include "GL/glew.h"
#include <QDebug>
struct TimerQuery
{
GLuint query;
static bool queryActive;
bool thisQueryActive;
TimerQuery()
: thisQueryActive(false)
{
glGenQueries(1, &query);
}
void begin()
{
if (queryActive)
return;
if (thisQueryActive)
return;
glBeginQuery(GL_TIME_ELAPSED, query);
queryActive = true;
thisQueryActive = true;
}
void end()
{
if (!thisQueryActive)
return;
glEndQuery(GL_TIME_ELAPSED);
queryActive = false;
thisQueryActive = false;
}
bool getResult(GLuint64 *result)
{
if (thisQueryActive)
return false;
GLint isReady = GL_FALSE;
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
if (isReady != GL_TRUE)
return false;
glGetQueryObjectui64v(query, GL_QUERY_RESULT, result);
if (glGetError() == GL_INVALID_OPERATION)
return false;
return true;
}
GLuint64 getResultSync()
{
if (thisQueryActive)
return 0;
GLuint64 result;
GLint isReady = GL_FALSE;
while (isReady == GL_FALSE)
glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
glGetQueryObjectui64v(query, GL_QUERY_RESULT, &result);
return result;
}
~TimerQuery()
{
if (thisQueryActive)
end();
glDeleteQueries(1, &query);
}
};
bool TimerQuery::queryActive = false;
struct GPUTimerGLQuery : public PerfTimer
{
TimerQuery queries[2];
const int iter;
uint8_t ind;
uint64_t acc;
int32_t counter;
bool first;
GPUTimerGLQuery(int iter)
: iter(iter),
ind(0),
acc(0),
counter(0),
first(true)
{}
void startTiming()
{
queries[ind].begin();
}
void endTiming()
{
queries[ind].end();
if (first)
{
first = false;
return;
}
swapInd();
GLuint64 result;
if (!queries[ind].getResult(&result))
return;
acc += result;
if (++counter < iter)
return;
qDebug() << " "
"Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms";
acc = counter = 0;
}
void swapInd()
{
ind = ind ? 0 : 1;
}
};
struct GPUTimerDummy : public PerfTimer
{
void startTiming() {}
void endTiming() {}
};
struct CPUTimer : public PerfTimer
{
const int iter;
uint64_t acc;
int32_t counter;
Uint64 ticks;
Uint64 perfFreq;
CPUTimer(int iter)
: iter(iter),
acc(0),
counter(0),
ticks(0)
{
perfFreq = SDL_GetPerformanceFrequency();
}
void startTiming()
{
ticks = SDL_GetPerformanceCounter();
}
void endTiming()
{
acc += SDL_GetPerformanceCounter() - ticks;
if (++counter < iter)
return;
qDebug() << "Avg. CPU time:" << ((double) acc / (iter * (perfFreq / 1000))) << "ms";
acc = counter = 0;
}
};
PerfTimer *createCPUTimer(int iter)
{
return new CPUTimer(iter);
}
PerfTimer *createGPUTimer(int iter)
{
if (GLEW_EXT_timer_query)
{
return new GPUTimerGLQuery(iter);
}
else
{
qDebug() << "GL_EXT_timer_query not present: cannot measure GPU performance";
return new GPUTimerDummy();
}
}

18
src/perftimer.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef PERFTIMER_H
#define PERFTIMER_H
struct PerfTimer
{
virtual ~PerfTimer() {}
virtual void startTiming() = 0;
virtual void endTiming() = 0;
};
/* Create timers that run on either CPU or GPU.
* After 'iter' pairs of startTiming()/endTiming(),
* they will calculate the average measurement and
* print it to the console */
PerfTimer *createGPUTimer(int iter);
PerfTimer *createCPUTimer(int iter);
#endif // PERFTIMER_H