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/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 \
|
||||
|
|
211
src/graphics.cpp
211
src/graphics.cpp
|
@ -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)
|
||||
|
|
|
@ -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