From 307eeb732d29b3fc90ee0a3c3f02c84fee25eb3b Mon Sep 17 00:00:00 2001 From: Jonas Kulla Date: Fri, 27 Sep 2013 16:54:01 +0200 Subject: [PATCH] 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. --- mkxp.pro | 6 +- src/graphics.cpp | 211 +++------------------------------------------- src/perftimer.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++ src/perftimer.h | 18 ++++ 4 files changed, 237 insertions(+), 200 deletions(-) create mode 100644 src/perftimer.cpp create mode 100644 src/perftimer.h diff --git a/mkxp.pro b/mkxp.pro index 765b05a..906acde 100644 --- a/mkxp.pro +++ b/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 \ diff --git a/src/graphics.cpp b/src/graphics.cpp index 9aa961e..2c22a82 100644 --- a/src/graphics.cpp +++ b/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) diff --git a/src/perftimer.cpp b/src/perftimer.cpp new file mode 100644 index 0000000..364fb42 --- /dev/null +++ b/src/perftimer.cpp @@ -0,0 +1,202 @@ +#include "perftimer.h" + +#include "SDL2/SDL_timer.h" +#include "GL/glew.h" + +#include + +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(); + } +} diff --git a/src/perftimer.h b/src/perftimer.h new file mode 100644 index 0000000..2208e3e --- /dev/null +++ b/src/perftimer.h @@ -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