Browse Source

GPU profiler working
Added resource creation/destruction/write/read to profiler stats
Refactored render stats class to be more easily accessible from non-render-system

Marko Pintera 11 years ago
parent
commit
19a14f5940
65 changed files with 785 additions and 174 deletions
  1. 9 3
      BansheeCore/Include/BsProfilerGPU.h
  2. 143 3
      BansheeCore/Include/BsRenderStats.h
  3. 0 10
      BansheeCore/Include/BsRenderSystem.h
  4. 7 1
      BansheeCore/Source/BsCoreApplication.cpp
  5. 11 4
      BansheeCore/Source/BsProfilerGPU.cpp
  6. 2 1
      BansheeCore/Source/BsRenderSystem.cpp
  7. 1 0
      BansheeD3D11RenderSystem/Include/BsD3D11OcclusionQuery.h
  8. 17 0
      BansheeD3D11RenderSystem/Include/BsD3D11Prerequisites.h
  9. 1 0
      BansheeD3D11RenderSystem/Include/BsD3D11TimerQuery.h
  10. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11BlendState.cpp
  11. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11DepthStencilState.cpp
  12. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11EventQuery.cpp
  13. 22 0
      BansheeD3D11RenderSystem/Source/BsD3D11GpuBuffer.cpp
  14. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11GpuBufferView.cpp
  15. 9 0
      BansheeD3D11RenderSystem/Source/BsD3D11GpuParamBlockBuffer.cpp
  16. 5 1
      BansheeD3D11RenderSystem/Source/BsD3D11GpuProgram.cpp
  17. 20 0
      BansheeD3D11RenderSystem/Source/BsD3D11IndexBuffer.cpp
  18. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11InputLayoutManager.cpp
  19. 14 1
      BansheeD3D11RenderSystem/Source/BsD3D11OcclusionQuery.cpp
  20. 3 0
      BansheeD3D11RenderSystem/Source/BsD3D11RasterizerState.cpp
  21. 24 19
      BansheeD3D11RenderSystem/Source/BsD3D11RenderSystem.cpp
  22. 6 2
      BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp
  23. 5 0
      BansheeD3D11RenderSystem/Source/BsD3D11SamplerState.cpp
  24. 62 57
      BansheeD3D11RenderSystem/Source/BsD3D11Texture.cpp
  25. 3 0
      BansheeD3D11RenderSystem/Source/BsD3D11TextureView.cpp
  26. 13 1
      BansheeD3D11RenderSystem/Source/BsD3D11TimerQuery.cpp
  27. 21 4
      BansheeD3D11RenderSystem/Source/BsD3D11VertexBuffer.cpp
  28. 1 1
      BansheeD3D11RenderSystem/Source/BsD3D11VideoModeInfo.cpp
  29. 11 0
      BansheeD3D9RenderSystem/Include/BsD3D9Prerequisites.h
  30. 5 0
      BansheeD3D9RenderSystem/Source/BsD3D9EventQuery.cpp
  31. 3 0
      BansheeD3D9RenderSystem/Source/BsD3D9GpuProgram.cpp
  32. 15 0
      BansheeD3D9RenderSystem/Source/BsD3D9IndexBuffer.cpp
  33. 7 0
      BansheeD3D9RenderSystem/Source/BsD3D9OcclusionQuery.cpp
  34. 13 0
      BansheeD3D9RenderSystem/Source/BsD3D9PixelBuffer.cpp
  35. 21 20
      BansheeD3D9RenderSystem/Source/BsD3D9RenderSystem.cpp
  36. 3 0
      BansheeD3D9RenderSystem/Source/BsD3D9Texture.cpp
  37. 8 0
      BansheeD3D9RenderSystem/Source/BsD3D9TimerQuery.cpp
  38. 15 1
      BansheeD3D9RenderSystem/Source/BsD3D9VertexBuffer.cpp
  39. 4 0
      BansheeD3D9RenderSystem/Source/BsD3D9VertexDeclaration.cpp
  40. 1 0
      BansheeEditor/Include/BsMainEditorWindow.h
  41. 2 5
      BansheeEditor/Source/BsMainEditorWindow.cpp
  42. 2 0
      BansheeEngine/Include/BsPrerequisites.h
  43. 4 3
      BansheeEngine/Include/BsProfilerOverlay.h
  44. 19 9
      BansheeEngine/Source/BsProfilerOverlay.cpp
  45. 5 0
      BansheeGLRenderSystem/Include/BsGLGpuBuffer.h
  46. 1 0
      BansheeGLRenderSystem/Include/BsGLOcclusionQuery.h
  47. 13 0
      BansheeGLRenderSystem/Include/BsGLPrerequisites.h
  48. 1 0
      BansheeGLRenderSystem/Include/BsGLTimerQuery.h
  49. 3 0
      BansheeGLRenderSystem/Source/BsGLEventQuery.cpp
  50. 5 1
      BansheeGLRenderSystem/Source/BsGLFrameBufferObject.cpp
  51. 22 0
      BansheeGLRenderSystem/Source/BsGLGpuBuffer.cpp
  52. 7 0
      BansheeGLRenderSystem/Source/BsGLGpuParamBlockBuffer.cpp
  53. 15 0
      BansheeGLRenderSystem/Source/BsGLIndexBuffer.cpp
  54. 12 1
      BansheeGLRenderSystem/Source/BsGLOcclusionQuery.cpp
  55. 5 0
      BansheeGLRenderSystem/Source/BsGLPixelBuffer.cpp
  56. 24 18
      BansheeGLRenderSystem/Source/BsGLRenderSystem.cpp
  57. 3 1
      BansheeGLRenderSystem/Source/BsGLTexture.cpp
  58. 13 1
      BansheeGLRenderSystem/Source/BsGLTimerQuery.cpp
  59. 4 0
      BansheeGLRenderSystem/Source/BsGLVertexArrayObjectManager.cpp
  60. 15 0
      BansheeGLRenderSystem/Source/BsGLVertexBuffer.cpp
  61. 2 0
      BansheeGLRenderSystem/Source/GLSL/include/BsGLSLProgramPipelineManager.h
  62. 3 0
      BansheeGLRenderSystem/Source/GLSL/src/BsGLSLGpuProgram.cpp
  63. 11 0
      BansheeGLRenderSystem/Source/GLSL/src/BsGLSLProgramPipelineManager.cpp
  64. 12 0
      BansheeUtility/Include/BsModule.h
  65. 52 6
      ExampleProject/Main/Main.cpp

+ 9 - 3
BansheeCore/Include/BsProfilerGPU.h

@@ -54,7 +54,7 @@ namespace BansheeEngine
 	/**
 	 * @brief	Profiler that measures time and amount of various GPU operations.
 	 *
-	 * @note	Core thread only.
+	 * @note	Core thread only except where noted otherwise.
 	 */
 	class BS_CORE_EXPORT ProfilerGPU : public Module<ProfilerGPU>
 	{
@@ -62,8 +62,8 @@ namespace BansheeEngine
 		struct ActiveSample
 		{
 			ProfilerString sampleName;
-			RenderStats startStats;
-			RenderStats endStats;
+			RenderStatsData startStats;
+			RenderStatsData endStats;
 			TimerQueryPtr activeTimeQuery;
 			OcclusionQueryPtr activeOcclusionQuery;
 		};
@@ -117,12 +117,16 @@ namespace BansheeEngine
 		 *
 		 * @note	There is an internal limit of maximum number of available reports, where oldest ones will
 		 *			get deleted so make sure to call this often if you don't want to miss some.
+		 *
+		 *			Thread safe.
 		 */
 		UINT32 getNumAvailableReports();
 
 		/**
 		 * @brief	Gets the oldest report available and removes it from the internal list.
 		 *			Throws an exception if no reports are available.
+		 *
+		 * @note	Thread safe.
 		 */
 		GPUProfilerReport getNextReport();
 
@@ -175,5 +179,7 @@ namespace BansheeEngine
 
 		mutable Stack<TimerQueryPtr> mFreeTimerQueries;
 		mutable Stack<OcclusionQueryPtr> mFreeOcclusionQueries;
+
+		BS_MUTEX(mMutex);
 	};
 }

+ 143 - 3
BansheeCore/Include/BsRenderStats.h

@@ -5,12 +5,26 @@
 
 namespace BansheeEngine
 {
+	/**
+	 * @brief	Common types to track resource statistics for.
+	 */
+	enum RenderStatResourceType
+	{
+		RenderStatObject_IndexBuffer,
+		RenderStatObject_VertexBuffer,
+		RenderStatObject_GpuBuffer,
+		RenderStatObject_GpuParamBuffer,
+		RenderStatObject_Texture,
+		RenderStatObject_GpuProgram,
+		RenderStatObject_Query
+	};
+
 	/**
 	 * @brief	Object that stores various render statistics.
 	 */
-	struct RenderStats
+	struct BS_CORE_EXPORT RenderStatsData
 	{
-		RenderStats()
+		RenderStatsData()
 		: numDrawCalls(0), numRenderTargetChanges(0), numPresents(0), numClears(0),
 		  numVertices(0), numPrimitives(0), numBlendStateChanges(0), numRasterizerStateChanges(0), 
 		  numDepthStencilStateChanges(0), numTextureBinds(0), numSamplerBinds(0), numVertexBufferBinds(0), 
@@ -40,6 +54,132 @@ namespace BansheeEngine
 		UINT64 numResourceReads;
 
 		UINT64 numObjectsCreated; 
-		UINT64 numObjectsDestroyed; 
+		UINT64 numObjectsDestroyed;
+	};
+
+	/**
+	 * @brief	Tracks various render system statistics.
+	 *
+	 * @note	Core thread only.
+	 */
+	class BS_CORE_EXPORT RenderStats : public Module<RenderStats>
+	{
+	public:
+		/** Increments draw call counter indicating how many times were
+		 *  render system API Draw methods called. */
+		void incNumDrawCalls() { mData.numDrawCalls++; }
+
+		/** Increments render target change counter indicating how many
+		 *  times did the active render target change. */
+		void incNumRenderTargetChanges() { mData.numRenderTargetChanges++; }
+
+		/** Increments render target present counter indicating how many
+		 *  times did the buffer swap happen. */
+		void incNumPresents() { mData.numPresents++; }
+
+		/** Increments render target clear counter indicating how many
+		 *  times did the target the cleared, entirely or partially. */
+		void incNumClears() { mData.numClears++; }
+
+		/** Increments vertex draw counter indicating how many
+		 *  vertices were sent to the pipeline. */
+		void addNumVertices(UINT32 count) { mData.numVertices += count; }
+
+		/** Increments primitive draw counter indicating how many
+		 *  primitives were sent to the pipeline. */
+		void addNumPrimitives(UINT32 count) { mData.numPrimitives += count; }
+
+		/** Increments blend state change counter indicating how many
+		 *  times was a blend state bound to the pipeline. */
+		void incNumBlendStateChanges() { mData.numBlendStateChanges++; }
+
+		/** Increments rasterizer state change counter indicating how many
+		 *  times was a rasterizer state bound to the pipeline. */
+		void incNumRasterizerStateChanges() { mData.numRasterizerStateChanges++; }
+
+		/** Increments depth/stencil state change counter indicating how many
+		 *  times was a depth/stencil state bound to the pipeline. */
+		void incNumDepthStencilStateChanges() { mData.numDepthStencilStateChanges++; }
+
+		/** Increments texture change counter indicating how many
+		 *  times was a texture bound to the pipeline. */
+		void incNumTextureBinds() { mData.numTextureBinds++; }
+
+		/** Increments sampler state change counter indicating how many
+		 *  times was a sampler state bound to the pipeline. */
+		void incNumSamplerBinds() { mData.numSamplerBinds++; }
+
+		/** Increments vertex buffer change counter indicating how many
+		 *  times was a vertex buffer bound to the pipeline. */
+		void incNumVertexBufferBinds() { mData.numVertexBufferBinds++; }
+
+		/** Increments index buffer change counter indicating how many
+		 *  times was a index buffer bound to the pipeline. */
+		void incNumIndexBufferBinds() { mData.numIndexBufferBinds++; }
+
+		/** Increments GPU parameter buffer change counter indicating how many
+		 *  times was a GPU parameter buffer bound to the pipeline. */
+		void incNumGpuParamBufferBinds() { mData.numGpuParamBufferBinds++; }
+
+		/** Increments GPU program change counter indicating how many
+		 *  times was a GPU program bound to the pipeline. */
+		void incNumGpuProgramBinds() { mData.numGpuProgramBinds++; }
+
+		/**
+		 * Increments created GPU resource counter. 
+		 *
+		 * @param	category	Category of the resource.
+		 */
+		void incResCreated(UINT32 category) 
+		{
+			// TODO - I'm ignoring resourceType for now. Later I will want to
+			// count object creation/destruction/read/write per type. I will
+			// also want to allow the caller to assign names to specific "resourceType" id.
+			// (Since many types will be RenderSystem specific).
+
+			mData.numObjectsCreated++;
+		}
+
+		/**
+		 * Increments destroyed GPU resource counter. 
+		 *
+		 * @param	category	Category of the resource.
+		 */
+		void incResDestroyed(UINT32 category) { mData.numObjectsDestroyed++; }
+
+		/**
+		 * Increments GPU resource read counter. 
+		 *
+		 * @param	category	Category of the resource.
+		 */
+		void incResRead(UINT32 category) { mData.numResourceReads++; }
+
+		/**
+		 * Increments GPU resource write counter. 
+		 *
+		 * @param	category	Category of the resource.
+		 */
+		void incResWrite(UINT32 category) { mData.numResourceWrites++; }
+
+		/**
+		 * Returns an object containing various rendering statistics.
+		 *			
+		 * @note	Do not modify the returned state unless you know what you are doing, it will
+		 *			change the actual internal object.
+		 */
+		RenderStatsData& getData() { return mData; }
+
+	private:
+		RenderStatsData mData;
 	};
+
+#if BS_PROFILING_ENABLED
+	#define BS_INC_RENDER_STAT_CAT(Stat, Category) RenderStats::instance().inc##Stat##((UINT32)##Category##)
+	#define BS_INC_RENDER_STAT(Stat) RenderStats::instance().inc##Stat##()
+	#define BS_ADD_RENDER_STAT(Stat, Count) RenderStats::instance().add##Stat##(##Count##)
+#else
+	#define BS_INC_RENDER_STAT_CAT(Stat, Category)
+	#define BS_INC_RENDER_STAT(Stat)
+	#define BS_ADD_RENDER_STAT(Stat, Count)
+#endif
 }

+ 0 - 10
BansheeCore/Include/BsRenderSystem.h

@@ -6,7 +6,6 @@
 #include "BsString.h"
 
 #include "BsSamplerState.h"
-#include "BsRenderStats.h"
 #include "BsCommandQueue.h"
 #include "BsDrawOps.h"
 #include "BsRenderSystemCapabilities.h"
@@ -323,14 +322,6 @@ namespace BansheeEngine
 		 */
 		virtual float getMaximumDepthInputValue() = 0;
 
-		/**
-		 * @brief	Returns an object containing various rendering statistics.
-		 *			
-		 * @note	Do not modify the returned state unless you know what you are doing, it will
-		 *			change the actual internal object.
-		 */
-		RenderStats& getRenderStats() { return mRenderStats; }
-
 		/************************************************************************/
 		/* 							INTERNAL METHODS				        	*/
 		/************************************************************************/
@@ -376,7 +367,6 @@ namespace BansheeEngine
 
 		RenderTargetPtr mActiveRenderTarget;
 
-		RenderStats mRenderStats;
 		DriverVersion mDriverVersion;
 		CullingMode mCullingMode;
 		UINT16 mDisabledTexUnitsFrom;

+ 7 - 1
BansheeCore/Source/BsCoreApplication.cpp

@@ -37,6 +37,7 @@
 #include "BsThreadPool.h"
 #include "BsTaskScheduler.h"
 #include "BsUUID.h"
+#include "BsRenderStats.h"
 
 #include "BsMaterial.h"
 #include "BsShader.h"
@@ -61,6 +62,7 @@ namespace BansheeEngine
 		ThreadPool::startUp<TThreadPool<ThreadBansheePolicy>>((numWorkerThreads));
 		TaskScheduler::startUp();
 		TaskScheduler::instance().removeWorker();
+		RenderStats::startUp();
 		CoreThread::startUp();
 		StringTable::startUp();
 		DeferredCallManager::startUp();
@@ -122,6 +124,7 @@ namespace BansheeEngine
 		StringTable::shutDown();
 
 		CoreThread::shutDown();
+		RenderStats::shutDown();
 		TaskScheduler::shutDown();
 		ThreadPool::shutDown();
 		ProfilingManager::shutDown();
@@ -175,7 +178,6 @@ namespace BansheeEngine
 
 			gCoreThread().queueCommand(&Platform::_coreUpdate);
 			gCoreThread().submitAccessors();
-			gCoreThread().queueCommand(std::bind(&ProfilerGPU::_update, ProfilerGPU::instancePtr()));
 			gCoreThread().queueCommand(std::bind(&CoreApplication::endCoreProfiling, this));
 			gCoreThread().queueCommand(std::bind(&CoreApplication::frameRenderingFinishedCallback, this));
 
@@ -206,10 +208,14 @@ namespace BansheeEngine
 	void CoreApplication::beginCoreProfiling()
 	{
 		gProfilerCPU().beginThread("Core");
+		ProfilerGPU::instance().beginFrame();
 	}
 
 	void CoreApplication::endCoreProfiling()
 	{
+		ProfilerGPU::instance().endFrame();
+		ProfilerGPU::instance()._update();
+
 		gProfilerCPU().endThread();
 		gProfiler()._updateCore();
 	}

+ 11 - 4
BansheeCore/Source/BsProfilerGPU.cpp

@@ -1,5 +1,5 @@
 #include "BsProfilerGPU.h"
-#include "BsRenderSystem.h"
+#include "BsRenderStats.h"
 #include "BsTimerQuery.h"
 #include "BsOcclusionQuery.h"
 #include "BsException.h"
@@ -70,11 +70,15 @@ namespace BansheeEngine
 
 	UINT32 ProfilerGPU::getNumAvailableReports()
 	{
+		BS_LOCK_MUTEX(mMutex);
+
 		return (UINT32)mReadyReports.size();
 	}
 
 	GPUProfilerReport ProfilerGPU::getNextReport()
 	{
+		BS_LOCK_MUTEX(mMutex);
+
 		if (mReadyReports.empty())
 			BS_EXCEPT(InvalidStateException, "No reports are available.")
 
@@ -97,7 +101,10 @@ namespace BansheeEngine
 				GPUProfilerReport report = resolveFrame(frame);
 				mUnresolvedFrames.pop();
 
-				mReadyReports.push(report);
+				{
+					BS_LOCK_MUTEX(mMutex);
+					mReadyReports.push(report);
+				}
 			}
 			else
 				break;
@@ -158,7 +165,7 @@ namespace BansheeEngine
 
 	void ProfilerGPU::beginSampleInternal(ActiveSample& sample)
 	{
-		sample.startStats = RenderSystem::instance().getRenderStats();
+		sample.startStats = RenderStats::instance().getData();
 		sample.activeTimeQuery = getTimerQuery();
 		sample.activeTimeQuery->begin();
 
@@ -168,7 +175,7 @@ namespace BansheeEngine
 
 	void ProfilerGPU::endSampleInternal(ActiveSample& sample)
 	{
-		sample.endStats = RenderSystem::instance().getRenderStats();
+		sample.endStats = RenderStats::instance().getData();
 		sample.activeOcclusionQuery->end();
 		sample.activeTimeQuery->end();
 	}

+ 2 - 1
BansheeCore/Source/BsRenderSystem.cpp

@@ -11,6 +11,7 @@
 #include "BsCoreThread.h"
 #include "BsMesh.h"
 #include "BsProfilerCPU.h"
+#include "BsRenderStats.h"
 
 using namespace std::placeholders;
 
@@ -272,7 +273,7 @@ namespace BansheeEngine {
 		{
 			target->swapBuffers();
 
-			mRenderStats.numPresents++;
+			BS_INC_RENDER_STAT(NumPresents);
 		}
 	}
 

+ 1 - 0
BansheeD3D11RenderSystem/Include/BsD3D11OcclusionQuery.h

@@ -40,6 +40,7 @@ namespace BansheeEngine
 		ID3D11Query* mQuery;
 		ID3D11DeviceContext* mContext;
 		bool mFinalized;
+		bool mQueryEndCalled;
 
 		UINT32 mNumSamples;
 

+ 17 - 0
BansheeD3D11RenderSystem/Include/BsD3D11Prerequisites.h

@@ -51,6 +51,9 @@ namespace BansheeEngine
 	class D3D11GpuBuffer;
 	class D3D11RenderUtility;
 
+	/**
+	 * @brief	Type IDs used for RTTI.
+	 */
 	enum TypeID_D3D11
 	{
 		TID_D3D11_GpuProgram = 12000,
@@ -62,6 +65,20 @@ namespace BansheeEngine
 		TID_D3D11_GpuComputeProgram = 12006
 	};
 
+	/**
+	 * @brief	DirectX 11 specific types to track resource statistics for.
+	 */
+	enum D3D11RenderStatResourceType
+	{
+		RenderStatObject_DepthStencilState = 100,
+		RenderStatObject_RasterizerState,
+		RenderStatObject_BlendState,
+		RenderStatObject_SamplerState,
+		RenderStatObject_InputLayout,
+		RenderStatObject_ResourceView,
+		RenderStatObject_SwapChain
+	};
+
 	typedef Vector<char*> HLSLMicroCode;
 
 	typedef std::shared_ptr<D3D11GpuVertexProgram> D3D11GpuVertexProgramPtr;

+ 1 - 0
BansheeD3D11RenderSystem/Include/BsD3D11TimerQuery.h

@@ -36,6 +36,7 @@ namespace BansheeEngine
 
 	private:
 		bool mFinalized;
+		bool mQueryEndCalled;
 		float mTimeDelta;
 
 		ID3D11Query* mBeginQuery;

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11BlendState.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D11Mappings.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -43,6 +44,8 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Cannot create blend state.\nError Description:" + errorDescription);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_BlendState);
+
 		BlendState::initialize_internal();
 	}
 
@@ -50,6 +53,8 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mBlendState);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_BlendState);
+
 		BlendState::destroy_internal();
 	}
 }

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11DepthStencilState.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D11Device.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Mappings.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -44,6 +45,8 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Cannot create depth stencil state.\nError Description:" + errorDescription);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_DepthStencilState);
+
 		DepthStencilState::initialize_internal();
 	}
 
@@ -51,6 +54,8 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mDepthStencilState);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_DepthStencilState);
+
 		DepthStencilState::destroy_internal();
 	}
 }

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11EventQuery.cpp

@@ -1,6 +1,7 @@
 #include "BsD3D11EventQuery.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -22,6 +23,8 @@ namespace BansheeEngine
 		}
 
 		mContext = device.getImmediateContext();
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	D3D11EventQuery::~D3D11EventQuery()
@@ -30,6 +33,8 @@ namespace BansheeEngine
 		{
 			mQuery->Release();
 		}
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D11EventQuery::begin()

+ 22 - 0
BansheeD3D11RenderSystem/Source/BsD3D11GpuBuffer.cpp

@@ -3,6 +3,8 @@
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11HardwareBuffer.h"
 #include "BsD3D11Device.h"
+#include "BsD3D11Mappings.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -40,6 +42,8 @@ namespace BansheeEngine
 		mBuffer = bs_new<D3D11HardwareBuffer, PoolAlloc>(bufferType, mUsage, mElementCount, mElementSize, 
 			d3d11rs->getPrimaryDevice(), false, false, mRandomGpuWrite, mUseCounter);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
+
 		GpuBuffer::initialize_internal();
 	}
 
@@ -47,11 +51,25 @@ namespace BansheeEngine
 	{
 		bs_delete<PoolAlloc>(mBuffer);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuBuffer);
+
 		GpuBuffer::destroy_internal();
 	}
 
 	void* D3D11GpuBuffer::lock(UINT32 offset, UINT32 length, GpuLockOptions options)
 	{
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
+		}
+#endif
+
 		return mBuffer->lock(offset, length, options);
 	}
 
@@ -62,11 +80,15 @@ namespace BansheeEngine
 
 	void D3D11GpuBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
 	{
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
+
 		mBuffer->readData(offset, length, pDest);
 	}
 
 	void D3D11GpuBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags)
 	{
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
+
 		mBuffer->writeData(offset, length, pSource, writeFlags);
 	}
 

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11GpuBufferView.cpp

@@ -3,6 +3,7 @@
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
 #include "BsUtil.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -17,6 +18,8 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mSRV);
 		SAFE_RELEASE(mUAV);
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_ResourceView);
 	}
 
 	void D3D11GpuBufferView::initialize(GpuBufferPtr buffer, GPU_BUFFER_DESC& desc)
@@ -33,6 +36,8 @@ namespace BansheeEngine
 		}
 		else
 			mSRV = createSRV(d3d11GpuBuffer, desc.firstElement, desc.elementWidth, desc.numElements);
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_ResourceView);
 	}
 
 	ID3D11ShaderResourceView* D3D11GpuBufferView::createSRV(D3D11GpuBuffer* buffer, UINT32 firstElement, UINT32 elementWidth, UINT32 numElements)

+ 9 - 0
BansheeD3D11RenderSystem/Source/BsD3D11GpuParamBlockBuffer.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D11HardwareBuffer.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -23,6 +24,8 @@ namespace BansheeEngine
 		else
 			BS_EXCEPT(InternalErrorException, "Invalid gpu param block usage.");
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuParamBuffer);
+
 		GpuParamBlockBuffer::initialize_internal();
 	}
 
@@ -31,6 +34,8 @@ namespace BansheeEngine
 		if(mBuffer != nullptr)
 			bs_delete<PoolAlloc>(mBuffer);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuParamBuffer);
+
 		GpuParamBlockBuffer::destroy_internal();
 	}
 
@@ -42,10 +47,14 @@ namespace BansheeEngine
 	void D3D11GpuParamBlockBuffer::writeData(const UINT8* data)
 	{
 		mBuffer->writeData(0, mSize, data, BufferWriteType::Discard);
+
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuParamBuffer);
 	}
 
 	void D3D11GpuParamBlockBuffer::readData(UINT8* data) const
 	{
 		mBuffer->readData(0, mSize, data);
+
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuParamBuffer);
 	}
 }

+ 5 - 1
BansheeD3D11RenderSystem/Source/BsD3D11GpuProgram.cpp

@@ -8,6 +8,7 @@
 #include "BsHardwareBufferManager.h"
 #include "BsD3D11HLSLParamParser.h"
 #include "BsD3D11GpuProgramRTTI.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -55,15 +56,18 @@ namespace BansheeEngine
 
 		mProgramId = GlobalProgramId++;
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
+
 		GpuProgram::initialize_internal();
 	}
 
 	void D3D11GpuProgram::destroy_internal()
 	{
 		mMicrocode.clear();
-
 		mInputDeclaration = nullptr;
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
+
 		GpuProgram::destroy_internal();
 	}
 

+ 20 - 0
BansheeD3D11RenderSystem/Source/BsD3D11IndexBuffer.cpp

@@ -1,5 +1,6 @@
 #include "BsD3D11IndexBuffer.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -19,6 +20,7 @@ namespace BansheeEngine
 	{
 		mBuffer = bs_new<D3D11HardwareBuffer, PoolAlloc>(D3D11HardwareBuffer::BT_INDEX, mUsage, 1, mSizeInBytes, std::ref(mDevice), mSystemMemory);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBuffer::initialize_internal();
 	}
 
@@ -27,11 +29,25 @@ namespace BansheeEngine
 		if(mBuffer != nullptr)
 			bs_delete<PoolAlloc>(mBuffer) ;
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_IndexBuffer);
+
 		IndexBuffer::destroy_internal();
 	}
 
 	void* D3D11IndexBuffer::lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options)
 	{
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
+		}
+#endif
+
 		return mBuffer->lock(offset, length, options);
 	}
 
@@ -43,11 +59,15 @@ namespace BansheeEngine
 	void D3D11IndexBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
 	{
 		mBuffer->readData(offset, length, pDest);
+
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
 	}
 
 	void D3D11IndexBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags)
 	{
 		mBuffer->writeData(offset, length, pSource, writeFlags);
+
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
 	}
 
 	void D3D11IndexBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11InputLayoutManager.cpp

@@ -4,6 +4,7 @@
 #include "BsD3D11Device.h"
 #include "BsD3D11GpuProgram.h"
 #include "BsHardwareBufferManager.h"
+#include "BsRenderStats.h"
 #include "BsDebug.h"
 #include "BsUtil.h"
 
@@ -48,6 +49,7 @@ namespace BansheeEngine
 			bs_delete<PoolAlloc>(firstElem->second);
 
 			mInputLayoutMap.erase(firstElem);
+			BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
 		}
 	}
 
@@ -124,6 +126,8 @@ namespace BansheeEngine
 		pair.vertexProgramId = vertexProgram.getProgramId();
 
 		mInputLayoutMap[pair] = newEntry;
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_InputLayout);
 	}
 
 	void D3D11InputLayoutManager::removeLeastUsed()
@@ -150,6 +154,7 @@ namespace BansheeEngine
 			bs_delete<PoolAlloc>(inputLayoutIter->second);
 
 			mInputLayoutMap.erase(inputLayoutIter);
+			BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_InputLayout);
 
 			elemsRemoved++;
 			if(elemsRemoved >= NUM_ELEMENTS_TO_PRUNE)

+ 14 - 1
BansheeD3D11RenderSystem/Source/BsD3D11OcclusionQuery.cpp

@@ -1,12 +1,13 @@
 #include "BsD3D11OcclusionQuery.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 #include "BsMath.h"
 
 namespace BansheeEngine
 {
 	D3D11OcclusionQuery::D3D11OcclusionQuery(bool binary)
-		:OcclusionQuery(binary), mContext(nullptr), mQuery(nullptr), mNumSamples(0), mFinalized(false)
+		:OcclusionQuery(binary), mContext(nullptr), mQuery(nullptr), mNumSamples(0), mFinalized(false), mQueryEndCalled(false)
 	{
 		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
 		D3D11Device& device = rs->getPrimaryDevice();
@@ -20,12 +21,16 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Failed to create an occlusion query.");
 
 		mContext = device.getImmediateContext();
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	D3D11OcclusionQuery::~D3D11OcclusionQuery()
 	{
 		if (mQuery != nullptr)
 			mQuery->Release();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D11OcclusionQuery::begin()
@@ -33,16 +38,24 @@ namespace BansheeEngine
 		mContext->Begin(mQuery);
 
 		mNumSamples = 0;
+		mQueryEndCalled = false;
+		
 		setActive(true);
 	}
 
 	void D3D11OcclusionQuery::end()
 	{
 		mContext->End(mQuery);
+
+		mQueryEndCalled = true;
+		mFinalized = false;
 	}
 
 	bool D3D11OcclusionQuery::isReady() const
 	{
+		if (!mQueryEndCalled)
+			return false;
+
 		if (mBinary)
 		{
 			BOOL anySamples = FALSE;

+ 3 - 0
BansheeD3D11RenderSystem/Source/BsD3D11RasterizerState.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
 #include "BsD3D11Mappings.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -39,6 +40,7 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Cannot create rasterizer state.\nError Description:" + errorDescription);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_RasterizerState);
 		RasterizerState::initialize_internal();
 	}
 
@@ -46,6 +48,7 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mRasterizerState);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_RasterizerState);
 		RasterizerState::destroy_internal();
 	}
 }

+ 24 - 19
BansheeD3D11RenderSystem/Source/BsD3D11RenderSystem.cpp

@@ -24,6 +24,7 @@
 #include "BsD3D11QueryManager.h"
 #include "BsDebug.h"
 #include "BsException.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -217,7 +218,7 @@ namespace BansheeEngine
 			BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
 		}
 
-		mRenderStats.numSamplerBinds++;
+		BS_INC_RENDER_STAT(NumSamplerBinds);
 	}
 
 	void D3D11RenderSystem::setBlendState(const BlendStatePtr& blendState)
@@ -227,7 +228,7 @@ namespace BansheeEngine
 		D3D11BlendState* d3d11BlendState = static_cast<D3D11BlendState*>(const_cast<BlendState*>(blendState.get()));
 		mDevice->getImmediateContext()->OMSetBlendState(d3d11BlendState->getInternal(), nullptr, 0xFFFFFFFF);
 
-		mRenderStats.numBlendStateChanges++;
+		BS_INC_RENDER_STAT(NumBlendStateChanges);
 	}
 
 	void D3D11RenderSystem::setRasterizerState(const RasterizerStatePtr& rasterizerState)
@@ -237,7 +238,7 @@ namespace BansheeEngine
 		D3D11RasterizerState* d3d11RasterizerState = static_cast<D3D11RasterizerState*>(const_cast<RasterizerState*>(rasterizerState.get()));
 		mDevice->getImmediateContext()->RSSetState(d3d11RasterizerState->getInternal());
 
-		mRenderStats.numRasterizerStateChanges++;
+		BS_INC_RENDER_STAT(NumRasterizerStateChanges);
 	}
 
 	void D3D11RenderSystem::setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue)
@@ -247,7 +248,7 @@ namespace BansheeEngine
 		D3D11DepthStencilState* d3d11RasterizerState = static_cast<D3D11DepthStencilState*>(const_cast<DepthStencilState*>(depthStencilState.get()));
 		mDevice->getImmediateContext()->OMSetDepthStencilState(d3d11RasterizerState->getInternal(), stencilRefValue);
 
-		mRenderStats.numDepthStencilStateChanges++;
+		BS_INC_RENDER_STAT(NumDepthStencilStateChanges);
 	}
 
 	void D3D11RenderSystem::setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const TexturePtr &texPtr)
@@ -291,7 +292,7 @@ namespace BansheeEngine
 			BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
 		}
 
-		mRenderStats.numTextureBinds++;
+		BS_INC_RENDER_STAT(NumTextureBinds);
 	}
 
 	void D3D11RenderSystem::disableTextureUnit(GpuProgramType gptype, UINT16 texUnit)
@@ -360,7 +361,7 @@ namespace BansheeEngine
 
 		mDevice->getImmediateContext()->IASetVertexBuffers(index, numBuffers, dx11buffers, strides, offsets);
 
-		mRenderStats.numVertexBufferBinds++;
+		BS_INC_RENDER_STAT(NumVertexBufferBinds);
 	}
 
 	void D3D11RenderSystem::setIndexBuffer(const IndexBufferPtr& buffer)
@@ -379,7 +380,7 @@ namespace BansheeEngine
 
 		mDevice->getImmediateContext()->IASetIndexBuffer(indexBuffer->getD3DIndexBuffer(), indexFormat, 0);
 
-		mRenderStats.numIndexBufferBinds++;
+		BS_INC_RENDER_STAT(NumIndexBufferBinds);
 	}
 
 	void D3D11RenderSystem::setVertexDeclaration(VertexDeclarationPtr vertexDeclaration)
@@ -449,7 +450,7 @@ namespace BansheeEngine
 		if (mDevice->hasError())
 			BS_EXCEPT(RenderingAPIException, "Failed to bindGpuProgram : " + mDevice->getErrorDescription());
 
-		mRenderStats.numGpuProgramBinds++;
+		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 	}
 
 	void D3D11RenderSystem::unbindGpuProgram(GpuProgramType gptype)
@@ -481,7 +482,7 @@ namespace BansheeEngine
 			BS_EXCEPT(InvalidParametersException, "Unsupported gpu program type: " + toString(gptype));
 		}
 
-		mRenderStats.numGpuProgramBinds++;
+		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 	}
 
 	void D3D11RenderSystem::bindGpuParams(GpuProgramType gptype, GpuParamsPtr bindableParams)
@@ -550,7 +551,7 @@ namespace BansheeEngine
 				break;
 			};
 
-			mRenderStats.numGpuParamBufferBinds++;
+			BS_INC_RENDER_STAT(NumGpuParamBufferBinds);
 		}
 
 		if (mDevice->hasError())
@@ -570,9 +571,11 @@ namespace BansheeEngine
 			LOGWRN(mDevice->getErrorDescription());
 #endif
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += vertexCountToPrimCount(mActiveDrawOp, vertexCount);
+		UINT32 primCount = vertexCountToPrimCount(mActiveDrawOp, vertexCount);
+
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
 	}
 
 	void D3D11RenderSystem::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount)
@@ -588,9 +591,11 @@ namespace BansheeEngine
 			LOGWRN(mDevice->getErrorDescription());
 #endif
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += vertexCountToPrimCount(mActiveDrawOp, indexCount);
+		UINT32 primCount = vertexCountToPrimCount(mActiveDrawOp, vertexCount);
+
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
 	}
 
 	void D3D11RenderSystem::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
@@ -620,7 +625,7 @@ namespace BansheeEngine
 		if (!clearEntireTarget)
 		{
 			D3D11RenderUtility::instance().drawClearQuad(buffers, color, depth, stencil);
-			mRenderStats.numClears++;
+			BS_INC_RENDER_STAT(NumClears);
 		}
 		else
 			clearRenderTarget(buffers, color, depth, stencil);
@@ -682,7 +687,7 @@ namespace BansheeEngine
 				mDevice->getImmediateContext()->ClearDepthStencilView(depthStencilView, clearFlag, depth, (UINT8)stencil);
 		}
 
-		mRenderStats.numClears++;
+		BS_INC_RENDER_STAT(NumClears);
 	}
 
 	void D3D11RenderSystem::setRenderTarget(RenderTargetPtr target)
@@ -713,7 +718,7 @@ namespace BansheeEngine
 
 		bs_deleteN<ScratchAlloc>(views, maxRenderTargets);
 
-		mRenderStats.numRenderTargetChanges++;
+		BS_INC_RENDER_STAT(NumRenderTargetChanges);
 	}
 
 	void D3D11RenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes)

+ 6 - 2
BansheeD3D11RenderSystem/Source/BsD3D11RenderWindow.cpp

@@ -9,6 +9,7 @@
 #include "BsD3D11DriverList.h"
 #include "BsD3D11Driver.h"
 #include "BsD3D11VideoModeInfo.h"
+#include "BsRenderStats.h"
 #include "BsInput.h"
 #include "BsException.h"
 
@@ -255,6 +256,7 @@ namespace BansheeEngine
 		mClosed = true;
 
 		SAFE_RELEASE(mSwapChain);
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_SwapChain);
 
 		if (mHWnd && !mIsExternal)
 		{
@@ -647,6 +649,8 @@ namespace BansheeEngine
 
 		if (FAILED(hr))
 			BS_EXCEPT(RenderingAPIException, "Unable to create swap chain");
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_SwapChain);
 	}
 
 	void D3D11RenderWindow::createSizeDependedD3DResources()
@@ -720,14 +724,14 @@ namespace BansheeEngine
 	{
 		if (mDevice.getD3D11Device() == nullptr)
 		{
-			BS_EXCEPT(RenderingAPIException, "D3D11Device is NULL!");
+			BS_EXCEPT(RenderingAPIException, "D3D11Device is null.");
 		}
 
 		IDXGIDevice* pDXGIDevice = nullptr;
 		HRESULT hr = mDevice.getD3D11Device()->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDXGIDevice);
 
 		if(FAILED(hr))
-			BS_EXCEPT(RenderingAPIException, "Unable to query a DXGIDevice");
+			BS_EXCEPT(RenderingAPIException, "Unable to query a DXGIDevice.");
 
 		return pDXGIDevice;
 	}

+ 5 - 0
BansheeD3D11RenderSystem/Source/BsD3D11SamplerState.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
 #include "BsD3D11Mappings.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -96,6 +97,8 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Cannot create sampler state.\nError Description:" + errorDescription);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_SamplerState);
+
 		SamplerState::initialize_internal();
 	}
 
@@ -103,6 +106,8 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mSamplerState);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_SamplerState);
+
 		SamplerState::destroy_internal();
 	}
 }

+ 62 - 57
BansheeD3D11RenderSystem/Source/BsD3D11Texture.cpp

@@ -6,28 +6,58 @@
 #include "BsCoreThread.h"
 #include "BsException.h"
 #include "BsAsyncOp.h"
+#include "BsRenderStats.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
 {
 	D3D11Texture::D3D11Texture()
-		: Texture()
-		, m1DTex(nullptr)
-		, m2DTex(nullptr)
-		, m3DTex(nullptr)
-		, mTex(nullptr)
-		, mShaderResourceView(nullptr)
-		, mStagingBuffer(nullptr)
-		, mLockedSubresourceIdx(-1)
-		, mLockedForReading(false)
-		, mStaticBuffer(nullptr)
+		: Texture(), m1DTex(nullptr), m2DTex(nullptr), m3DTex(nullptr), 
+		mTex(nullptr), mShaderResourceView(nullptr), mStagingBuffer(nullptr), 
+		mLockedSubresourceIdx(-1), mLockedForReading(false), mStaticBuffer(nullptr)
+	{ }
+
+	D3D11Texture::~D3D11Texture()
+	{ }
+
+	void D3D11Texture::initialize_internal()
 	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		switch (getTextureType())
+		{
+		case TEX_TYPE_1D:
+			create1DTex();
+			break;
+		case TEX_TYPE_2D:
+		case TEX_TYPE_CUBE_MAP:
+			create2DTex();
+			break;
+		case TEX_TYPE_3D:
+			create3DTex();
+			break;
+		default:
+			destroy_internal();
+			BS_EXCEPT(RenderingAPIException, "Unknown texture type");
+		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
+		Texture::initialize_internal();
 	}
 
-	D3D11Texture::~D3D11Texture()
+	void D3D11Texture::destroy_internal()
 	{
-			
+		SAFE_RELEASE(mTex);
+		SAFE_RELEASE(mShaderResourceView);
+		SAFE_RELEASE(m1DTex);
+		SAFE_RELEASE(m2DTex);
+		SAFE_RELEASE(m3DTex);
+		SAFE_RELEASE(mStagingBuffer);
+
+		clearBufferViews();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
+		Texture::destroy_internal();
 	}
 
 	void D3D11Texture::copyImpl(TexturePtr& target)
@@ -47,6 +77,18 @@ namespace BansheeEngine
 
 	PixelData D3D11Texture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face)
 	{
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
+		}
+#endif
+
 		UINT32 mipWidth = mWidth >> mipLevel;
 		UINT32 mipHeight = mHeight >> mipLevel;
 		UINT32 mipDepth = mDepth >> mipLevel;
@@ -143,6 +185,8 @@ namespace BansheeEngine
 				String errorDescription = device.getErrorDescription();
 				BS_EXCEPT(RenderingAPIException, "D3D11 device cannot map texture\nError Description:" + errorDescription);
 			}
+
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
 		}
 		else
 		{
@@ -150,45 +194,6 @@ namespace BansheeEngine
 		}
 	}
 
-	void D3D11Texture::initialize_internal()
-	{
-		THROW_IF_NOT_CORE_THREAD;
-
-		// load based on tex.type
-		switch (getTextureType())
-		{
-			case TEX_TYPE_1D:
-				create1DTex();
-				break;
-			case TEX_TYPE_2D:
-			case TEX_TYPE_CUBE_MAP:
-				create2DTex();
-				break;
-			case TEX_TYPE_3D:
-				create3DTex();
-				break;
-			default:
-				destroy_internal();
-				BS_EXCEPT(RenderingAPIException, "Unknown texture type");
-		}
-
-		Texture::initialize_internal();
-	}
-
-	void D3D11Texture::destroy_internal()
-	{
-		SAFE_RELEASE(mTex);
-		SAFE_RELEASE(mShaderResourceView);
-		SAFE_RELEASE(m1DTex);
-		SAFE_RELEASE(m2DTex);
-		SAFE_RELEASE(m3DTex);
-		SAFE_RELEASE(mStagingBuffer);
-
-		clearBufferViews();
-
-		Texture::destroy_internal();
-	}
-
 	void D3D11Texture::create1DTex()
 	{
 		// We must have those defined here
@@ -225,9 +230,9 @@ namespace BansheeEngine
 		}
 		else
 		{
-			desc.Usage			= D3D11Mappings::getUsage(mUsage);
+			desc.Usage			= D3D11Mappings::getUsage((GpuBufferUsage)mUsage);
 			desc.BindFlags		= D3D11_BIND_SHADER_RESOURCE;
-			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags(mUsage);
+			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)mUsage);
 
 			// Determine total number of mipmaps including main one (d3d11 convention)
 			UINT32 numMips		= (mNumMipmaps == MIP_UNLIMITED || (1U << mNumMipmaps) > mWidth) ? 0 : mNumMipmaps + 1;
@@ -340,9 +345,9 @@ namespace BansheeEngine
 		}
 		else
 		{
-			desc.Usage			= D3D11Mappings::getUsage(mUsage);
+			desc.Usage			= D3D11Mappings::getUsage((GpuBufferUsage)mUsage);
 			desc.BindFlags		= D3D11_BIND_SHADER_RESOURCE;
-			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags(mUsage);
+			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)mUsage);
 
 			// Determine total number of mipmaps including main one (d3d11 convention)
 			UINT32 numMips = (mNumMipmaps == MIP_UNLIMITED || (1U << mNumMipmaps) > mWidth) ? 0 : mNumMipmaps + 1;
@@ -486,9 +491,9 @@ namespace BansheeEngine
 		}
 		else
 		{
-			desc.Usage			= D3D11Mappings::getUsage(mUsage);
+			desc.Usage			= D3D11Mappings::getUsage((GpuBufferUsage)mUsage);
 			desc.BindFlags		= D3D11_BIND_SHADER_RESOURCE;
-			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags(mUsage);
+			desc.CPUAccessFlags = D3D11Mappings::getAccessFlags((GpuBufferUsage)mUsage);
 
 			// Determine total number of mipmaps including main one (d3d11 convention)
 			UINT numMips = (mNumMipmaps == MIP_UNLIMITED || (1U << mNumMipmaps) > std::max(std::max(mWidth, mHeight), mDepth)) ? 0 : mNumMipmaps + 1;

+ 3 - 0
BansheeD3D11RenderSystem/Source/BsD3D11TextureView.cpp

@@ -3,6 +3,7 @@
 #include "BsD3D11Device.h"
 #include "BsD3D11Texture.h"
 #include "BsUtil.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -26,6 +27,7 @@ namespace BansheeEngine
 		else
 			mSRV = createSRV(d3d11Texture, mDesc.mostDetailMip, mDesc.numMips, mDesc.firstArraySlice, mDesc.numArraySlices);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_ResourceView);
 		TextureView::initialize_internal();
 	}
 
@@ -36,6 +38,7 @@ namespace BansheeEngine
 		SAFE_RELEASE(mDSV);
 		SAFE_RELEASE(mRTV);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_ResourceView);
 		TextureView::destroy_internal();
 	}
 

+ 13 - 1
BansheeD3D11RenderSystem/Source/BsD3D11TimerQuery.cpp

@@ -1,13 +1,14 @@
 #include "BsD3D11TimerQuery.h"
 #include "BsD3D11RenderSystem.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
 {
 	D3D11TimerQuery::D3D11TimerQuery()
 		:mFinalized(false), mContext(nullptr), mBeginQuery(nullptr), 
-		mEndQuery(nullptr), mDisjointQuery(nullptr), mTimeDelta(0.0f)
+		mEndQuery(nullptr), mDisjointQuery(nullptr), mTimeDelta(0.0f), mQueryEndCalled(false)
 	{
 		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
 		D3D11Device& device = rs->getPrimaryDevice();
@@ -37,6 +38,7 @@ namespace BansheeEngine
 		}
 
 		mContext = device.getImmediateContext();
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	D3D11TimerQuery::~D3D11TimerQuery()
@@ -49,6 +51,8 @@ namespace BansheeEngine
 
 		if(mDisjointQuery != nullptr)
 			mDisjointQuery->Release();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D11TimerQuery::begin()
@@ -56,6 +60,8 @@ namespace BansheeEngine
 		mContext->Begin(mDisjointQuery);
 		mContext->End(mBeginQuery);
 
+		mQueryEndCalled = false;
+		
 		setActive(true);
 	}
 
@@ -63,10 +69,16 @@ namespace BansheeEngine
 	{
 		mContext->End(mEndQuery);
 		mContext->End(mDisjointQuery);
+
+		mQueryEndCalled = true;
+		mFinalized = false;
 	}
 
 	bool D3D11TimerQuery::isReady() const
 	{
+		if (!mQueryEndCalled)
+			return false;
+
 		D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData;
 		return mContext->GetData(mDisjointQuery, &disjointData, sizeof(disjointData), 0) == S_OK;
 	}

+ 21 - 4
BansheeD3D11RenderSystem/Source/BsD3D11VertexBuffer.cpp

@@ -1,5 +1,6 @@
 #include "BsD3D11VertexBuffer.h"
 #include "BsD3D11Device.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -13,6 +14,18 @@ namespace BansheeEngine
 
 	void* D3D11VertexBuffer::lockImpl(UINT32 offset, UINT32 length, GpuLockOptions options)
 	{
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
+		}
+#endif
+
 		return mBuffer->lock(offset, length, options);
 	}
 
@@ -21,14 +34,16 @@ namespace BansheeEngine
 		mBuffer->unlock();
 	}
 
-	void D3D11VertexBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
+	void D3D11VertexBuffer::readData(UINT32 offset, UINT32 length, void* dest)
 	{
-		mBuffer->readData(offset, length, pDest);
+		mBuffer->readData(offset, length, dest);
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
 	}
 
-	void D3D11VertexBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags)
+	void D3D11VertexBuffer::writeData(UINT32 offset, UINT32 length, const void* source, BufferWriteType writeFlags)
 	{
-		mBuffer->writeData(offset, length, pSource, writeFlags);
+		mBuffer->writeData(offset, length, source, writeFlags);
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
 	}
 
 	void D3D11VertexBuffer::copyData(HardwareBuffer& srcBuffer, UINT32 srcOffset, 
@@ -42,6 +57,7 @@ namespace BansheeEngine
 		mBuffer = bs_new<D3D11HardwareBuffer, PoolAlloc>(D3D11HardwareBuffer::BT_VERTEX, 
 			mUsage, 1, mSizeInBytes, std::ref(mDevice), mSystemMemory, mStreamOut);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
 		VertexBuffer::initialize_internal();
 	}
 
@@ -50,6 +66,7 @@ namespace BansheeEngine
 		if(mBuffer != nullptr)
 			bs_delete<PoolAlloc>(mBuffer);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexBuffer);
 		VertexBuffer::destroy_internal();
 	}
 }

+ 1 - 1
BansheeD3D11RenderSystem/Source/BsD3D11VideoModeInfo.cpp

@@ -23,7 +23,7 @@ namespace BansheeEngine
 
 		UINT32 numModes = 0;
 
-		HRESULT hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, 0);
+		HRESULT hr = output->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, 0, &numModes, nullptr);
 		if (FAILED(hr))
 		{
 			SAFE_RELEASE(output);

+ 11 - 0
BansheeD3D9RenderSystem/Include/BsD3D9Prerequisites.h

@@ -49,6 +49,9 @@ namespace BansheeEngine
 	typedef std::shared_ptr<D3D9RenderWindow> D3D9RenderWindowPtr;
 	typedef std::shared_ptr<D3D9Texture> D3D9TexturePtr;
 
+	/**
+	 * @brief	Type IDs used for RTTI.
+	 */
 	enum TypeID_D3D9
 	{
 		TID_D3D9_GpuProgram = 10000,
@@ -56,6 +59,14 @@ namespace BansheeEngine
 		TID_D3D9_GpuFragmentProgram = 10002
 	};
 
+	/**
+	 * @brief	DirectX 9 specific types to track resource statistics for.
+	 */
+	enum D3D9RenderStatResourceType
+	{
+		RenderStatObject_VertexDeclaration = 100
+	};
+
 #if (BS_PLATFORM == BS_PLATFORM_WIN32) && !defined(BS_STATIC_LIB)
 #	ifdef BS_RSD3D9_EXPORTS
 #		define BS_D3D9_EXPORT __declspec(dllexport)

+ 5 - 0
BansheeD3D9RenderSystem/Source/BsD3D9EventQuery.cpp

@@ -2,6 +2,7 @@
 #include "BsD3D9RenderSystem.h"
 #include "BsD3D9ResourceManager.h"
 #include "BsD3D9Device.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -26,11 +27,15 @@ namespace BansheeEngine
 		{
 			BS_EXCEPT(RenderingAPIException, "Failed to create an Event query.");
 		}
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	void D3D9EventQuery::releaseQuery()
 	{
 		SAFE_RELEASE(mQuery);
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D9EventQuery::begin()

+ 3 - 0
BansheeD3D9RenderSystem/Source/BsD3D9GpuProgram.cpp

@@ -9,6 +9,7 @@
 #include "BsGpuProgramManager.h"
 #include "BsD3D9HLSLParamParser.h"
 #include "BsD3D9GpuProgramRTTI.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -195,6 +196,7 @@ namespace BansheeEngine
 			SAFE_RELEASE(constTable);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
 		GpuProgram::initialize_internal();
 	}
 
@@ -202,6 +204,7 @@ namespace BansheeEngine
 	{
 		SAFE_RELEASE(mMicrocode);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
 		GpuProgram::destroy_internal();
 	}
 

+ 15 - 0
BansheeD3D9RenderSystem/Source/BsD3D9IndexBuffer.cpp

@@ -5,6 +5,7 @@
 #include "BsD3D9RenderSystem.h"
 #include "BsD3D9Device.h"
 #include "BsD3D9ResourceManager.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -37,6 +38,7 @@ namespace BansheeEngine
 			}
 		}	
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBuffer::initialize_internal();
 	}
 
@@ -59,6 +61,7 @@ namespace BansheeEngine
 		if(mSystemMemoryBuffer != nullptr)
 			bs_free(mSystemMemoryBuffer);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_IndexBuffer);
 		IndexBuffer::destroy_internal();
 	}
 
@@ -66,6 +69,18 @@ namespace BansheeEngine
     {		
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
+		}
+#endif
+
 		if (options != GBL_READ_ONLY)
 		{
 			for (auto& bufferResourcesPair : mMapDeviceToBufferResources)

+ 7 - 0
BansheeD3D9RenderSystem/Source/BsD3D9OcclusionQuery.cpp

@@ -1,5 +1,6 @@
 #include "BsD3D9OcclusionQuery.h"
 #include "BsD3D9RenderSystem.h"
+#include "BsRenderStats.h"
 #include "BsMath.h"
 
 namespace BansheeEngine
@@ -25,11 +26,14 @@ namespace BansheeEngine
 		{
 			BS_EXCEPT(RenderingAPIException, "Failed to create an occlusion query.");
 		}
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	void D3D9OcclusionQuery::releaseQuery()
 	{
 		SAFE_RELEASE(mQuery);
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D9OcclusionQuery::begin()
@@ -56,6 +60,9 @@ namespace BansheeEngine
 		if (mQuery == nullptr)
 			return mQueryIssued; // If we lost the query, return as ready if it was ever issued
 
+		if (!mQueryIssued)
+			return false;
+
 		BOOL queryData;
 		return mQuery->GetData(&queryData, sizeof(BOOL), 0) == S_OK;
 	}

+ 13 - 0
BansheeD3D9RenderSystem/Source/BsD3D9PixelBuffer.cpp

@@ -4,6 +4,7 @@
 #include "BsException.h"
 #include "BsBitwise.h"
 #include "BsRenderSystem.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -216,6 +217,18 @@ namespace BansheeEngine
 	{	
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
+		}
+#endif
+
 		DWORD flags = 0;
 		switch(options)
 		{

+ 21 - 20
BansheeD3D9RenderSystem/Source/BsD3D9RenderSystem.cpp

@@ -28,6 +28,7 @@
 #include "BsCoreThread.h"
 #include "BsD3D9QueryManager.h"
 #include "BsDebug.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -234,7 +235,7 @@ namespace BansheeEngine
 		for (unsigned int nStage=0; nStage < 8; ++nStage)
 			setTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage);
 
-		mRenderStats.numGpuProgramBinds++;
+		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 
 		RenderSystem::bindGpuProgram(prg);
 	}
@@ -262,7 +263,7 @@ namespace BansheeEngine
 			break;
 		};
 
-		mRenderStats.numGpuProgramBinds++;
+		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 
 		RenderSystem::unbindGpuProgram(gptype);
 	}
@@ -427,7 +428,7 @@ namespace BansheeEngine
 			bs_free<ScratchAlloc>(curBufferData.second);
 		}
 
-		mRenderStats.numGpuParamBufferBinds++;
+		BS_INC_RENDER_STAT(NumGpuParamBufferBinds);
 	}
 
 	void D3D9RenderSystem::setTexture(GpuProgramType gptype, UINT16 unit, bool enabled, const TexturePtr& tex)
@@ -476,8 +477,8 @@ namespace BansheeEngine
 					setSamplerState(static_cast<DWORD>(unit), D3DSAMP_SRGBTEXTURE, FALSE);
 				}
 
-				mRenderStats.numTextureBinds++;
-				mRenderStats.numSamplerBinds++;
+				BS_INC_RENDER_STAT(NumTextureBinds);
+				BS_INC_RENDER_STAT(NumSamplerBinds);
 			}
 		}
 		else
@@ -491,7 +492,7 @@ namespace BansheeEngine
 					BS_EXCEPT(RenderingAPIException, str);
 				}
 
-				mRenderStats.numTextureBinds++;
+				BS_INC_RENDER_STAT(NumTextureBinds);
 			}
 
 			hr = setTextureStageState(static_cast<DWORD>(unit), D3DTSS_COLOROP, D3DTOP_DISABLE);
@@ -542,7 +543,7 @@ namespace BansheeEngine
 		// Set border color
 		setTextureBorderColor(unit, state->getBorderColor());
 
-		mRenderStats.numSamplerBinds++;
+		BS_INC_RENDER_STAT(NumSamplerBinds);
 	}
 
 	void D3D9RenderSystem::setBlendState(const BlendStatePtr& blendState)
@@ -568,7 +569,7 @@ namespace BansheeEngine
 		UINT8 writeMask = blendState->getRenderTargetWriteMask(0);
 		setColorBufferWriteEnabled((writeMask & 0x1) != 0, (writeMask & 0x2) != 0, (writeMask & 0x4) != 0, (writeMask & 0x8) != 0);
 
-		mRenderStats.numBlendStateChanges++;
+		BS_INC_RENDER_STAT(NumBlendStateChanges);
 	}
 
 	void D3D9RenderSystem::setRasterizerState(const RasterizerStatePtr& rasterizerState)
@@ -587,7 +588,7 @@ namespace BansheeEngine
 
 		setAntialiasedLineEnable(rasterizerState->getAntialiasedLineEnable());
 
-		mRenderStats.numRasterizerStateChanges++;
+		BS_INC_RENDER_STAT(NumRasterizerStateChanges);
 	}
 
 	void D3D9RenderSystem::setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue)
@@ -614,7 +615,7 @@ namespace BansheeEngine
 		// Set stencil ref value
 		setStencilRefValue(stencilRefValue);
 
-		mRenderStats.numDepthStencilStateChanges++;
+		BS_INC_RENDER_STAT(NumDepthStencilStateChanges);
 	}
 
 	void D3D9RenderSystem::setTextureMipmapBias(UINT16 unit, float bias)
@@ -1067,7 +1068,7 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Failed to setDepthStencil : " + msg);
 		}
 
-		mRenderStats.numRenderTargetChanges++;
+		BS_INC_RENDER_STAT(NumRenderTargetChanges);
 	}
 
 	void D3D9RenderSystem::setViewport(Viewport vp)
@@ -1181,7 +1182,7 @@ namespace BansheeEngine
 			if (FAILED(hr))
 				BS_EXCEPT(RenderingAPIException, "Unable to set D3D9 stream source for buffer binding");
 
-			mRenderStats.numVertexBufferBinds++;
+			BS_INC_RENDER_STAT(NumVertexBufferBinds);
 		}
 	}
 
@@ -1195,7 +1196,7 @@ namespace BansheeEngine
 		if (FAILED(hr))
 			BS_EXCEPT(RenderingAPIException, "Failed to set index buffer");
 
-		mRenderStats.numIndexBufferBinds++;
+		BS_INC_RENDER_STAT(NumIndexBufferBinds);
 	}
 
 	void D3D9RenderSystem::setDrawOperation(DrawOperationType op)
@@ -1217,9 +1218,9 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Failed to DrawPrimitive : " + msg);
 		}
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += primCount;
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
 	}
 
 	void D3D9RenderSystem::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount)
@@ -1242,9 +1243,9 @@ namespace BansheeEngine
 			BS_EXCEPT(RenderingAPIException, "Failed to DrawIndexedPrimitive : " + msg);
 		}
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += primCount;
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
 	}
 
 	void D3D9RenderSystem::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
@@ -1390,7 +1391,7 @@ namespace BansheeEngine
 			}
 		}
 
-		mRenderStats.numClears++;
+		BS_INC_RENDER_STAT(NumClears);
 	}
 
 	IDirect3D9*	D3D9RenderSystem::getDirect3D9()

+ 3 - 0
BansheeD3D9RenderSystem/Source/BsD3D9Texture.cpp

@@ -9,6 +9,7 @@
 #include "BsD3D9Device.h"
 #include "BsD3D9DeviceManager.h"
 #include "BsD3D9ResourceManager.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -34,6 +35,7 @@ namespace BansheeEngine
 			createInternalResources(d3d9Device);
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
 		Texture::initialize_internal();
 	}
 
@@ -61,6 +63,7 @@ namespace BansheeEngine
 
 		clearBufferViews();
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
 		Texture::destroy_internal();
 	}
 

+ 8 - 0
BansheeD3D9RenderSystem/Source/BsD3D9TimerQuery.cpp

@@ -1,5 +1,6 @@
 #include "BsD3D9TimerQuery.h"
 #include "BsD3D9RenderSystem.h"
+#include "BsRenderStats.h"
 #include "BsDebug.h"
 
 namespace BansheeEngine
@@ -9,11 +10,15 @@ namespace BansheeEngine
 		mEndQuery(nullptr), mDisjointQuery(nullptr), mTimeDelta(0.0f), mDevice(nullptr)
 	{
 		createQuery();
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	D3D9TimerQuery::~D3D9TimerQuery()
 	{
 		releaseQuery();
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void D3D9TimerQuery::createQuery()
@@ -90,6 +95,9 @@ namespace BansheeEngine
 		if (!isQueryValid()) // Possibly device reset, in which case query is considered done if issued
 			return mQueryIssued;
 
+		if (!mQueryIssued)
+			return false;
+
 		BOOL queryData;
 		return mDisjointQuery->GetData(&queryData, sizeof(BOOL), 0) == S_OK;
 	}

+ 15 - 1
BansheeD3D9RenderSystem/Source/BsD3D9VertexBuffer.cpp

@@ -5,6 +5,7 @@
 #include "BsD3D9RenderSystem.h"
 #include "BsD3D9Device.h"
 #include "BsD3D9ResourceManager.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -37,6 +38,7 @@ namespace BansheeEngine
 			}
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
 		VertexBuffer::initialize_internal();
 	}
 
@@ -59,6 +61,7 @@ namespace BansheeEngine
 		if (mSystemMemoryBuffer != nullptr)
 			bs_free(mSystemMemoryBuffer);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexBuffer);
 		VertexBuffer::destroy_internal();
 	}
 
@@ -66,6 +69,18 @@ namespace BansheeEngine
     {		
 		D3D9_DEVICE_ACCESS_CRITICAL_SECTION
 
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
+		}
+#endif
+
 		if (options != GBL_READ_ONLY)
 		{
 			for (auto& bufferResourcesPair : mMapDeviceToBufferResources)
@@ -114,7 +129,6 @@ namespace BansheeEngine
         void* pSrc = this->lock(offset, length, GBL_READ_ONLY);
         memcpy(dest, pSrc, length);
         this->unlock();
-
     }
 
 	void D3D9VertexBuffer::writeData(UINT32 offset, UINT32 length, const void* source, 

+ 4 - 0
BansheeD3D9RenderSystem/Source/BsD3D9VertexDeclaration.cpp

@@ -3,6 +3,7 @@
 #include "BsException.h"
 #include "BsD3D9RenderSystem.h"
 #include "BsD3D9ResourceManager.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -17,6 +18,7 @@ namespace BansheeEngine
 	{
 		releaseDeclaration();
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexDeclaration);
 		VertexDeclaration::destroy_internal();
 	}
 
@@ -88,6 +90,8 @@ namespace BansheeEngine
 			bs_deleteN<PoolAlloc>(d3delems, (UINT32)(mElementList.size() + 1));
 
 			mMapDeviceToDeclaration[pCurDevice] = lpVertDecl;
+
+			BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexDeclaration);
 		}
 
 		// Declaration already exits.

+ 1 - 0
BansheeEditor/Include/BsMainEditorWindow.h

@@ -22,6 +22,7 @@ namespace BansheeEngine
 	protected:
 		GUIMenuBar* mMenuBar;
 		DockManager* mDockManager;
+		HProfilerOverlay mProfilerOverlay;
 
 		virtual void resized();
 

+ 2 - 5
BansheeEditor/Source/BsMainEditorWindow.cpp

@@ -77,14 +77,12 @@ namespace BansheeEngine
 		AABox dbgBox(Vector3(-300, -200, 1000), Vector3(300, 300, 1500));
 		//DrawHelper3D::instance().drawAABox(sceneCamera, dbgBox, Color::Green, 250.0f);
 
-		ProfilerOverlay::startUp(sceneCamera->getViewport());
-		ProfilerOverlay::instance().show(ProfilerOverlayType::CPUSamples);
+		mProfilerOverlay = mSceneObject->addComponent<ProfilerOverlay>(sceneCamera->getViewport());
+		mProfilerOverlay->show(ProfilerOverlayType::CPUSamples);
 	}
 
 	MainEditorWindow::~MainEditorWindow()
 	{
-		ProfilerOverlay::shutDown();
-
 		GUIElement::destroy(mDockManager);
 		bs_delete(mMenuBar);
 	}
@@ -111,6 +109,5 @@ namespace BansheeEngine
 	void MainEditorWindow::update()
 	{
 		mDockManager->update();
-		//PROFILE_CALL(ProfilerOverlay::instance().update(), "ProfilerOverlay");
 	}
 }

+ 2 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -75,6 +75,7 @@ namespace BansheeEngine
 	class GUIDropDownHitBox;
 	class RenderableProxy;
 	class RenderableHandler;
+	class ProfilerOverlay;
 
 	// 2D
 	class TextSprite;
@@ -98,6 +99,7 @@ namespace BansheeEngine
 	typedef GameObjectHandle<GUIWidget> HGUIWidget;
 	typedef GameObjectHandle<Camera> HCamera;
 	typedef GameObjectHandle<Renderable> HRenderable;
+	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
 
 	typedef ResourceHandle<SpriteTexture> HSpriteTexture;
 

+ 4 - 3
BansheeEngine/Include/BsProfilerOverlay.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "BsComponent.h"
 #include "BsProfilerGPU.h"
 #include "BsModule.h"
 #include "BsEvent.h"
@@ -13,7 +14,7 @@ namespace BansheeEngine
 		GPUSamples
 	};
 
-	class BS_EXPORT ProfilerOverlay : public Module<ProfilerOverlay>
+	class BS_EXPORT ProfilerOverlay : public Component
 	{
 	public:
 		struct BasicRow
@@ -63,7 +64,7 @@ namespace BansheeEngine
 		};
 
 	public:
-		ProfilerOverlay(const ViewportPtr& target);
+		ProfilerOverlay(const HSceneObject& parent, const ViewportPtr& target);
 		~ProfilerOverlay();
 
 		void setTarget(const ViewportPtr& target);
@@ -72,7 +73,7 @@ namespace BansheeEngine
 		void hide();
 
 		/**
-		 * @brief	Called every frame. Internal method.
+		 * @copydoc	Component::update
 		 */
 		void update();
 	private:

+ 19 - 9
BansheeEngine/Source/BsProfilerOverlay.cpp

@@ -282,8 +282,8 @@ namespace BansheeEngine
 
 	const UINT32 ProfilerOverlay::MAX_DEPTH = 4;
 
-	ProfilerOverlay::ProfilerOverlay(const ViewportPtr& target)
-		:mIsShown(false), mType(ProfilerOverlayType::CPUSamples)
+	ProfilerOverlay::ProfilerOverlay(const HSceneObject& parent, const ViewportPtr& target)
+		:Component(parent), mIsShown(false), mType(ProfilerOverlayType::CPUSamples)
 	{
 		setTarget(target);
 	}
@@ -394,7 +394,7 @@ namespace BansheeEngine
 		mGPUClearsStr = HString(L"__ProfOvClears", L"Clears: {0}");
 		mGPUVerticesStr = HString(L"__ProfOvVertices", L"Num. vertices: {0}");
 		mGPUPrimitivesStr = HString(L"__ProfOvPrimitives", L"Num. primitives: {0}");
-		mGPUSamplesStr = HString(L"__ProfOvSamples", L"Samples: {0}");
+		mGPUSamplesStr = HString(L"__ProfOvSamples", L"Samples drawn: {0}");
 		mGPUBlendStateChangesStr = HString(L"__ProfOvBSChanges", L"Blend state changes: {0}");
 		mGPURasterStateChangesStr = HString(L"__ProfOvRSChanges", L"Rasterizer state changes: {0}");
 		mGPUDepthStencilStateChangesStr = HString(L"__ProfOvDSSChanges", L"Depth/stencil state changes: {0}");
@@ -438,24 +438,37 @@ namespace BansheeEngine
 
 		updateCPUSampleAreaSizes();
 		updateGPUSampleAreaSizes();
+
+		if (!mIsShown)
+			hide();
+		else
+		{
+			if (mType == ProfilerOverlayType::CPUSamples)
+				show(ProfilerOverlayType::CPUSamples);
+			else
+				show(ProfilerOverlayType::GPUSamples);
+		}
 	}
 
 	void ProfilerOverlay::show(ProfilerOverlayType type)
 	{
-		if(mIsShown && mType == type)
-			return;
-
 		if (type == ProfilerOverlayType::CPUSamples)
 		{
 			mCPUBasicAreaLabels->enable();
 			mCPUPreciseAreaLabels->enable();
 			mCPUBasicAreaContents->enable();
 			mCPUPreciseAreaContents->enable();
+			mGPUAreaFrameContents->disable();
+			mGPUAreaFrameSamples->disable();
 		}
 		else
 		{
 			mGPUAreaFrameContents->enable();
 			mGPUAreaFrameSamples->enable();
+			mCPUBasicAreaLabels->disable();
+			mCPUPreciseAreaLabels->disable();
+			mCPUBasicAreaContents->disable();
+			mCPUPreciseAreaContents->disable();
 		}
 
 		mType = type;
@@ -464,9 +477,6 @@ namespace BansheeEngine
 
 	void ProfilerOverlay::hide()
 	{
-		if(!mIsShown)
-			return;
-
 		mCPUBasicAreaLabels->disable();
 		mCPUPreciseAreaLabels->disable();
 		mCPUBasicAreaContents->disable();

+ 5 - 0
BansheeGLRenderSystem/Include/BsGLGpuBuffer.h

@@ -51,6 +51,11 @@ namespace BansheeEngine
 		 */
 		void initialize_internal();	
 
+		/**
+		 * @copydoc GpuBuffer::destroy_internal
+		 */
+		void destroy_internal();	
+
 		/**
 		 * @copydoc GpuBuffer::createView
 		 */

+ 1 - 0
BansheeGLRenderSystem/Include/BsGLOcclusionQuery.h

@@ -46,6 +46,7 @@ namespace BansheeEngine
 	private:
 		GLuint mQueryObj;
 		bool mFinalized;
+		bool mEndIssued;
 
 		UINT32 mNumSamples;
 	};

+ 13 - 0
BansheeGLRenderSystem/Include/BsGLPrerequisites.h

@@ -25,10 +25,23 @@ namespace BansheeEngine
 	typedef std::shared_ptr<GLGpuParamBlock> GLGpuParamBlockPtr;
 	typedef std::shared_ptr<GLSLGpuProgram> GLSLGpuProgramPtr;
 
+	/**
+	 * @brief	Type IDs used for RTTI.
+	 */
 	enum TypeID_D3D9
 	{
 		TID_GL_GLSLGpuProgram = 11000
 	};
+
+	/**
+	 * @brief	OpenGL specific types to track resource statistics for.
+	 */
+	enum GLRenderStatResourceType
+	{
+		RenderStatObject_PipelineObject = 100,
+		RenderStatObject_FrameBufferObject,
+		RenderStatObject_VertexArrayObject
+	};
 }
 
 #if BS_THREAD_SUPPORT == 1

+ 1 - 0
BansheeGLRenderSystem/Include/BsGLTimerQuery.h

@@ -47,6 +47,7 @@ namespace BansheeEngine
 		GLuint mQueryStartObj;
 		GLuint mQueryEndObj;
 		bool mFinalized;
+		bool mEndIssued;
 
 		float mTimeDelta;
 	};

+ 3 - 0
BansheeGLRenderSystem/Source/BsGLEventQuery.cpp

@@ -1,4 +1,5 @@
 #include "BsGLEventQuery.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -6,11 +7,13 @@ namespace BansheeEngine
 		:mQueryObj(0)
 	{
 		glGenQueries(1, &mQueryObj);
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	GLEventQuery::~GLEventQuery()
 	{
 		glDeleteQueries(1, &mQueryObj);
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void GLEventQuery::begin()

+ 5 - 1
BansheeGLRenderSystem/Source/BsGLFrameBufferObject.cpp

@@ -2,6 +2,7 @@
 #include "BsGLPixelFormat.h"
 #include "BsGLPixelBuffer.h"
 #include "BsGLRenderTexture.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -11,11 +12,14 @@ namespace BansheeEngine
 
         for(UINT32 x = 0; x < BS_MAX_MULTIPLE_RENDER_TARGETS; ++x)
             mColor[x].buffer = nullptr;
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_FrameBufferObject);
     }
 
     GLFrameBufferObject::~GLFrameBufferObject()
     {
-        glDeleteFramebuffersEXT(1, &mFB);        
+        glDeleteFramebuffersEXT(1, &mFB);    
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_FrameBufferObject);
     }
 
     void GLFrameBufferObject::bindSurface(UINT32 attachment, const GLSurfaceDesc &target)

+ 22 - 0
BansheeGLRenderSystem/Source/BsGLGpuBuffer.cpp

@@ -1,5 +1,6 @@
 #include "BsGLGpuBuffer.h"
 #include "BsDebug.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -16,11 +17,30 @@ namespace BansheeEngine
 	{
 		LOGWRN("Generic buffers are not supported in OpenGL. Creating a dummy buffer. All operations on it will either be no-op or return a nullptr.");
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuBuffer);
 		GpuBuffer::initialize_internal();
 	}
 
+	void GLGpuBuffer::destroy_internal()
+	{
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuBuffer);
+		GpuBuffer::destroy_internal();
+	}
+
 	void* GLGpuBuffer::lock(UINT32 offset, UINT32 length, GpuLockOptions options)
 	{
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
+		}
+#endif
+
 		return nullptr;
 	}
 
@@ -30,10 +50,12 @@ namespace BansheeEngine
 
 	void GLGpuBuffer::readData(UINT32 offset, UINT32 length, void* pDest)
 	{
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuBuffer);
 	}
 
 	void GLGpuBuffer::writeData(UINT32 offset, UINT32 length, const void* pSource, BufferWriteType writeFlags)
 	{
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuBuffer);
 	}
 
 	void GLGpuBuffer::copyData(GpuBuffer& srcBuffer, UINT32 srcOffset, 

+ 7 - 0
BansheeGLRenderSystem/Source/BsGLGpuParamBlockBuffer.cpp

@@ -1,4 +1,5 @@
 #include "BsGLGpuParamBlockBuffer.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine
@@ -21,6 +22,7 @@ namespace BansheeEngine
 
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuParamBuffer);
 		GpuParamBlockBuffer::initialize_internal();
 	}
 
@@ -28,6 +30,7 @@ namespace BansheeEngine
 	{
 		glDeleteBuffers(1, &mGLHandle);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuParamBuffer);
 		GpuParamBlockBuffer::destroy_internal();
 	}
 
@@ -36,6 +39,8 @@ namespace BansheeEngine
 		glBindBuffer(GL_UNIFORM_BUFFER, mGLHandle);
 		glBufferSubData(GL_UNIFORM_BUFFER, 0 , mSize, data);
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_GpuParamBuffer);
 	}
 
 	void GLGpuParamBlockBuffer::readData(UINT8* data) const
@@ -43,5 +48,7 @@ namespace BansheeEngine
 		glBindBuffer(GL_UNIFORM_BUFFER, mGLHandle);
 		glGetBufferSubData(GL_UNIFORM_BUFFER, 0 , mSize, (GLvoid*)data);
 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
+
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_GpuParamBuffer);
 	}
 }

+ 15 - 0
BansheeGLRenderSystem/Source/BsGLIndexBuffer.cpp

@@ -1,5 +1,6 @@
 #include "BsGLIndexBuffer.h"
 #include "BsGLHardwareBufferManager.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine 
@@ -26,6 +27,7 @@ namespace BansheeEngine
 		glBufferData(GL_ELEMENT_ARRAY_BUFFER, mSizeInBytes, NULL, 
 			GLHardwareBufferManager::getGLUsage(mUsage));
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_IndexBuffer);
 		IndexBuffer::initialize_internal();
 	}
 
@@ -33,6 +35,7 @@ namespace BansheeEngine
 	{
 		glDeleteBuffers(1, &mBufferId);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_IndexBuffer);
 		IndexBuffer::destroy_internal();
 	}
 
@@ -45,6 +48,18 @@ namespace BansheeEngine
                 "Invalid attempt to lock an index buffer that has already been locked");
         }
 
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_IndexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_IndexBuffer);
+		}
+#endif
+
 		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mBufferId);
 
 		if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))

+ 12 - 1
BansheeGLRenderSystem/Source/BsGLOcclusionQuery.cpp

@@ -1,17 +1,21 @@
 #include "BsGLOcclusionQuery.h"
 #include "BsMath.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
 	GLOcclusionQuery::GLOcclusionQuery(bool binary)
-		:OcclusionQuery(binary), mQueryObj(0), mNumSamples(0), mFinalized(false)
+		:OcclusionQuery(binary), mQueryObj(0), 
+		mNumSamples(0), mFinalized(false), mEndIssued(false)
 	{
 		glGenQueries(1, &mQueryObj);
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	GLOcclusionQuery::~GLOcclusionQuery()
 	{
 		glDeleteQueries(1, &mQueryObj);
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void GLOcclusionQuery::begin()
@@ -19,16 +23,23 @@ namespace BansheeEngine
 		glBeginQuery(mBinary ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED, mQueryObj);
 
 		mNumSamples = 0;
+		mEndIssued = false;
 		setActive(true);
 	}
 
 	void GLOcclusionQuery::end()
 	{
 		glEndQuery(mBinary ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED);
+
+		mEndIssued = true;
+		mFinalized = false;
 	}
 
 	bool GLOcclusionQuery::isReady() const
 	{
+		if (!mEndIssued)
+			return false;
+
 		GLint done = 0;
 		glGetQueryObjectiv(mQueryObj, GL_QUERY_RESULT_AVAILABLE, &done);
 

+ 5 - 0
BansheeGLRenderSystem/Source/BsGLPixelBuffer.cpp

@@ -5,6 +5,7 @@
 #include "BsException.h"
 #include "BsBitwise.h"
 #include "BsGLRenderTexture.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -267,6 +268,8 @@ namespace BansheeEngine
 		glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
 		glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
 		glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+		BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
 	}
 
 	void GLTextureBuffer::download(const PixelData &data)
@@ -315,6 +318,8 @@ namespace BansheeEngine
 			glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
 			glPixelStorei(GL_PACK_ALIGNMENT, 4);
 		}
+
+		BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
 	}
 
 	void GLTextureBuffer::bindToFramebuffer(GLenum attachment, UINT32 zoffset)

+ 24 - 18
BansheeGLRenderSystem/Source/BsGLRenderSystem.cpp

@@ -23,6 +23,7 @@
 #include "BsCoreThread.h"
 #include "BsGLQueryManager.h"
 #include "BsDebug.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -303,7 +304,7 @@ namespace BansheeEngine
 
 			blockBinding++;
 
-			mRenderStats.numGpuParamBufferBinds++;
+			BS_INC_RENDER_STAT(NumGpuParamBufferBinds);
 		}
 
 		bool hasBoundAtLeastOne = false;
@@ -388,7 +389,7 @@ namespace BansheeEngine
 		}
 
 		if (hasBoundAtLeastOne)
-			mRenderStats.numGpuParamBufferBinds++;
+			BS_INC_RENDER_STAT(NumGpuParamBufferBinds);
 
 		if(uniformBufferData != nullptr)
 		{
@@ -424,7 +425,7 @@ namespace BansheeEngine
 
 		activateGLTextureUnit(0);
 
-		mRenderStats.numTextureBinds++;
+		BS_INC_RENDER_STAT(NumTextureBinds);
 	}
 
 	void GLRenderSystem::setSamplerState(GpuProgramType gptype, UINT16 unit, const SamplerStatePtr& state)
@@ -451,7 +452,7 @@ namespace BansheeEngine
 		// Set border color
 		setTextureBorderColor(unit, state->getBorderColor());
 
-		mRenderStats.numSamplerBinds++;
+		BS_INC_RENDER_STAT(NumSamplerBinds);
 	}
 
 	void GLRenderSystem::setBlendState(const BlendStatePtr& blendState)
@@ -477,7 +478,7 @@ namespace BansheeEngine
 		UINT8 writeMask = blendState->getRenderTargetWriteMask(0);
 		setColorBufferWriteEnabled((writeMask & 0x1) != 0, (writeMask & 0x2) != 0, (writeMask & 0x4) != 0, (writeMask & 0x8) != 0);
 
-		mRenderStats.numBlendStateChanges++;
+		BS_INC_RENDER_STAT(NumBlendStateChanges);
 	}
 
 	void GLRenderSystem::setRasterizerState(const RasterizerStatePtr& rasterizerState)
@@ -492,7 +493,7 @@ namespace BansheeEngine
 
 		setScissorTestEnable(rasterizerState->getScissorEnable());
 
-		mRenderStats.numRasterizerStateChanges++;
+		BS_INC_RENDER_STAT(NumRasterizerStateChanges);
 	}
 
 	void GLRenderSystem::setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue)
@@ -518,7 +519,7 @@ namespace BansheeEngine
 		// Set stencil ref value
 		setStencilRefValue(stencilRefValue);
 
-		mRenderStats.numDepthStencilStateChanges++;
+		BS_INC_RENDER_STAT(NumDepthStencilStateChanges);
 	}
 
 	void GLRenderSystem::setViewport(Viewport vp)
@@ -586,7 +587,7 @@ namespace BansheeEngine
 			}
 		}
 
-		mRenderStats.numRenderTargetChanges++;
+		BS_INC_RENDER_STAT(NumRenderTargetChanges);
 	}
 
 	void GLRenderSystem::beginFrame()
@@ -649,9 +650,11 @@ namespace BansheeEngine
 
 		endDraw();
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
+		UINT32 primCount = vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
+
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
 	}
 
 	void GLRenderSystem::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount)
@@ -674,10 +677,13 @@ namespace BansheeEngine
 
 		endDraw();
 
-		mRenderStats.numDrawCalls++;
-		mRenderStats.numVertices += vertexCount;
-		mRenderStats.numPrimitives += vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
-		mRenderStats.numIndexBufferBinds++;
+		UINT32 primCount = vertexCountToPrimCount(mCurrentDrawOperation, vertexCount);
+
+		BS_INC_RENDER_STAT(NumDrawCalls);
+		BS_ADD_RENDER_STAT(NumVertices, vertexCount);
+		BS_ADD_RENDER_STAT(NumPrimitives, primCount);
+
+		BS_INC_RENDER_STAT(NumIndexBufferBinds);
 	}
 
 	void GLRenderSystem::setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom)
@@ -802,7 +808,7 @@ namespace BansheeEngine
 			glStencilMask(mStencilWriteMask);
 		}
 
-		mRenderStats.numClears++;
+		BS_INC_RENDER_STAT(NumClears);
 	}
 
 	/************************************************************************/
@@ -1325,8 +1331,8 @@ namespace BansheeEngine
 		const GLVertexArrayObject& vao = GLVertexArrayObjectManager::instance().getVAO(mCurrentVertexProgram, mBoundVertexDeclaration, mBoundVertexBuffers);
 		glBindVertexArray(vao.getGLHandle()); 
 
-		mRenderStats.numVertexBufferBinds++;
-		mRenderStats.numGpuProgramBinds++;
+		BS_INC_RENDER_STAT(NumVertexBufferBinds);
+		BS_INC_RENDER_STAT(NumGpuProgramBinds);
 	}
 
 	void GLRenderSystem::endDraw()

+ 3 - 1
BansheeGLRenderSystem/Source/BsGLTexture.cpp

@@ -2,12 +2,12 @@
 #include "BsGLSupport.h"
 #include "BsGLPixelFormat.h"
 #include "BsGLPixelBuffer.h"
-
 #include "BsException.h"
 #include "BsBitwise.h"
 #include "BsCoreThread.h"
 #include "BsTextureManager.h"
 #include "BsGLRenderTexture.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -150,6 +150,7 @@ namespace BansheeEngine
 		}
 #endif
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
 		Texture::initialize_internal();
 	}
 
@@ -160,6 +161,7 @@ namespace BansheeEngine
 
 		clearBufferViews();
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
 		Texture::destroy_internal();
 	}
 

+ 13 - 1
BansheeGLRenderSystem/Source/BsGLTimerQuery.cpp

@@ -1,17 +1,20 @@
 #include "BsGLTimerQuery.h"
 #include "BsMath.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
 	GLTimerQuery::GLTimerQuery()
 		:mQueryStartObj(0), mQueryEndObj(0), 
-		mTimeDelta(0.0f), mFinalized(false)
+		mTimeDelta(0.0f), mFinalized(false), mEndIssued(false)
 	{
 		GLuint queries[2];
 		glGenQueries(2, queries);
 
 		mQueryStartObj = queries[0];
 		mQueryEndObj = queries[1];
+
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Query);
 	}
 
 	GLTimerQuery::~GLTimerQuery()
@@ -21,6 +24,8 @@ namespace BansheeEngine
 		queries[1] = mQueryEndObj;
 
 		glDeleteQueries(2, queries);
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Query);
 	}
 
 	void GLTimerQuery::begin()
@@ -28,15 +33,22 @@ namespace BansheeEngine
 		glQueryCounter(mQueryStartObj, GL_TIMESTAMP);
 
 		setActive(true);
+		mEndIssued = false;
 	}
 
 	void GLTimerQuery::end()
 	{
 		glQueryCounter(mQueryEndObj, GL_TIMESTAMP);
+
+		mEndIssued = true;
+		mFinalized = false;
 	}
 
 	bool GLTimerQuery::isReady() const
 	{
+		if (!mEndIssued)
+			return false;
+
 		GLint done = 0;
 		glGetQueryObjectiv(mQueryEndObj, GL_QUERY_RESULT_AVAILABLE, &done);
 

+ 4 - 0
BansheeGLRenderSystem/Source/BsGLVertexArrayObjectManager.cpp

@@ -4,6 +4,7 @@
 #include "BsGLSLGpuProgram.h"
 #include "BsGLHardwareBufferManager.h"
 #include "BsUtil.h"
+#include "BsRenderStats.h"
 
 #define VBO_BUFFER_OFFSET(i) ((char *)NULL + (i))
 
@@ -178,6 +179,7 @@ namespace BansheeEngine
 
 		auto iter = mVAObjects.insert(wantedVAO);
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexArrayObject);
 		return *iter.first;
 	}
 
@@ -192,5 +194,7 @@ namespace BansheeEngine
 
 		glDeleteVertexArrays(1, &vao.mHandle);
 		bs_free(vao.mAttachedBuffers);
+
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexArrayObject);
 	}
 }

+ 15 - 0
BansheeGLRenderSystem/Source/BsGLVertexBuffer.cpp

@@ -1,6 +1,7 @@
 #include "BsGLHardwareBufferManager.h"
 #include "BsGLVertexBuffer.h"
 #include "BsGLVertexArrayObjectManager.h"
+#include "BsRenderStats.h"
 #include "BsException.h"
 
 namespace BansheeEngine 
@@ -30,6 +31,7 @@ namespace BansheeEngine
 		glBufferData(GL_ARRAY_BUFFER, mSizeInBytes, NULL,
 			GLHardwareBufferManager::getGLUsage(mUsage));
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_VertexBuffer);
 		VertexBuffer::initialize_internal();
 	}
 
@@ -40,6 +42,7 @@ namespace BansheeEngine
 		while (mVAObjects.size() > 0)
 			GLVertexArrayObjectManager::instance().notifyBufferDestroyed(mVAObjects[0]);
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_VertexBuffer);
 		VertexBuffer::destroy_internal();
 	}
 
@@ -66,6 +69,18 @@ namespace BansheeEngine
                 "Invalid attempt to lock a vertex buffer that has already been locked");
         }
 
+#if BS_PROFILING_ENABLED
+		if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_VertexBuffer);
+		}
+
+		if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
+		{
+			BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_VertexBuffer);
+		}
+#endif
+
 		glBindBuffer(GL_ARRAY_BUFFER, mBufferId);
 
 		if ((options == GBL_WRITE_ONLY) || (options == GBL_WRITE_ONLY_NO_OVERWRITE) || (options == GBL_WRITE_ONLY_DISCARD))

+ 2 - 0
BansheeGLRenderSystem/Source/GLSL/include/BsGLSLProgramPipelineManager.h

@@ -23,6 +23,8 @@ namespace BansheeEngine
 	class GLSLProgramPipelineManager
 	{
 	public:
+		~GLSLProgramPipelineManager();
+
 		/**
 		 * @brief	Creates or returns an existing pipeline that uses the provided combination of GPU programs. Provide
 		 *			null for unused programs.

+ 3 - 0
BansheeGLRenderSystem/Source/GLSL/src/BsGLSLGpuProgram.cpp

@@ -6,6 +6,7 @@
 #include "BsGLSLParamParser.h"
 #include "BsHardwareBufferManager.h"
 #include "BsGLSLGpuProgramRTTI.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine 
 {
@@ -131,6 +132,7 @@ namespace BansheeEngine
 			}
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_GpuProgram);
 		GpuProgram::initialize_internal();
 	}
 
@@ -142,6 +144,7 @@ namespace BansheeEngine
 			mGLHandle = 0;
 		}
 
+		BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_GpuProgram);
 		GpuProgram::destroy_internal();
 	}
 

+ 11 - 0
BansheeGLRenderSystem/Source/GLSL/src/BsGLSLProgramPipelineManager.cpp

@@ -1,5 +1,6 @@
 #include "BsGLSLProgramPipelineManager.h"
 #include "BsGLSLGpuProgram.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
@@ -30,6 +31,15 @@ namespace BansheeEngine
 			a.hullProgKey == b.hullProgKey && a.domainProgKey == b.domainProgKey;
 	}
 
+	GLSLProgramPipelineManager::~GLSLProgramPipelineManager()
+	{
+		for (auto& pipeline : mPipelines)
+		{
+			glDeleteProgramPipelines(1, &pipeline.second.glHandle);
+			BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_PipelineObject);
+		}
+	}
+
 	const GLSLProgramPipeline* GLSLProgramPipelineManager::getPipeline(GLSLGpuProgram* vertexProgram, GLSLGpuProgram* fragmentProgram, 
 		GLSLGpuProgram* geometryProgram, GLSLGpuProgram* hullProgram, GLSLGpuProgram* domainProgram)
 	{
@@ -75,6 +85,7 @@ namespace BansheeEngine
 
 			mPipelines[key] = newPipeline;
 
+			BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_PipelineObject);
 			return &mPipelines[key];
 		}
 		else

+ 12 - 0
BansheeUtility/Include/BsModule.h

@@ -143,18 +143,30 @@ namespace BansheeEngine
 		 */
 		virtual void onShutDown() {}
 
+		/**
+		 * @brief	Returns a singleton instance of this module. Throws an exception
+		 *			if module is not yet initialized.
+		 */
 		static T*& _instance()
 		{
 			static T* inst = nullptr;
 			return inst;
 		}
 
+		/**
+		 * @brief	Checks has the Module been shut down.
+		 *			
+		 * @note	If module was never even started, this will return false.
+		 */
 		static bool& isDestroyed()
 		{
 			static bool inst = false;
 			return inst;
 		}
 
+		/**
+		 * @brief	Checks has the Module been started up.
+		 */
 		static bool& isShutDown()
 		{
 			static bool inst = true;

+ 52 - 6
ExampleProject/Main/Main.cpp

@@ -26,6 +26,7 @@
 #include "BsRenderWindow.h"
 #include "BsSceneObject.h"
 #include "BsCoreThread.h"
+#include "BsProfilerOverlay.h"
 
 namespace BansheeEngine
 {
@@ -46,6 +47,13 @@ namespace BansheeEngine
 	HGpuProgram exampleVertexGPUProg;
 
 	HCamera sceneCamera;
+	HProfilerOverlay profilerOverlay;
+
+	VirtualButton toggleCPUProfilerBtn;
+	VirtualButton toggleGPUProfilerBtn;
+
+	bool cpuProfilerActive = false;
+	bool gpuProfilerActive = false;
 
 	void toggleFullscreen()
 	{
@@ -64,6 +72,38 @@ namespace BansheeEngine
 		fullscreen = !fullscreen;
 	}
 
+	void buttonUp(const VirtualButton& button)
+	{
+		if (button == toggleCPUProfilerBtn)
+		{
+			if (cpuProfilerActive)
+			{
+				profilerOverlay->hide();
+				cpuProfilerActive = false;
+			}
+			else
+			{
+				profilerOverlay->show(ProfilerOverlayType::CPUSamples);
+				cpuProfilerActive = true;
+				gpuProfilerActive = false;
+			}
+		}
+		else if (button == toggleGPUProfilerBtn)
+		{
+			if (gpuProfilerActive)
+			{
+				profilerOverlay->hide();
+				gpuProfilerActive = false;
+			}
+			else
+			{
+				profilerOverlay->show(ProfilerOverlayType::GPUSamples);
+				gpuProfilerActive = true;
+				cpuProfilerActive = false;
+			}
+		}
+	}
+
 	void setUpExample()
 	{
 		// Import assets
@@ -139,9 +179,13 @@ namespace BansheeEngine
 		inputConfig->registerButton("Right", BC_D);
 		inputConfig->registerButton("Back", BC_S);
 
-		inputConfig->registerButton("SimThreadProfilerOverlay", BC_F1);
-		inputConfig->registerButton("CoreThreadProfilerOverlay", BC_F2);
-		inputConfig->registerButton("GPUProfilerOverlay", BC_F3);
+		inputConfig->registerButton("CPUProfilerOverlay", BC_F1);
+		inputConfig->registerButton("GPUProfilerOverlay", BC_F2);
+
+		toggleCPUProfilerBtn = VirtualButton("CPUProfilerOverlay");
+		toggleGPUProfilerBtn = VirtualButton("GPUProfilerOverlay");
+
+		VirtualInput::instance().onButtonUp.connect(&buttonUp);
 
 		// TODO - Add vertical/horizontal axes here
 
@@ -160,9 +204,8 @@ namespace BansheeEngine
 		GUIArea* topArea = GUIArea::createStretchedXY(*gui, 0, 0, 0, 0);
 		GUILayout& topLayout = topArea->getLayout().addLayoutY();
 
-		topLayout.addElement(GUILabel::create(HString(L"Press F1 to toggle Sim thread profiler overlay")));
-		topLayout.addElement(GUILabel::create(HString(L"Press F2 to toggle Core thread profiler overlay")));
-		topLayout.addElement(GUILabel::create(HString(L"Press F3 to toggle GPU profiler overlay")));
+		topLayout.addElement(GUILabel::create(HString(L"Press F1 to toggle CPU profiler overlay")));
+		topLayout.addElement(GUILabel::create(HString(L"Press F2 to toggle GPU profiler overlay")));
 		topLayout.addFlexibleSpace();
 
 		// Resolution/Camera options GUI
@@ -175,6 +218,9 @@ namespace BansheeEngine
 		toggleFullscreenButton->onClick.connect(&toggleFullscreen);
 		rightLayout.addElement(toggleFullscreenButton);
 
+		// Initialize profiler overlay
+		profilerOverlay = exampleSO->addComponent<ProfilerOverlay>(guiCamera->getViewport());
+
 		// TODO - add ExampleGUI component
 	}
 }