Explorar el Código

Adding GPU profiling in the renderer

Panagiotis Christopoulos Charitos hace 14 años
padre
commit
c96b7b20b4

+ 51 - 0
src/GfxApi/GlStateMachine.cpp

@@ -64,4 +64,55 @@ void GlStateMachine::sync()
 		flags[*flagEnum] = glIsEnabled(*flagEnum);
 		++flagEnum;
 	}
+
+	// viewport
+	GLint viewport[4];
+	glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+	viewportX = viewport[0];
+	viewportY = viewport[1];
+	viewportW = viewport[2];
+	viewportH = viewport[3];
+}
+
+
+//==============================================================================
+// setViewport                                                                 =
+//==============================================================================
+void GlStateMachine::setViewport(uint x, uint y, uint w, uint h)
+{
+	if(x != (uint)viewportX || y != (uint)viewportY ||
+		w != (uint)viewportW || h != (uint)viewportH)
+	{
+		glViewport(x, y, w, h);
+		viewportX = x;
+		viewportY = y;
+		viewportW = w;
+		viewportH = h;
+	}
+}
+
+
+//==============================================================================
+// useShaderProg                                                               =
+//==============================================================================
+void GlStateMachine::useShaderProg(GLuint id)
+{
+	ASSERT(getCurrentProgramGlId() == sProgGlId);
+
+	if(sProgGlId != id)
+	{
+		glUseProgram(id);
+		sProgGlId = id;
+	}
+}
+
+
+//==============================================================================
+// getCurrentProgramGlId                                                       =
+//==============================================================================
+GLuint GlStateMachine::getCurrentProgramGlId()
+{
+	int i;
+	glGetIntegerv(GL_CURRENT_PROGRAM, &i);
+	return i;
 }

+ 8 - 25
src/GfxApi/GlStateMachine.h

@@ -24,43 +24,26 @@ class GlStateMachine
 		bool isEnabled(GLenum flag);
 
 		void useShaderProg(GLuint id);
+
+		void setViewport(uint x, uint y, uint w, uint h);
 		/// @}
 
 	private:
 		/// @name The GL state
 		/// @{
-		GLuint sProgGlId;
+		GLuint sProgGlId; ///< Last used SProg ID
 
 		boost::unordered_map<GLenum, bool> flags;
 		static GLenum flagEnums[];
+
+		GLint viewportX;
+		GLint viewportY;
+		GLsizei viewportW;
+		GLsizei viewportH;
 		/// @}
 
 		static GLuint getCurrentProgramGlId();
 };
 
 
-//==============================================================================
-// Inlines                                                                     =
-//==============================================================================
-
-inline void GlStateMachine::useShaderProg(GLuint id)
-{
-	ASSERT(getCurrentProgramGlId() == sProgGlId);
-
-	if(sProgGlId != id)
-	{
-		glUseProgram(id);
-		sProgGlId = id;
-	}
-}
-
-
-inline GLuint GlStateMachine::getCurrentProgramGlId()
-{
-	int i;
-	glGetIntegerv(GL_CURRENT_PROGRAM, &i);
-	return i;
-}
-
-
 #endif

+ 62 - 0
src/GfxApi/TimeQuery.cpp

@@ -0,0 +1,62 @@
+#include "TimeQuery.h"
+#include "Util/Assert.h"
+
+
+//==============================================================================
+// Constructor                                                                 =
+//==============================================================================
+TimeQuery::TimeQuery()
+{
+	glGenQueries(2, &glIds[0]);
+	state = S_CREATED;
+}
+
+
+//==============================================================================
+// Destructor                                                                  =
+//==============================================================================
+TimeQuery::~TimeQuery()
+{
+	glDeleteQueries(2, &glIds[0]);
+}
+
+
+//==============================================================================
+// begin                                                                       =
+//==============================================================================
+void TimeQuery::begin()
+{
+	ASSERT(state == S_CREATED || state == S_ENDED);
+
+	glQueryCounter(GL_TIMESTAMP, glIds[0]);
+
+	state = S_STARTED;
+}
+
+
+//==============================================================================
+// end                                                                         =
+//==============================================================================
+double TimeQuery::end()
+{
+	ASSERT(state == S_STARTED);
+
+	glQueryCounter(GL_TIMESTAMP, glIds[1]);
+
+	// Wait
+	GLint done = 0;
+	while(!done)
+	{
+		glGetQueryObjectiv(glIds[1], GL_QUERY_RESULT_AVAILABLE, &done);
+	}
+
+	// Get elapsed time
+	GLuint64 timerStart, timerEnd;
+
+	glGetQueryObjectui64v(glIds[0], GL_QUERY_RESULT, &timerStart);
+	glGetQueryObjectui64v(glIds[1], GL_QUERY_RESULT, &timerEnd);
+
+	state = S_ENDED;
+
+	return (timerEnd - timerStart) / 1000000000.0;
+}

+ 39 - 0
src/GfxApi/TimeQuery.h

@@ -0,0 +1,39 @@
+#ifndef TIME_QUERY_H
+#define TIME_QUERY_H
+
+#include <GL/glew.h>
+#include <boost/array.hpp>
+
+
+/// Used to profile the GPU. It gets the time elapsed from when the begin() is
+/// called until the endAndGetTimeElapsed() method. The query causes
+/// synchronization issues because it waits for the GL commands to finish. For
+/// that it is slow and its not recommended for use in production code.
+class TimeQuery
+{
+	public:
+		TimeQuery();
+		~TimeQuery();
+
+		/// Begin
+		void begin();
+
+		/// End and get elapsed time. In seconds
+		double end();
+
+	private:
+		/// The query state
+		enum State
+		{
+			S_CREATED,
+			S_STARTED,
+			S_ENDED
+		};
+
+		boost::array<GLuint, 2> glIds; ///< GL IDs
+		State state; ///< The query state. It saves us from improper use of the
+		             ///< the class
+};
+
+
+#endif

+ 1 - 0
src/Physics/Character.cpp

@@ -7,6 +7,7 @@
 #include "MasterContainer.h"
 #include "MotionState.h"
 #include "RigidBody.h"
+#include "MasterContainer.h"
 
 
 namespace Phys {

+ 5 - 6
src/Physics/Character.h

@@ -1,7 +1,6 @@
 #ifndef PHYS_CHARACTER_H
 #define PHYS_CHARACTER_H
 
-#include "MasterContainer.h"
 #include "Math/Math.h"
 #include "Core/Object.h"
 
@@ -11,15 +10,15 @@ class btConvexShape;
 class btKinematicCharacterController;
 class btGhostPairCallback;
 class SceneNode;
-namespace Phys {
-class MasterContainer;
-class MotionState;
-}
 
 
 namespace Phys {
 
 
+class MasterContainer;
+class MotionState;
+
+
 /// Its basically a wrapper around bullet character
 class Character
 {
@@ -40,7 +39,7 @@ class Character
 			Initializer();
 		};
 
-		Character(MasterContainer& masterContainer_, const Initializer& init);
+		Character(MasterContainer& masterContainer, const Initializer& init);
 		~Character();
 		void rotate(float angle);
 		void moveForward(float distance);

+ 2 - 1
src/Renderer/Dbg.cpp

@@ -265,7 +265,8 @@ void Dbg::run()
 	sProg->bind();
 
 	// OGL stuff
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, true);
 	GlStateMachineSingleton::getInstance().enable(GL_BLEND, false);
 

+ 2 - 1
src/Renderer/Ez.cpp

@@ -58,7 +58,8 @@ void Ez::run()
 
 	fbo.bind();
 
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 
 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, true);

+ 1 - 1
src/Renderer/Hdr.cpp

@@ -96,7 +96,7 @@ void Hdr::run()
 
 	int w = renderingQuality * r.getWidth();
 	int h = renderingQuality * r.getHeight();
-	Renderer::setViewport(0, 0, w, h);
+	GlStateMachineSingleton::getInstance().setViewport(0, 0, w, h);
 
 	GlStateMachineSingleton::getInstance().enable(GL_BLEND, false);
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);

+ 4 - 2
src/Renderer/Is.cpp

@@ -220,7 +220,8 @@ void Is::spotLightPass(const SpotLight& light)
 		GlStateMachineSingleton::getInstance().enable(GL_BLEND, true);
 		glBlendFunc(GL_ONE, GL_ONE);
 		GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);
-		Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+		GlStateMachineSingleton::getInstance().setViewport(0, 0,
+			r.getWidth(), r.getHeight());
 	}
 
 	// stencil optimization
@@ -308,7 +309,8 @@ void Is::copyDepth()
 void Is::run()
 {
 	// OGL stuff
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 
 	// Copy
 	if(r.getFramesNum() % 2 == 0)

+ 13 - 2
src/Renderer/MainRenderer.cpp

@@ -98,14 +98,25 @@ void MainRenderer::initGl()
 void MainRenderer::render(Camera& cam_)
 {
 	Renderer::render(cam_);
-	dbg.run();
+
+	if(isStageProfilingEnabled())
+	{
+		dbgTq.begin();
+		dbg.run();
+		dbgTime = dbgTq.end();
+	}
+	else
+	{
+		dbg.run();
+	}
 
 	//
 	// Render the PPS FAI to the framebuffer
 	//
 	glBindFramebuffer(GL_FRAMEBUFFER, 0); // Bind the window framebuffer
 
-	setViewport(0, 0, AppSingleton::getInstance().getWindowWidth(),
+	GlStateMachineSingleton::getInstance().setViewport(
+		0, 0, AppSingleton::getInstance().getWindowWidth(),
 		AppSingleton::getInstance().getWindowHeight());
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);
 	GlStateMachineSingleton::getInstance().enable(GL_BLEND, false);

+ 7 - 0
src/Renderer/MainRenderer.h

@@ -22,6 +22,7 @@ class MainRenderer: public Renderer
 			getScreenshotJpegQuality, setScreenshotJpegQuality)
 		GETTER_R_BY_VAL(float, renderingQuality, getRenderingQuality)
 		GETTER_RW(Dbg, dbg, getDbg)
+		GETTER_R_BY_VAL(double, dbgTime, getDbgTime)
 		/// @}
 
 		/// The same as Renderer::init but with additional initialization.
@@ -44,6 +45,12 @@ class MainRenderer: public Renderer
 		Dbg dbg; ///< Debugging rendering stage. Only the main renderer has it
 		/// @}
 
+		/// @name Profiling stuff
+		/// @{
+		double dbgTime;
+		TimeQuery dbgTq;
+		/// @}
+
 		RsrcPtr<ShaderProg> sProg; ///< Final pass' shader program
 		int screenshotJpegQuality; ///< The quality of the JPEG screenshots.
 		                           ///< From 0 to 100

+ 2 - 1
src/Renderer/Ms.cpp

@@ -99,7 +99,8 @@ void Ms::run()
 		glClear(GL_DEPTH_BUFFER_BIT);
 	}
 
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 
 	//GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, true);
 	//app->getScene().skybox.Render(cam.getViewMatrix().getRotationPart());

+ 4 - 2
src/Renderer/Pps.cpp

@@ -122,7 +122,8 @@ void Pps::runPrePass()
 
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);
 	GlStateMachineSingleton::getInstance().enable(GL_BLEND, false);
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 
 	prePassSProg->bind();
 	prePassSProg->findUniVar("isFai")->set(r.getIs().getFai(), 0);
@@ -153,7 +154,8 @@ void Pps::runPostPass()
 
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);
 	GlStateMachineSingleton::getInstance().enable(GL_BLEND, false);
-	Renderer::setViewport(0, 0, r.getWidth(), r.getHeight());
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		r.getWidth(), r.getHeight());
 
 	postPassSProg->bind();
 	postPassSProg->findUniVar("ppsPrePassFai")->set(prePassFai, 0);

+ 30 - 5
src/Renderer/Renderer.cpp

@@ -84,11 +84,36 @@ void Renderer::render(Camera& cam_)
 
 	viewProjectionMat = cam->getProjectionMatrix() * cam->getViewMatrix();
 
-	ms.run();
-	is.run();
-	pps.runPrePass();
-	bs.run();
-	pps.runPostPass();
+	if(enableStageProfilingFlag)
+	{
+		msTq.begin();
+		ms.run();
+		msTime = msTq.end();
+
+		isTq.begin();
+		is.run();
+		isTime = isTq.end();
+
+		ppsTq.begin();
+		pps.runPrePass();
+		ppsTime = ppsTq.end();
+
+		bsTq.begin();
+		bs.run();
+		bsTime = bsTq.end();
+
+		ppsTq.begin();
+		pps.runPostPass();
+		ppsTime += ppsTq.end();
+	}
+	else
+	{
+		ms.run();
+		is.run();
+		pps.runPrePass();
+		bs.run();
+		pps.runPostPass();
+	}
 
 	++framesNum;
 }

+ 15 - 10
src/Renderer/Renderer.h

@@ -17,6 +17,7 @@
 #include "Drawers/SceneDrawer.h"
 #include "SkinsDeformer.h"
 #include "GfxApi/GlStateMachine.h"
+#include "GfxApi/TimeQuery.h"
 
 
 class Camera;
@@ -60,6 +61,12 @@ class Renderer
 		GETTER_R(Vec2, planes, getPlanes)
 		GETTER_R(Vec2, limitsOfNearPlane, getLimitsOfNearPlane)
 		GETTER_R(Vec2, limitsOfNearPlane2, getLimitsOfNearPlane2)
+		GETTER_R_BY_VAL(double, msTime, getMsTime)
+		GETTER_R_BY_VAL(double, isTime, getIsTime)
+		GETTER_R_BY_VAL(double, ppsTime, getPpsTime)
+		GETTER_R_BY_VAL(double, bsTime, getBsTime)
+		GETTER_SETTER_BY_VAL(bool, enableStageProfilingFlag,
+			isStageProfilingEnabled, setEnableStageProfiling)
 		/// @}
 
 		/// Init the renderer given an initialization class
@@ -80,9 +87,6 @@ class Renderer
 			const Mat4& modelViewMat, const Mat4& projectionMat,
 			const int view[4]);
 
-		/// OpenGL wrapper
-		static void setViewport(uint x, uint y, uint w, uint h);
-
 		/// Draws a quad. Actually it draws 2 triangles because OpenGL will no
 		/// longer support quads
 		void drawQuad();
@@ -97,7 +101,7 @@ class Renderer
 		/// fragment shader from:
 		/// @code z = (- zFar * zNear) / (zFar - depth * (zFar - zNear))
 		/// @endcode
-		/// The above can be optimized and this method actually precalculates a
+		/// The above can be optimized and this method actually pre-calculates a
 		/// few things in order to lift a few calculations from the fragment
 		/// shader. So the z is:
 		/// @code z =  -planes.y / (planes.x + depth) @endcode
@@ -119,6 +123,13 @@ class Renderer
 		Bs bs; ///< Blending stage
 		/// @}
 
+		/// @name Profiling stuff
+		/// @{
+		double msTime, isTime, ppsTime, bsTime;
+		TimeQuery msTq, isTq, ppsTq, bsTq;
+		bool enableStageProfilingFlag;
+		/// @}
+
 		/// Width of the rendering. Don't confuse with the window width
 		uint width;
 		/// Height of the rendering. Don't confuse with the window width
@@ -158,12 +169,6 @@ class Renderer
 };
 
 
-inline void Renderer::setViewport(uint x, uint y, uint w, uint h)
-{
-	glViewport(x, y, w, h);
-}
-
-
 } // end namespace
 
 

+ 2 - 1
src/Renderer/Sm.cpp

@@ -131,7 +131,8 @@ void Sm::run(const Light& light, float distance)
 	crntLevel->fbo.bind();
 
 	// set GL
-	Renderer::setViewport(0, 0, crntLevel->resolution, crntLevel->resolution);
+	GlStateMachineSingleton::getInstance().setViewport(0, 0,
+		crntLevel->resolution, crntLevel->resolution);
 	glClear(GL_DEPTH_BUFFER_BIT);
 
 	// disable color & blend & enable depth test

+ 1 - 1
src/Renderer/Ssao.cpp

@@ -112,7 +112,7 @@ void Ssao::run()
 	GlStateMachineSingleton::getInstance().enable(GL_DEPTH_TEST, false);
 
 
-	Renderer::setViewport(0, 0, width, height);
+	GlStateMachineSingleton::getInstance().setViewport(0, 0, width, height);
 
 	//
 	// 1st pass

+ 2 - 0
src/Scripting/Renderer/MainRenderer.bpi.cpp

@@ -10,5 +10,7 @@ WRAP(MainRenderer)
 		.def("getDbg", (R::Dbg& (R::MainRenderer::*)())(
 			&R::MainRenderer::getDbg),
 			return_value_policy<reference_existing_object>())
+
+		.def("getDbgTime", &R::MainRenderer::getDbgTime)
 	;
 }

+ 4 - 0
src/Scripting/Renderer/Renderer.bpi.cpp

@@ -9,5 +9,9 @@ WRAP(Renderer)
 	class_<R::Renderer, noncopyable>("Renderer", no_init)
 		.def("getPps", (getPpsAccessor)(&R::Renderer::getPps),
 			return_value_policy<reference_existing_object>())
+		.def("getMsTime", &R::Renderer::getMsTime)
+		.def("getIsTime", &R::Renderer::getIsTime)
+		.def("getPpsTime", &R::Renderer::getPpsTime)
+		.def("getBsTime", &R::Renderer::getBsTime)
 	;
 }