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:
parent
4ff563725b
commit
307eeb732d
6
mkxp.pro
6
mkxp.pro
|
@ -60,7 +60,8 @@ HEADERS += \
|
||||||
src/gl-util.h \
|
src/gl-util.h \
|
||||||
src/util.h \
|
src/util.h \
|
||||||
src/config.h \
|
src/config.h \
|
||||||
src/tileatlas.h
|
src/tileatlas.h \
|
||||||
|
src/perftimer.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
|
@ -87,7 +88,8 @@ SOURCES += \
|
||||||
src/debuglogger.cpp \
|
src/debuglogger.cpp \
|
||||||
src/etc.cpp \
|
src/etc.cpp \
|
||||||
src/config.cpp \
|
src/config.cpp \
|
||||||
src/tileatlas.cpp
|
src/tileatlas.cpp \
|
||||||
|
src/perftimer.cpp
|
||||||
|
|
||||||
EMBED = shader/transSimple.frag \
|
EMBED = shader/transSimple.frag \
|
||||||
shader/trans.frag \
|
shader/trans.frag \
|
||||||
|
|
211
src/graphics.cpp
211
src/graphics.cpp
|
@ -33,187 +33,11 @@
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "etc-internal.h"
|
#include "etc-internal.h"
|
||||||
#include "binding.h"
|
#include "binding.h"
|
||||||
|
#include "perftimer.h"
|
||||||
|
|
||||||
#include "SDL2/SDL_video.h"
|
#include "SDL2/SDL_video.h"
|
||||||
#include "SDL2/SDL_timer.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
|
struct PingPong
|
||||||
{
|
{
|
||||||
TEXFBO rt[2];
|
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
|
struct GraphicsPrivate
|
||||||
{
|
{
|
||||||
/* Screen resolution, ie. the resolution at which
|
/* Screen resolution, ie. the resolution at which
|
||||||
|
@ -477,8 +288,8 @@ struct GraphicsPrivate
|
||||||
|
|
||||||
FPSLimiter fpsLimiter;
|
FPSLimiter fpsLimiter;
|
||||||
|
|
||||||
GPUTimer gpuTimer;
|
PerfTimer *gpuTimer;
|
||||||
CPUTimer cpuTimer;
|
PerfTimer *cpuTimer;
|
||||||
|
|
||||||
bool frozen;
|
bool frozen;
|
||||||
TEXFBO frozenScene;
|
TEXFBO frozenScene;
|
||||||
|
@ -495,10 +306,11 @@ struct GraphicsPrivate
|
||||||
frameCount(0),
|
frameCount(0),
|
||||||
brightness(255),
|
brightness(255),
|
||||||
fpsLimiter(frameRate),
|
fpsLimiter(frameRate),
|
||||||
gpuTimer(frameRate),
|
|
||||||
cpuTimer(frameRate),
|
|
||||||
frozen(false)
|
frozen(false)
|
||||||
{
|
{
|
||||||
|
gpuTimer = createGPUTimer(frameRate);
|
||||||
|
cpuTimer = createCPUTimer(frameRate);
|
||||||
|
|
||||||
TEXFBO::init(frozenScene);
|
TEXFBO::init(frozenScene);
|
||||||
TEXFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
|
TEXFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
|
||||||
TEXFBO::linkFBO(frozenScene);
|
TEXFBO::linkFBO(frozenScene);
|
||||||
|
@ -517,6 +329,9 @@ struct GraphicsPrivate
|
||||||
|
|
||||||
~GraphicsPrivate()
|
~GraphicsPrivate()
|
||||||
{
|
{
|
||||||
|
delete gpuTimer;
|
||||||
|
delete cpuTimer;
|
||||||
|
|
||||||
TEXFBO::fini(frozenScene);
|
TEXFBO::fini(frozenScene);
|
||||||
TEXFBO::fini(currentScene);
|
TEXFBO::fini(currentScene);
|
||||||
|
|
||||||
|
@ -627,8 +442,8 @@ void Graphics::update()
|
||||||
{
|
{
|
||||||
gState->checkShutdown();
|
gState->checkShutdown();
|
||||||
|
|
||||||
// p->cpuTimer.endTiming();
|
// p->cpuTimer->endTiming();
|
||||||
// p->gpuTimer.startTiming();
|
// p->gpuTimer->startTiming();
|
||||||
|
|
||||||
if (p->frozen)
|
if (p->frozen)
|
||||||
return;
|
return;
|
||||||
|
@ -636,8 +451,8 @@ void Graphics::update()
|
||||||
p->checkResize();
|
p->checkResize();
|
||||||
p->redrawScreen();
|
p->redrawScreen();
|
||||||
|
|
||||||
// p->gpuTimer.endTiming();
|
// p->gpuTimer->endTiming();
|
||||||
// p->cpuTimer.startTiming();
|
// p->cpuTimer->startTiming();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::wait(int duration)
|
void Graphics::wait(int duration)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue