Przeglądaj źródła

GPUProfiler implementation

Marko Pintera 11 lat temu
rodzic
commit
a05f982776

+ 109 - 40
CamelotCore/Include/BsGPUProfiler.h

@@ -2,62 +2,81 @@
 
 #include "CmPrerequisites.h"
 #include "CmModule.h"
+#include "BsRenderStats.h"
 
 namespace BansheeEngine
 {
+	/**
+	* @brief	Contains various profiler statistics about a single GPU profiling sample
+	*/
+	struct GPUProfileSample
+	{
+		String name; /**< Name of the sample for easier identification. */
+		float timeMs; /**< Time in milliseconds it took to execute the sampled block. */
+
+		UINT32 numDrawCalls; /**< Number of draw calls that happened. */
+		UINT32 numRenderTargetChanges; /**< How many times was render target changed. */
+		UINT32 numPresents; /**< How many times did a buffer swap happen on a double buffered render target. */
+		UINT32 numClears; /**< How many times was render target cleared. */
+
+		UINT32 numVertices; /**< Total number of vertices sent to the GPU. */
+		UINT32 numPrimitives; /**< Total number of primitives sent to the GPU. */
+		UINT32 numDrawnSamples; /**< Number of samples drawn by the GPU. */
+
+		UINT32 numBlendStateChanges; /**< How many times did the blend state change. */
+		UINT32 numRasterizerStateChanges; /**< How many times did the rasterizer state change. */
+		UINT32 numDepthStencilStateChanges; /**< How many times did the depth stencil state change. */
+
+		UINT32 numTextureBinds; /**< How many times was a texture bound. */
+		UINT32 numSamplerBinds; /**< How many times was a sampler bound. */
+		UINT32 numVertexBufferBinds; /**< How many times was a vertex buffer bound. */
+		UINT32 numIndexBufferBinds; /**< How many times was an index buffer bound. */
+		UINT32 numGpuParamBufferBinds; /**< How many times was an GPU parameter buffer bound. */
+		UINT32 numGpuProgramBinds; /**< How many times was a GPU program bound. */
+
+		UINT32 numResourceWrites; /**< How many times were GPU resources written to. */
+		UINT32 numResourceReads; /**< How many times were GPU resources read from. */
+
+		UINT32 numObjectsCreated; /**< How many GPU objects were created. */
+		UINT32 numObjectsDestroyed; /**< How many GPU objects were destroyed. */
+	};
+
 	/**
 	 * @brief	Profiler report containing information about GPU sampling data 
 	 *			from a single frame.
 	 */
 	struct GPUProfilerReport
 	{
-		/**
-		 * @brief	Contains various profiler statistics about a single GPU profiling sample
-		 */
-		struct Sample
-		{
-			String name; /**< Name of the sample for easier identification. */
-			float timeMs; /**< Time in milliseconds it took to execute the sampled block. */
-
-			UINT32 numDrawCalls; /**< Number of draw calls that happened. */
-			UINT32 numRenderTargetChanges; /**< How many times was render target changed. */
-			UINT32 numPresents; /**< How many times did a buffer swap happen on a double buffered render target. */
-			UINT32 numClears; /**< How many times was render target cleared. */
-
-			UINT32 numVertices; /**< Total number of vertices sent to the GPU. */
-			UINT32 numTriangles; /**< Total number of triangles sent to the GPU. */
-			UINT32 numDrawnSamples; /**< Number of samples drawn by the GPU. */
-
-			UINT32 numBlendStateChanges; /**< How many times did the blend state change. */
-			UINT32 numRasterizerStateChanges; /**< How many times did the rasterizer state change. */
-			UINT32 numDepthStencilStateChanges; /**< How many times did the depth stencil state change. */
-			
-			UINT32 numTextureBinds; /**< How many times was a texture bound. */
-			UINT32 numSamplerBinds; /**< How many times was a sampler bound. */
-			UINT32 numVertexBufferBinds; /**< How many times was a vertex buffer bound. */
-			UINT32 numIndexBufferBinds; /**< How many times was an index buffer bound. */
-			UINT32 numGpuParamBufferBinds; /**< How many times was an GPU parameter buffer bound. */
-			UINT32 numGpuProgramBinds; /**< How many times was a GPU program bound. */
-
-			UINT32 numResourceWrites; /**< How many times were GPU resources written to. */
-			UINT32 numResourceReads; /**< How many times were GPU resources read from. */
-
-			UINT32 numObjectsCreated; /**< How many GPU objects were created. */
-			UINT32 numObjectsDestroyed; /**< How many GPU objects were destroyed. */
-		};
-
-		Sample frameSample; /**< Sample containing data for entire frame. */
-		Vector<Sample> samples;
+		GPUProfileSample frameSample; /**< Sample containing data for entire frame. */
+		Vector<GPUProfileSample> samples;
 	};
 
 	/**
 	 * @brief	Profiler that measures time and amount of various GPU operations.
 	 *
-	 * @note	Sim thread only. However most operations will be queued on the core thread or
-	 *			on the GPU itself so the results will not be immediately available.
+	 * @note	Core thread only.
 	 */
 	class CM_EXPORT GPUProfiler : public Module<GPUProfiler>
 	{
+	private:
+		struct ActiveSample
+		{
+			ProfilerString sampleName;
+			RenderStats startStats;
+			RenderStats endStats;
+			TimerQueryPtr activeTimeQuery;
+			OcclusionQueryPtr activeOcclusionQuery;
+		};
+
+		struct ActiveFrame
+		{
+			ActiveSample frameSample;
+			Vector<ActiveSample> samples;
+		};
+
+	public:
+		GPUProfiler();
+
 		/**
 		 * @brief	Signals a start of a new frame. Every frame will generate a separate profiling report.
 		 *			This call must be followed by "endFrame", and any sampling operations must happen between
@@ -105,6 +124,56 @@ namespace BansheeEngine
 		 * @brief	Gets the oldest report available and removes it from the internal list.
 		 *			Throws an exception if no reports are available.
 		 */
-		const GPUProfilerReport& getNextReport();
+		GPUProfilerReport getNextReport();
+
+		/**
+		 * @brief	To be called once per frame from the Core thread.
+		 *
+		 * @note	Internal method.
+		 */
+		void _update();
+
+	private:
+		/**
+		 * @brief	Assigns start values for the provided sample.
+		 */
+		void beginSampleInternal(ActiveSample& sample);
+
+		/**
+		 * @brief	Assigns end values for the provided sample.
+		 */
+		void endSampleInternal(ActiveSample& sample);
+
+		/**
+		 * @brief	Creates a new timer query or returns an existing free query.
+		 */
+		TimerQueryPtr getTimerQuery() const;
+
+		/**
+		 * @brief	Creates a new occlusion query or returns an existing free query.
+		 */
+		OcclusionQueryPtr getOcclusionQuery() const;
+
+		/**
+		 * @brief	Interprets the active frame results and generates a profiler report for
+		 *			the frame. Provided frame queries must have finished before calling this.
+		 */
+		GPUProfilerReport resolveFrame(ActiveFrame& frame);
+
+		/**
+		 * @brief	Resolves an active sample and converts it to report sample.
+		 */
+		void resolveSample(const ActiveSample& sample, GPUProfileSample& reportSample);
+
+	private:
+		ActiveFrame mActiveFrame;
+		bool mIsFrameActive;
+		UINT32 mNumActiveSamples;
+
+		Queue<ActiveFrame> mUnresolvedFrames;
+		Queue<GPUProfilerReport> mReadyReports;
+
+		mutable Stack<TimerQueryPtr> mFreeTimerQueries;
+		mutable Stack<OcclusionQueryPtr> mFreeOcclusionQueries;
 	};
 }

+ 3 - 5
CamelotCore/Include/BsRenderStats.h

@@ -12,10 +12,9 @@ namespace BansheeEngine
 	{
 		RenderStats()
 		: numDrawCalls(0), numRenderTargetChanges(0), numPresents(0), numClears(0),
-		  numVertices(0), numPrimitives(0), numDrawnSamples(0), numBlendStateChanges(0),
-		  numRasterizerStateChanges(0), numDepthStencilStateChanges(0), numTextureBinds(0),
-		  numSamplerBinds(0), numVertexBufferBinds(0), numIndexBufferBinds(0), numGpuParamBufferBinds(0),
-		  numGpuProgramBinds(0)
+		  numVertices(0), numPrimitives(0), numBlendStateChanges(0), numRasterizerStateChanges(0), 
+		  numDepthStencilStateChanges(0), numTextureBinds(0), numSamplerBinds(0), numVertexBufferBinds(0), 
+		  numIndexBufferBinds(0), numGpuParamBufferBinds(0), numGpuProgramBinds(0)
 		{ }
 
 		UINT64 numDrawCalls;
@@ -25,7 +24,6 @@ namespace BansheeEngine
 
 		UINT64 numVertices;
 		UINT64 numPrimitives;
-		UINT64 numDrawnSamples; 
 
 		UINT64 numBlendStateChanges; 
 		UINT64 numRasterizerStateChanges; 

+ 7 - 7
CamelotCore/Include/CmOcclusionQuery.h

@@ -5,7 +5,7 @@
 namespace BansheeEngine
 {
 	/**
-	* @brief	Represents a query that counts number of fragments rendered by the GPU
+	* @brief	Represents a query that counts number of samples rendered by the GPU
 	*			while the query is active.
 	*
 	* @note		Core thread only.
@@ -17,7 +17,7 @@ namespace BansheeEngine
 		virtual ~OcclusionQuery() {}
 
 		/**
-		* @brief	Starts the query. Any draw calls after this call will have any rendered fragments
+		* @brief	Starts the query. Any draw calls after this call will have any rendered samples
 		*			counted in the query.
 		*
 		* @note		Place any commands you want to measure after this call. Call "end" when done.
@@ -37,25 +37,25 @@ namespace BansheeEngine
 		virtual bool isReady() const = 0;
 
 		/**
-		 * @brief	Returns the number of fragments that passed the depth and stencil test between
+		 * @brief	Returns the number of samples that passed the depth and stencil test between
 		 *			query start and end.
 		 *
 		 * @note	If the query is binary, this will return 0 or 1. 1 meaning one or more samples were rendered,
 		 *			but will not give you the exact count.
 		 */
-		virtual UINT32 getNumFragments() = 0;
+		virtual UINT32 getNumSamples() = 0;
 
 		/**
 		 * @brief	Triggered when the query has completed. Argument provided
-		 *			is the number of fragments counted by the query.
+		 *			is the number of samples counted by the query.
 		 */
 		Event<void(UINT32)> onComplete;
 
 		/**
 		 * @brief	Creates a new occlusion query. 
 		 *
-		 * @param binary	If query is binary it will not give you an exact count of fragments rendered, but will instead
-		 *					just return 0 (no fragments were rendered) or 1 (one or more fragments were rendered). Binary
+		 * @param binary	If query is binary it will not give you an exact count of samples rendered, but will instead
+		 *					just return 0 (no samples were rendered) or 1 (one or more samples were rendered). Binary
 		 *					queries can return sooner as they potentially do not need to wait until all of the geometry is rendered.
 		 */
 		static OcclusionQueryPtr create(bool binary);

+ 200 - 0
CamelotCore/Source/BsGPUProfiler.cpp

@@ -1 +1,201 @@
 #include "BsGPUProfiler.h"
+#include "CmRenderSystem.h"
+#include "CmTimerQuery.h"
+#include "CmOcclusionQuery.h"
+#include "CmException.h"
+
+namespace BansheeEngine
+{
+	GPUProfiler::GPUProfiler()
+		:mNumActiveSamples(0), mIsFrameActive(false)
+	{ }
+
+	void GPUProfiler::beginFrame()
+	{
+		if (mIsFrameActive)
+			CM_EXCEPT(InvalidStateException, "Cannot begin a frame because another frame is active.");
+
+		mActiveFrame = ActiveFrame();
+
+		mActiveFrame.frameSample.sampleName = "Frame";
+		beginSampleInternal(mActiveFrame.frameSample);
+
+		mIsFrameActive = true;
+	}
+
+	void GPUProfiler::endFrame()
+	{
+		if (mNumActiveSamples > 0)
+			CM_EXCEPT(InvalidStateException, "Attempting to end a frame while a sample is active.");
+
+		if (!mIsFrameActive)
+			return;
+
+		endSampleInternal(mActiveFrame.frameSample);
+
+		mUnresolvedFrames.push(mActiveFrame);
+		mIsFrameActive = false;
+	}
+
+	void GPUProfiler::beginSample(const ProfilerString& name)
+	{
+		if (!mIsFrameActive)
+			CM_EXCEPT(InvalidStateException, "Cannot begin a sample because no frame is active.");
+
+		mActiveFrame.samples.push_back(ActiveSample());
+		ActiveSample& sample = mActiveFrame.samples.back();
+
+		sample.sampleName = name;
+		beginSampleInternal(sample);
+		mNumActiveSamples++;
+	}
+
+	void GPUProfiler::endSample(const ProfilerString& name)
+	{
+		if (mNumActiveSamples == 0)
+			return;
+
+		ActiveSample& sample = mActiveFrame.samples.back();
+		if (sample.sampleName != name)
+		{
+			String errorStr = "Attempting to end a sample that doesn't match. Got: " + 
+				String(name.c_str()) + ". Expected: " + String(sample.sampleName.c_str());
+
+			CM_EXCEPT(InvalidStateException, errorStr);
+		}
+
+		endSampleInternal(sample);
+		mNumActiveSamples--;
+	}
+
+	UINT32 GPUProfiler::getNumAvailableReports()
+	{
+		return (UINT32)mReadyReports.size();
+	}
+
+	GPUProfilerReport GPUProfiler::getNextReport()
+	{
+		if (mReadyReports.empty())
+			CM_EXCEPT(InvalidStateException, "No reports are available.")
+
+		GPUProfilerReport report = mReadyReports.front();
+		mReadyReports.pop();
+
+		return report;
+	}
+
+	void GPUProfiler::_update()
+	{
+		while (!mUnresolvedFrames.empty())
+		{
+			ActiveFrame& frame = mUnresolvedFrames.front();
+
+			// Frame sample timer query is the last query we issued
+			// so if it is complete, we may assume all queries are complete.
+			if (frame.frameSample.activeTimeQuery->isReady())
+			{
+				GPUProfilerReport report = resolveFrame(frame);
+				mUnresolvedFrames.pop();
+
+				mReadyReports.push(report);
+			}
+			else
+				break;
+		}
+	}
+
+	GPUProfilerReport GPUProfiler::resolveFrame(ActiveFrame& frame)
+	{
+		GPUProfilerReport report;
+		
+		resolveSample(frame.frameSample, report.frameSample);
+
+		for (auto& sample : frame.samples)
+		{
+			report.samples.push_back(GPUProfileSample());
+			GPUProfileSample& newSample = report.samples.back();
+
+			resolveSample(sample, newSample);
+		}
+
+		return report;
+	}
+
+	void GPUProfiler::resolveSample(const ActiveSample& sample, GPUProfileSample& reportSample)
+	{
+		reportSample.name = String(sample.sampleName.c_str());
+		reportSample.timeMs = sample.activeTimeQuery->getTimeMs();
+		reportSample.numDrawnSamples = sample.activeOcclusionQuery->getNumSamples();
+
+		reportSample.numDrawCalls = (UINT32)(sample.endStats.numDrawCalls - sample.startStats.numDrawCalls);
+		reportSample.numRenderTargetChanges = (UINT32)(sample.endStats.numRenderTargetChanges - sample.startStats.numRenderTargetChanges);
+		reportSample.numPresents = (UINT32)(sample.endStats.numPresents - sample.startStats.numPresents);
+		reportSample.numClears = (UINT32)(sample.endStats.numClears - sample.startStats.numClears);
+
+		reportSample.numVertices = (UINT32)(sample.endStats.numVertices - sample.startStats.numVertices);
+		reportSample.numPrimitives = (UINT32)(sample.endStats.numPrimitives - sample.startStats.numPrimitives);
+		
+		reportSample.numBlendStateChanges = (UINT32)(sample.endStats.numBlendStateChanges - sample.startStats.numBlendStateChanges);
+		reportSample.numRasterizerStateChanges = (UINT32)(sample.endStats.numRasterizerStateChanges - sample.startStats.numRasterizerStateChanges);
+		reportSample.numDepthStencilStateChanges = (UINT32)(sample.endStats.numDepthStencilStateChanges - sample.startStats.numDepthStencilStateChanges);
+
+		reportSample.numTextureBinds = (UINT32)(sample.endStats.numTextureBinds - sample.startStats.numTextureBinds);
+		reportSample.numSamplerBinds = (UINT32)(sample.endStats.numSamplerBinds - sample.startStats.numSamplerBinds);
+		reportSample.numVertexBufferBinds = (UINT32)(sample.endStats.numVertexBufferBinds - sample.startStats.numVertexBufferBinds);
+		reportSample.numIndexBufferBinds = (UINT32)(sample.endStats.numIndexBufferBinds - sample.startStats.numIndexBufferBinds);
+		reportSample.numGpuParamBufferBinds = (UINT32)(sample.endStats.numGpuParamBufferBinds - sample.startStats.numGpuParamBufferBinds);
+		reportSample.numGpuProgramBinds = (UINT32)(sample.endStats.numGpuProgramBinds - sample.startStats.numGpuProgramBinds);
+
+		reportSample.numResourceWrites = (UINT32)(sample.endStats.numResourceWrites - sample.startStats.numResourceWrites);
+		reportSample.numResourceReads = (UINT32)(sample.endStats.numResourceReads - sample.startStats.numResourceReads);
+
+		reportSample.numObjectsCreated = (UINT32)(sample.endStats.numObjectsCreated - sample.startStats.numObjectsCreated);
+		reportSample.numObjectsDestroyed = (UINT32)(sample.endStats.numObjectsDestroyed - sample.startStats.numObjectsDestroyed);
+
+		mFreeTimerQueries.push(sample.activeTimeQuery);
+		mFreeOcclusionQueries.push(sample.activeOcclusionQuery);
+	}
+
+	void GPUProfiler::beginSampleInternal(ActiveSample& sample)
+	{
+		sample.startStats = RenderSystem::instance().getRenderStats();
+		sample.activeTimeQuery = getTimerQuery();
+		sample.activeTimeQuery->begin();
+
+		sample.activeOcclusionQuery = getOcclusionQuery();
+		sample.activeOcclusionQuery->begin();
+	}
+
+	void GPUProfiler::endSampleInternal(ActiveSample& sample)
+	{
+		sample.endStats = RenderSystem::instance().getRenderStats();
+		sample.activeOcclusionQuery->end();
+		sample.activeTimeQuery->end();
+	}
+
+	TimerQueryPtr GPUProfiler::getTimerQuery() const
+	{
+		if (!mFreeTimerQueries.empty())
+		{
+			TimerQueryPtr timerQuery = mFreeTimerQueries.top();
+			mFreeTimerQueries.pop();
+
+			return timerQuery;
+		}
+
+		return TimerQuery::create();
+	}
+
+	OcclusionQueryPtr GPUProfiler::getOcclusionQuery() const
+	{
+		if (!mFreeOcclusionQueries.empty())
+		{
+			OcclusionQueryPtr occlusionQuery = mFreeOcclusionQueries.top();
+			mFreeOcclusionQueries.pop();
+
+			return occlusionQuery;
+		}
+
+		return OcclusionQuery::create(false);
+	}
+}

+ 1 - 1
CamelotCore/Source/CmQueryManager.cpp

@@ -34,7 +34,7 @@ namespace BansheeEngine
 		{
 			if (query->isActive() && query->isReady())
 			{
-				query->onComplete(query->getNumFragments());
+				query->onComplete(query->getNumSamples());
 				query->setActive(false);
 			}
 		}

+ 2 - 2
CamelotD3D11RenderSystem/Include/CmD3D11OcclusionQuery.h

@@ -32,7 +32,7 @@ namespace BansheeEngine
 		/**
 		* @copydoc OcclusionQuery::getNumFragments
 		*/
-		virtual UINT32 getNumFragments();
+		virtual UINT32 getNumSamples();
 
 	private:
 		friend class QueryManager;
@@ -41,7 +41,7 @@ namespace BansheeEngine
 		ID3D11DeviceContext* mContext;
 		bool mFinalized;
 
-		UINT32 mNumFragments;
+		UINT32 mNumSamples;
 
 		void finalize();
 	};

+ 14 - 14
CamelotD3D11RenderSystem/Source/CmD3D11OcclusionQuery.cpp

@@ -6,7 +6,7 @@
 namespace BansheeEngine
 {
 	D3D11OcclusionQuery::D3D11OcclusionQuery(bool binary)
-		:OcclusionQuery(binary), mContext(nullptr), mQuery(nullptr), mNumFragments(0), mFinalized(false)
+		:OcclusionQuery(binary), mContext(nullptr), mQuery(nullptr), mNumSamples(0), mFinalized(false)
 	{
 		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
 		D3D11Device& device = rs->getPrimaryDevice();
@@ -32,7 +32,7 @@ namespace BansheeEngine
 	{
 		mContext->Begin(mQuery);
 
-		mNumFragments = 0;
+		mNumSamples = 0;
 		setActive(true);
 	}
 
@@ -45,24 +45,24 @@ namespace BansheeEngine
 	{
 		if (mBinary)
 		{
-			BOOL anyFragments = FALSE;
-			return mContext->GetData(mQuery, &anyFragments, sizeof(anyFragments), 0) == S_OK;
+			BOOL anySamples = FALSE;
+			return mContext->GetData(mQuery, &anySamples, sizeof(anySamples), 0) == S_OK;
 		}
 		else
 		{
-			UINT64 numFragments = 0;
-			return mContext->GetData(mQuery, &numFragments, sizeof(numFragments), 0) == S_OK;
+			UINT64 numSamples = 0;
+			return mContext->GetData(mQuery, &numSamples, sizeof(numSamples), 0) == S_OK;
 		}
 	}
 
-	UINT32 D3D11OcclusionQuery::getNumFragments()
+	UINT32 D3D11OcclusionQuery::getNumSamples()
 	{
 		if (!mFinalized && isReady())
 		{
 			finalize();
 		}
 
-		return mNumFragments;
+		return mNumSamples;
 	}
 
 	void D3D11OcclusionQuery::finalize()
@@ -71,17 +71,17 @@ namespace BansheeEngine
 
 		if (mBinary)
 		{
-			BOOL anyFragments = FALSE;
-			mContext->GetData(mQuery, &anyFragments, sizeof(anyFragments), 0);
+			BOOL anySamples = FALSE;
+			mContext->GetData(mQuery, &anySamples, sizeof(anySamples), 0);
 
-			mNumFragments = anyFragments == TRUE ? 1 : 0;
+			mNumSamples = anySamples == TRUE ? 1 : 0;
 		}
 		else
 		{
-			UINT64 numFragments = 0;
-			mContext->GetData(mQuery, &numFragments, sizeof(numFragments), 0);
+			UINT64 numSamples = 0;
+			mContext->GetData(mQuery, &numSamples, sizeof(numSamples), 0);
 
-			mNumFragments = (UINT32)numFragments;
+			mNumSamples = (UINT32)numSamples;
 		}
 	}
 }

+ 2 - 2
CamelotD3D9Renderer/Include/CmD3D9OcclusionQuery.h

@@ -33,7 +33,7 @@ namespace BansheeEngine
 		/**
 		* @copydoc OcclusionQuery::getNumFragments
 		*/
-		virtual UINT32 getNumFragments();
+		virtual UINT32 getNumSamples();
 
 		/**
 		* @copydoc	D3D9Resource::notifyOnDeviceCreate
@@ -78,6 +78,6 @@ namespace BansheeEngine
 		bool mQueryIssued;
 		bool mFinalized;
 
-		UINT32 mNumFragments;
+		UINT32 mNumSamples;
 	};
 }

+ 8 - 8
CamelotD3D9Renderer/Source/CmD3D9OcclusionQuery.cpp

@@ -5,7 +5,7 @@
 namespace BansheeEngine
 {
 	D3D9OcclusionQuery::D3D9OcclusionQuery(bool binary)
-		:OcclusionQuery(binary), mQuery(nullptr), mNumFragments(0), 
+		:OcclusionQuery(binary), mQuery(nullptr), mNumSamples(0), 
 		mFinalized(false), mDevice(nullptr), mQueryIssued(false)
 	{
 		createQuery();
@@ -37,7 +37,7 @@ namespace BansheeEngine
 		if (mQuery != nullptr)
 			mQuery->Issue(D3DISSUE_BEGIN);
 
-		mNumFragments = 0;
+		mNumSamples = 0;
 		mQueryIssued = false;
 		setActive(true);
 	}
@@ -60,14 +60,14 @@ namespace BansheeEngine
 		return mQuery->GetData(&queryData, sizeof(BOOL), 0) == S_OK;
 	}
 
-	UINT32 D3D9OcclusionQuery::getNumFragments()
+	UINT32 D3D9OcclusionQuery::getNumSamples()
 	{
 		if (!mFinalized && isReady())
 		{
 			finalize();
 		}
 
-		return mNumFragments;
+		return mNumSamples;
 	}
 
 	void D3D9OcclusionQuery::finalize()
@@ -76,14 +76,14 @@ namespace BansheeEngine
 
 		if (mQuery == nullptr)
 		{
-			mNumFragments = 0;
+			mNumSamples = 0;
 			return;
 		}
 
-		DWORD numFragments;
-		mQuery->GetData(&numFragments, sizeof(DWORD), 0);
+		DWORD numSamples;
+		mQuery->GetData(&numSamples, sizeof(DWORD), 0);
 
-		mNumFragments = (UINT32)numFragments;
+		mNumSamples = (UINT32)numSamples;
 	}
 
 	void D3D9OcclusionQuery::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)

+ 2 - 2
CamelotGLRenderer/Include/CmGLOcclusionQuery.h

@@ -32,7 +32,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc OcclusionQuery::getNumFragments
 		 */
-		virtual UINT32 getNumFragments();
+		virtual UINT32 getNumSamples();
 
 	private:
 		friend class QueryManager;
@@ -40,7 +40,7 @@ namespace BansheeEngine
 		GLuint mQueryObj;
 		bool mFinalized;
 
-		UINT32 mNumFragments;
+		UINT32 mNumSamples;
 
 		void finalize();
 	};

+ 8 - 8
CamelotGLRenderer/Source/CmGLOcclusionQuery.cpp

@@ -4,7 +4,7 @@
 namespace BansheeEngine
 {
 	GLOcclusionQuery::GLOcclusionQuery(bool binary)
-		:OcclusionQuery(binary), mQueryObj(0), mNumFragments(0), mFinalized(false)
+		:OcclusionQuery(binary), mQueryObj(0), mNumSamples(0), mFinalized(false)
 	{
 		glGenQueries(1, &mQueryObj);
 	}
@@ -18,7 +18,7 @@ namespace BansheeEngine
 	{
 		glBeginQuery(mBinary ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED, mQueryObj);
 
-		mNumFragments = 0;
+		mNumSamples = 0;
 		setActive(true);
 	}
 
@@ -35,14 +35,14 @@ namespace BansheeEngine
 		return done == GL_TRUE;
 	}
 
-	UINT32 GLOcclusionQuery::getNumFragments()
+	UINT32 GLOcclusionQuery::getNumSamples()
 	{
 		if (!mFinalized && isReady())
 		{
 			finalize();
 		}
 
-		return mNumFragments;
+		return mNumSamples;
 	}
 
 	void GLOcclusionQuery::finalize()
@@ -54,14 +54,14 @@ namespace BansheeEngine
 			GLboolean anyPassed = GL_FALSE;
 			glGetQueryObjectuiv(mQueryObj, GL_QUERY_RESULT_ARB, (GLuint*)&anyPassed);
 
-			mNumFragments = anyPassed == GL_TRUE ? 1 : 0;
+			mNumSamples = anyPassed == GL_TRUE ? 1 : 0;
 		}
 		else
 		{
-			GLuint numFragments = 0;
-			glGetQueryObjectuiv(mQueryObj, GL_QUERY_RESULT_ARB, (GLuint*)&numFragments);
+			GLuint numSamples = 0;
+			glGetQueryObjectuiv(mQueryObj, GL_QUERY_RESULT_ARB, (GLuint*)&numSamples);
 
-			mNumFragments = (UINT32)numFragments;
+			mNumSamples = (UINT32)numSamples;
 		}
 	}
 }

+ 3 - 0
Polish.txt

@@ -19,6 +19,9 @@ I should be able to specify resolution when going to windowed mode
  - Maybe just store the windowed and fullscreen resolutions separately and restore automatically?
  - I have a feeling DX9 might start crashing once I resize to sub-fullscreen res and go back to FS - test it
 
+ Add VSync toggle to RenderWindow if it doesn't already exist.
+ Test creating a fullscreen window on window creation.
+
 DISREGARD MONITOR INDEX ON DX9
  - It's not trivial and its not worth wasting time on a deprecated system
  - Seems I would need to destroy the device and then recreate it using the new adapter index