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
					
				
					 4 changed files with 237 additions and 200 deletions
				
			
		
							
								
								
									
										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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										202
									
								
								src/perftimer.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/perftimer.cpp
									
										
									
									
									
										Normal 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
									
								
							
							
						
						
									
										18
									
								
								src/perftimer.h
									
										
									
									
									
										Normal 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
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue