Browse Source

Added Occlusion queries

Marko Pintera 11 years ago
parent
commit
87c63a50e6
29 changed files with 520 additions and 767 deletions
  1. 0 1
      BansheeEngine.sln
  2. 1 1
      CamelotCore/Include/CmEventQuery.h
  3. 71 127
      CamelotCore/Include/CmOcclusionQuery.h
  4. 2 0
      CamelotCore/Include/CmPrerequisites.h
  5. 38 5
      CamelotCore/Include/CmQueryManager.h
  6. 10 2
      CamelotCore/Include/CmTimerQuery.h
  7. 1 1
      CamelotCore/Source/CmApplication.cpp
  8. 13 43
      CamelotCore/Source/CmOcclusionQuery.cpp
  9. 21 1
      CamelotCore/Source/CmQueryManager.cpp
  10. 2 0
      CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj
  11. 6 0
      CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj.filters
  12. 48 0
      CamelotD3D11RenderSystem/Include/CmD3D11OcclusionQuery.h
  13. 12 0
      CamelotD3D11RenderSystem/Include/CmD3D11QueryManager.h
  14. 1 1
      CamelotD3D11RenderSystem/Include/CmD3D11TimerQuery.h
  15. 87 0
      CamelotD3D11RenderSystem/Source/CmD3D11OcclusionQuery.cpp
  16. 9 0
      CamelotD3D11RenderSystem/Source/CmD3D11QueryManager.cpp
  17. 26 94
      CamelotD3D9Renderer/Include/CmD3D9OcclusionQuery.h
  18. 12 0
      CamelotD3D9Renderer/Include/CmD3D9QueryManager.h
  19. 1 1
      CamelotD3D9Renderer/Include/CmD3D9TimerQuery.h
  20. 35 225
      CamelotD3D9Renderer/Source/CmD3D9OcclusionQuery.cpp
  21. 9 0
      CamelotD3D9Renderer/Source/CmD3D9QueryManager.cpp
  22. 41 102
      CamelotGLRenderer/Include/CmGLOcclusionQuery.h
  23. 12 0
      CamelotGLRenderer/Include/CmGLQueryManager.h
  24. 1 1
      CamelotGLRenderer/Include/CmGLTimerQuery.h
  25. 48 126
      CamelotGLRenderer/Source/CmGLOcclusionQuery.cpp
  26. 9 0
      CamelotGLRenderer/Source/CmGLQueryManager.cpp
  27. 1 1
      Notes.txt
  28. 3 0
      TODO.txt
  29. 0 35
      TaskScheduler.txt

+ 0 - 1
BansheeEngine.sln

@@ -37,7 +37,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		RenderOperation.txt = RenderOperation.txt
 		ResourceBundles.txt = ResourceBundles.txt
 		SpriteTexture.txt = SpriteTexture.txt
-		TaskScheduler.txt = TaskScheduler.txt
 		TODO.txt = TODO.txt
 		TODODoc.txt = TODODoc.txt
 		TransformUpdatesAndRenderer.txt = TransformUpdatesAndRenderer.txt

+ 1 - 1
CamelotCore/Include/CmEventQuery.h

@@ -47,7 +47,7 @@ namespace BansheeEngine
 		friend class QueryManager;
 
 		/**
-		 * @brief	Returns true if the query is still waiting for its "ready" callback to be triggered.
+		 * @brief	Returns true if the has still not been completed by the GPU.
 		 */
 		bool isActive() const { return mActive; }
 		void setActive(bool active) { mActive = active; }

+ 71 - 127
CamelotCore/Include/CmOcclusionQuery.h

@@ -1,132 +1,76 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
+#pragma once
 
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#ifndef _HardwareOcclusionQuery__
-#define _HardwareOcclusionQuery__
-
-// Precompiler options
 #include "CmPrerequisites.h"
 
-namespace BansheeEngine {
-
-
-
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup RenderSystem
-	*  @{
-	*/
-/**
-  * This is a abstract class that that provides the interface for the query class for 
-  * hardware occlusion.
-  *
-  * @author Lee Sandberg
-  * Updated on 13/8/2005 by Tuan Kuranes email: [email protected]
-  */
-	class CM_EXPORT OcclusionQuery
+namespace BansheeEngine
 {
-//----------------------------------------------------------------------
-// Public methods
-//--
-public:
-	/**
-	  * Object public member functions
-	  */
-
-	/**
-	  * Default object constructor
-	  * 
-	  */
-	OcclusionQuery();
-
-	/**
-	  * Object destructor
-	  */
-	virtual ~OcclusionQuery();
-
-	/**
-	  * Starts the hardware occlusion query
-	  * @Remarks	Simple usage: Create one or more OcclusionQuery object one per outstanding query or one per tested object 
-	  *				OcclusionQuery* m_pOcclusionQuery;
-	  *				createOcclusionQuery( &m_pOcclusionQuery );
-	  *				In the rendering loop:
-	  *				Draw all occluders
-	  *				m_pOcclusionQuery->startOcclusionQuery();
-	  *				Draw the polygons to be tested
-	  *				m_pOcclusionQuery->endOcclusionQuery();
-	  *
-	  *				Results must be pulled using:
-	  *				UINT	m_uintNumberOfPixelsVisable;
-	  *				pullOcclusionQuery( &m_dwNumberOfPixelsVisable );
-	  *			
-	  */
-	virtual void beginOcclusionQuery() = 0;
-
-	/**
-	  * Ends the hardware occlusion test
-	  */
-	virtual void endOcclusionQuery() = 0;
-
-	/**
-      * Pulls the hardware occlusion query.
-	  * @note Waits until the query result is available; use isStillOutstanding
-	  *		if just want to test if the result is available.
-      * @retval NumOfFragments will get the resulting number of fragments.
-      * @return True if success or false if not.
-      */
-	virtual bool pullOcclusionQuery(unsigned int* NumOfFragments) = 0;
-
 	/**
-	  * Let's you get the last pixel count with out doing the hardware occlusion test
-	  * @return The last fragment count from the last test.
-	  * Remarks This function won't give you new values, just the old value.
-	  */
-	unsigned int getLastQuerysPixelcount() const { return mPixelCount; }
-
-	/**
-	  * Lets you know when query is done, or still be processed by the Hardware
-	  * @return true if query isn't finished.
-	  */
-	 virtual bool isStillOutstanding(void) = 0; 
-
-
-    //----------------------------------------------------------------------
-    // protected members
-    //--
-    protected :
-        // numbers of visible pixels determined by last query
-        unsigned int mPixelCount;
-        // is query hasn't yet returned a result.
-		bool		 mIsQueryResultStillOutstanding;
-};
-
-	/** @} */
-	/** @} */
-}
-#endif
-
+	* @brief	Represents a query that counts number of fragments rendered by the GPU
+	*			while the query is active.
+	*
+	* @note		Core thread only.
+	*/
+	class CM_EXPORT OcclusionQuery
+	{
+	public:
+		OcclusionQuery(bool binary);
+		virtual ~OcclusionQuery() {}
+
+		/**
+		* @brief	Starts the query. Any draw calls after this call will have any rendered fragments
+		*			counted in the query.
+		*
+		* @note		Place any commands you want to measure after this call. Call "end" when done.
+		*/
+		virtual void begin() = 0;
+
+		/**
+		* @brief	Stops the query. 
+		*
+		* @note		Be aware that queries are executed on the GPU and the results will not be immediately available.
+		*/
+		virtual void end() = 0;
+
+		/**
+		* @brief	Check if GPU has processed the query.
+		*/
+		virtual bool isReady() const = 0;
+
+		/**
+		 * @brief	Returns the number of fragments 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;
+
+		/**
+		 * @brief	Triggered when the query has completed. Argument provided
+		 *			is the number of fragments 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
+		 *					queries can return sooner as they potentially do not need to wait until all of the geometry is rendered.
+		 */
+		static OcclusionQueryPtr create(bool binary);
+
+	protected:
+		friend class QueryManager;
+
+		/**
+		* @brief	Returns true if the has still not been completed by the GPU.
+		*/
+		bool isActive() const { return mActive; }
+		void setActive(bool active) { mActive = active; }
+
+	protected:
+		bool mActive;
+		bool mBinary;
+	};
+}

+ 2 - 0
CamelotCore/Include/CmPrerequisites.h

@@ -130,6 +130,7 @@ namespace BansheeEngine
 	class VertexDataDesc;
 	class EventQuery;
 	class TimerQuery;
+	class OcclusionQuery;
 	class FrameAlloc;
 	class FolderMonitor;
 	// Asset import
@@ -220,6 +221,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<CoreThreadAccessor<CommandQueueSync>> SyncedCoreAccessorPtr;
 	typedef std::shared_ptr<EventQuery> EventQueryPtr;
 	typedef std::shared_ptr<TimerQuery> TimerQueryPtr;
+	typedef std::shared_ptr<OcclusionQuery> OcclusionQueryPtr;
 	typedef std::shared_ptr<ResourceManifest> ResourceManifestPtr;
 }
 

+ 38 - 5
CamelotCore/Include/CmQueryManager.h

@@ -16,23 +16,56 @@ namespace BansheeEngine
 	public:
 		QueryManager();
 
+		/**
+		 * @brief	Creates a new event query that allows you to get notified
+		 *			when GPU starts executing the query.
+		 */
 		virtual EventQueryPtr createEventQuery() const = 0;
+
+		/**
+		* @brief	Creates a new timer query that allows you to get notified
+		*			of how much time has passed between query start and end.
+		*/
 		virtual TimerQueryPtr createTimerQuery() const = 0;
 
+		/**
+		* @brief	Creates a new occlusion query that allows you to know
+		*			how many fragments were rendered between query start and end.
+		*
+		* @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
+		*				queries can return sooner as they potentially do not need to wait until all of the geometry is rendered.
+		*/
+		virtual OcclusionQueryPtr createOcclusionQuery(bool binary) const = 0;
+
 		/**
 		 * @note	Internal method, called every frame.
 		 */
-		void update();
-
-	protected:
-		mutable Vector<EventQuery*> mEventQueries;
-		mutable Vector<TimerQuery*> mTimerQueries;
+		void _update();
 
 	protected:
 		friend class EventQuery;
 		friend class TimerQuery;
+		friend class OcclusionQuery;
 
+		/**
+		 * @brief	Deletes an Event query. Always use this method and don't delete them manually.
+		 */
 		static void deleteEventQuery(EventQuery* query);
+
+		/**
+		* @brief	Deletes a Timer query. Always use this method and don't delete them manually.
+		*/
 		static void deleteTimerQuery(TimerQuery* query);
+
+		/**
+		* @brief	Deletes an Occlusion query. Always use this method and don't delete them manually.
+		*/
+		static void deleteOcclusionQuery(OcclusionQuery* query);
+
+	protected:
+		mutable Vector<EventQuery*> mEventQueries;
+		mutable Vector<TimerQuery*> mTimerQueries;
+		mutable Vector<OcclusionQuery*> mOcclusionQueries;
 	};
 }

+ 10 - 2
CamelotCore/Include/CmTimerQuery.h

@@ -41,15 +41,23 @@ namespace BansheeEngine
 		 */
 		virtual float getTimeMs() = 0;
 
+		/**
+		* @brief	Triggered when GPU processes the query. As a parameter
+		*			it provides query duration in milliseconds.
+		*/
 		Event<void(float)> onTriggered;
 
+		/**
+		 * @brief	Creates a new query, but does not schedule it on GPU.
+		 */
 		static TimerQueryPtr create();
 
 	protected:
 		friend class QueryManager;
 
-		virtual void finalize() = 0;
-
+		/**
+		* @brief	Returns true if the has still not been completed by the GPU.
+		*/
 		bool isActive() const { return mActive; }
 		void setActive(bool active) { mActive = active; }
 

+ 1 - 1
CamelotCore/Source/CmApplication.cpp

@@ -114,7 +114,7 @@ namespace BansheeEngine
 			PROFILE_CALL(gSceneManager().update(), "SceneManager");
 
 			gCoreThread().queueCommand(std::bind(&Application::beginCoreProfiling, this));
-			gCoreThread().queueCommand(std::bind(&QueryManager::update, QueryManager::instancePtr()));
+			gCoreThread().queueCommand(std::bind(&QueryManager::_update, QueryManager::instancePtr()));
 
 			if(!mainLoopCallback.empty())
 				mainLoopCallback();

+ 13 - 43
CamelotCore/Source/CmOcclusionQuery.cpp

@@ -1,44 +1,14 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-
 #include "CmOcclusionQuery.h"
-
-namespace BansheeEngine {
-
-
-    OcclusionQuery::OcclusionQuery() : 
-        mPixelCount(0),
-        mIsQueryResultStillOutstanding(false)
-    {
-    }
-    OcclusionQuery::~OcclusionQuery()
-    {
-    }
-
-}
-
+#include "CmQueryManager.h"
+
+namespace BansheeEngine
+{
+	OcclusionQuery::OcclusionQuery(bool binary)
+		:mActive(false), mBinary(binary)
+	{ }
+
+	OcclusionQueryPtr OcclusionQuery::create(bool binary)
+	{
+		return QueryManager::instance().createOcclusionQuery(binary);
+	}
+}

+ 21 - 1
CamelotCore/Source/CmQueryManager.cpp

@@ -1,6 +1,7 @@
 #include "CmQueryManager.h"
 #include "CmEventQuery.h"
 #include "CmTimerQuery.h"
+#include "CmOcclusionQuery.h"
 
 namespace BansheeEngine
 {
@@ -9,7 +10,7 @@ namespace BansheeEngine
 
 	}
 
-	void QueryManager::update()
+	void QueryManager::_update()
 	{
 		for(auto& query : mEventQueries)
 		{
@@ -28,6 +29,15 @@ namespace BansheeEngine
 				query->setActive(false);
 			}
 		}
+
+		for (auto& query : mOcclusionQueries)
+		{
+			if (query->isActive() && query->isReady())
+			{
+				query->onComplete(query->getNumFragments());
+				query->setActive(false);
+			}
+		}
 	}
 
 	void QueryManager::deleteEventQuery(EventQuery* query)
@@ -49,4 +59,14 @@ namespace BansheeEngine
 
 		cm_delete(query);
 	}
+
+	void QueryManager::deleteOcclusionQuery(OcclusionQuery* query)
+	{
+		auto iterFind = std::find(instance().mOcclusionQueries.begin(), instance().mOcclusionQueries.end(), query);
+
+		if (iterFind != instance().mOcclusionQueries.end())
+			instance().mOcclusionQueries.erase(iterFind);
+
+		cm_delete(query);
+	}
 }

+ 2 - 0
CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj

@@ -250,6 +250,7 @@
     <ClInclude Include="Include\CmD3D11Mappings.h" />
     <ClInclude Include="Include\CmD3D11MultiRenderTexture.h" />
     <ClInclude Include="Include\CmD3D11GpuParamBlockBuffer.h" />
+    <ClInclude Include="Include\CmD3D11OcclusionQuery.h" />
     <ClInclude Include="Include\CmD3D11Prerequisites.h" />
     <ClInclude Include="Include\CmD3D11QueryManager.h" />
     <ClInclude Include="Include\CmD3D11RenderUtility.h" />
@@ -288,6 +289,7 @@
     <ClCompile Include="Source\CmD3D11HLSLProgramFactory.cpp" />
     <ClCompile Include="Source\CmD3D11InputLayoutManager.cpp" />
     <ClCompile Include="Source\CmD3D11Mappings.cpp" />
+    <ClCompile Include="Source\CmD3D11OcclusionQuery.cpp" />
     <ClCompile Include="Source\CmD3D11Plugin.cpp" />
     <ClCompile Include="Source\CmD3D11QueryManager.cpp" />
     <ClCompile Include="Source\CmD3D11RenderUtility.cpp" />

+ 6 - 0
CamelotD3D11RenderSystem/CamelotD3D11RenderSystem.vcxproj.filters

@@ -129,6 +129,9 @@
     <ClInclude Include="Include\CmD3D11GpuProgramRTTI.h">
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmD3D11OcclusionQuery.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmD3D11GpuProgram.cpp">
@@ -239,5 +242,8 @@
     <ClCompile Include="Source\CmD3D11TimerQuery.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmD3D11OcclusionQuery.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 48 - 0
CamelotD3D11RenderSystem/Include/CmD3D11OcclusionQuery.h

@@ -0,0 +1,48 @@
+#pragma once
+
+#include "CmD3D11Prerequisites.h"
+#include "CmOcclusionQuery.h"
+
+namespace BansheeEngine
+{
+	/**
+	* @copydoc OcclusionQuery
+	*/
+	class CM_D3D11_EXPORT D3D11OcclusionQuery : public OcclusionQuery
+	{
+	public:
+		D3D11OcclusionQuery(bool binary);
+		~D3D11OcclusionQuery();
+
+		/**
+		* @copydoc OcclusionQuery::begin
+		*/
+		virtual void begin();
+
+		/**
+		* @copydoc OcclusionQuery::end
+		*/
+		virtual void end();
+
+		/**
+		* @copydoc OcclusionQuery::isReady
+		*/
+		virtual bool isReady() const;
+
+		/**
+		* @copydoc OcclusionQuery::getNumFragments
+		*/
+		virtual UINT32 getNumFragments();
+
+	private:
+		friend class QueryManager;
+
+		ID3D11Query* mQuery;
+		ID3D11DeviceContext* mContext;
+		bool mFinalized;
+
+		UINT32 mNumFragments;
+
+		void finalize();
+	};
+}

+ 12 - 0
CamelotD3D11RenderSystem/Include/CmD3D11QueryManager.h

@@ -8,7 +8,19 @@ namespace BansheeEngine
 	class CM_D3D11_EXPORT D3D11QueryManager : public QueryManager
 	{
 	public:
+		/**
+		 * @copydoc		QueryManager::createEventQuery
+		 */
 		EventQueryPtr createEventQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createTimerQuery
+		 */
 		TimerQueryPtr createTimerQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createOcclusionQuery
+		 */
+		OcclusionQueryPtr createOcclusionQuery(bool binary) const;
 	};
 }

+ 1 - 1
CamelotD3D11RenderSystem/Include/CmD3D11TimerQuery.h

@@ -43,6 +43,6 @@ namespace BansheeEngine
 		ID3D11Query* mDisjointQuery;
 		ID3D11DeviceContext* mContext;
 
-		virtual void finalize();
+		void finalize();
 	};
 }

+ 87 - 0
CamelotD3D11RenderSystem/Source/CmD3D11OcclusionQuery.cpp

@@ -0,0 +1,87 @@
+#include "CmD3D11OcclusionQuery.h"
+#include "CmD3D11RenderSystem.h"
+#include "CmD3D11Device.h"
+#include "CmMath.h"
+
+namespace BansheeEngine
+{
+	D3D11OcclusionQuery::D3D11OcclusionQuery(bool binary)
+		:OcclusionQuery(binary), mContext(nullptr), mQuery(nullptr), mNumFragments(0), mFinalized(false)
+	{
+		D3D11RenderSystem* rs = static_cast<D3D11RenderSystem*>(RenderSystem::instancePtr());
+		D3D11Device& device = rs->getPrimaryDevice();
+
+		D3D11_QUERY_DESC queryDesc;
+		queryDesc.Query = mBinary ? D3D11_QUERY_OCCLUSION_PREDICATE : D3D11_QUERY_OCCLUSION;
+		queryDesc.MiscFlags = 0;
+
+		HRESULT hr = device.getD3D11Device()->CreateQuery(&queryDesc, &mQuery);
+		if (hr != S_OK)
+			CM_EXCEPT(RenderingAPIException, "Failed to create an occlusion query.");
+
+		mContext = device.getImmediateContext();
+	}
+
+	D3D11OcclusionQuery::~D3D11OcclusionQuery()
+	{
+		if (mQuery != nullptr)
+			mQuery->Release();
+	}
+
+	void D3D11OcclusionQuery::begin()
+	{
+		mContext->Begin(mQuery);
+
+		mNumFragments = 0;
+		setActive(true);
+	}
+
+	void D3D11OcclusionQuery::end()
+	{
+		mContext->End(mQuery);
+	}
+
+	bool D3D11OcclusionQuery::isReady() const
+	{
+		if (mBinary)
+		{
+			BOOL anyFragments = FALSE;
+			return mContext->GetData(mQuery, &anyFragments, sizeof(anyFragments), 0) == S_OK;
+		}
+		else
+		{
+			UINT64 numFragments = 0;
+			return mContext->GetData(mQuery, &numFragments, sizeof(numFragments), 0) == S_OK;
+		}
+	}
+
+	UINT32 D3D11OcclusionQuery::getNumFragments()
+	{
+		if (!mFinalized && isReady())
+		{
+			finalize();
+		}
+
+		return mNumFragments;
+	}
+
+	void D3D11OcclusionQuery::finalize()
+	{
+		mFinalized = true;
+
+		if (mBinary)
+		{
+			BOOL anyFragments = FALSE;
+			mContext->GetData(mQuery, &anyFragments, sizeof(anyFragments), 0);
+
+			mNumFragments = anyFragments == TRUE ? 1 : 0;
+		}
+		else
+		{
+			UINT64 numFragments = 0;
+			mContext->GetData(mQuery, &numFragments, sizeof(numFragments), 0);
+
+			mNumFragments = (UINT32)numFragments;
+		}
+	}
+}

+ 9 - 0
CamelotD3D11RenderSystem/Source/CmD3D11QueryManager.cpp

@@ -1,6 +1,7 @@
 #include "CmD3D11QueryManager.h"
 #include "CmD3D11EventQuery.h"
 #include "CmD3D11TimerQuery.h"
+#include "CmD3D11OcclusionQuery.h"
 
 namespace BansheeEngine
 {
@@ -19,4 +20,12 @@ namespace BansheeEngine
 
 		return query;
 	}
+
+	OcclusionQueryPtr D3D11QueryManager::createOcclusionQuery(bool binary) const
+	{
+		OcclusionQueryPtr query = std::shared_ptr<D3D11OcclusionQuery>(cm_new<D3D11OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		mOcclusionQueries.push_back(query.get());
+
+		return query;
+	}
 }

+ 26 - 94
CamelotD3D9Renderer/Include/CmD3D9OcclusionQuery.h

@@ -1,115 +1,47 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-(Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-
-#ifndef _D3D9HARWAREOCCLUSIONQUERY_H__
-#define _D3D9HARWAREOCCLUSIONQUERY_H__
+#pragma once
 
 #include "CmD3D9Prerequisites.h"
 #include "CmOcclusionQuery.h"
-#include "CmD3D9Resource.h"
-
-
-namespace BansheeEngine {
-
-	// If you use multiple rendering passes you can test only the first pass and all other passes don't have to be rendered 
-	// if the first pass results has too few pixels visible.
-
-	// Be sure to render all occluder first and whats out so the RenderQue don't switch places on 
-	// the occluding objects and the tested objects because it thinks it's more effective..
 
+namespace BansheeEngine
+{
 	/**
-	* This is a class that is the DirectX9 implementation of 
-	* hardware occlusion testing.
-	*
-	* @author Lee Sandberg, email [email protected]
-	*
-	* Updated on 12/7/2004 by Chris McGuirk
-	* Updated on 4/8/2005 by Tuan Kuranes email: [email protected]
+	* @copydoc OcclusionQuery
 	*/
-	class CM_D3D9_EXPORT D3D9OcclusionQuery : public OcclusionQuery, public D3D9Resource
+	class CM_D3D9_EXPORT D3D9OcclusionQuery : public OcclusionQuery
 	{
-		//----------------------------------------------------------------------
-		// Public methods
-		//--
 	public:
+		D3D9OcclusionQuery(bool binary);
+		~D3D9OcclusionQuery();
 
 		/**
-		* Default object constructor
-		* 
+		* @copydoc OcclusionQuery::begin
 		*/
-		D3D9OcclusionQuery();
+		virtual void begin();
 
 		/**
-		* Object destructor
+		* @copydoc OcclusionQuery::end
 		*/
-		~D3D9OcclusionQuery();
+		virtual void end();
 
-		//------------------------------------------------------------------
-		// Occlusion query functions (see base class documentation for this)
-		//--
-
-		void beginOcclusionQuery();	
-		void endOcclusionQuery();
-		bool pullOcclusionQuery( unsigned int* NumOfFragments);
-		unsigned int getLastQuerysPixelcount();
-        bool isStillOutstanding(void);
-	
-		// Called immediately after the Direct3D device has been created.
-		virtual void notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device);
-
-		// Called before the Direct3D device is going to be destroyed.
-		virtual void notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device);
-		
-		// Called immediately after the Direct3D device has entered a lost state.
-		// This is the place to release non-managed resources.
-		virtual void notifyOnDeviceLost(IDirect3DDevice9* d3d9Device);
+		/**
+		* @copydoc OcclusionQuery::isReady
+		*/
+		virtual bool isReady() const;
 
-		// Called immediately after the Direct3D device has been reset.
-		// This is the place to create non-managed resources.
-		virtual void notifyOnDeviceReset(IDirect3DDevice9* d3d9Device);
-	
+		/**
+		* @copydoc OcclusionQuery::getNumFragments
+		*/
+		virtual UINT32 getNumFragments();
 
 	private:
-		void createQuery(IDirect3DDevice9* d3d9Device);
-		void releaseQuery(IDirect3DDevice9* d3d9Device);
+		friend class QueryManager;
 
-		//----------------------------------------------------------------------
-		// private members
-		//--
-	private:					
-		typedef Map<IDirect3DDevice9*, IDirect3DQuery9*> DeviceToQueryMap;
-		typedef DeviceToQueryMap::iterator					   DeviceToQueryIterator;
+		IDirect3DQuery9* mQuery;
+		bool mFinalized;
 
-		DeviceToQueryMap				mMapDeviceToQuery;		
-	};
-
-
-}
+		UINT32 mNumFragments;
 
-
-#endif
+		void finalize();
+	};
+}

+ 12 - 0
CamelotD3D9Renderer/Include/CmD3D9QueryManager.h

@@ -8,7 +8,19 @@ namespace BansheeEngine
 	class CM_D3D9_EXPORT D3D9QueryManager : public QueryManager
 	{
 	public:
+		/**
+		 * @copydoc		QueryManager::createEventQuery
+		 */
 		EventQueryPtr createEventQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createTimerQuery
+		 */
 		TimerQueryPtr createTimerQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createOcclusionQuery
+		 */
+		OcclusionQueryPtr createOcclusionQuery(bool binary) const;
 	};
 }

+ 1 - 1
CamelotD3D9Renderer/Include/CmD3D9TimerQuery.h

@@ -43,6 +43,6 @@ namespace BansheeEngine
 		IDirect3DQuery9* mDisjointQuery;
 		IDirect3DQuery9* mFreqQuery;
 
-		virtual void finalize();
+		void finalize();
 	};
 }

+ 35 - 225
CamelotD3D9Renderer/Source/CmD3D9OcclusionQuery.cpp

@@ -1,253 +1,63 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-(Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
 #include "CmD3D9OcclusionQuery.h"
-#include "CmRenderSystemCapabilities.h"
-#include "CmException.h"
 #include "CmD3D9RenderSystem.h"
+#include "CmMath.h"
 
-namespace BansheeEngine {
-
-	/**
-	* This is a class that is the DirectX9 implementation of 
-	* hardware occlusion testing.
-	*
-	* @author Lee Sandberg
-	*
-	* Updated on 12/7/2004 by Chris McGuirk
-	* Updated on 4/8/2005 by Tuan Kuranes email: [email protected]
-	*/
-
-	/**
-	* Default object constructor
-	*/
-    D3D9OcclusionQuery::D3D9OcclusionQuery()
-	{ 
-		
-	}
-
-	/**
-	* Object destructor
-	*/
-	D3D9OcclusionQuery::~D3D9OcclusionQuery() 
-	{ 
-		DeviceToQueryIterator it = mMapDeviceToQuery.begin();
-
-		while (it != mMapDeviceToQuery.end())
-		{
-			SAFE_RELEASE(it->second);
-			++it;
-		}	
-		mMapDeviceToQuery.clear();
-	}
-
-	//------------------------------------------------------------------
-	// Occlusion query functions (see base class documentation for this)
-	//--
-	void D3D9OcclusionQuery::beginOcclusionQuery() 
-	{	
-		IDirect3DDevice9* pCurDevice  = D3D9RenderSystem::getActiveD3D9Device();				
-		DeviceToQueryIterator it      = mMapDeviceToQuery.find(pCurDevice);
-
-		// No resource exits for current device -> create it.
-		if (it == mMapDeviceToQuery.end() || it->second == NULL)		
-			createQuery(pCurDevice);			
-		
-
-		// Grab the query of the current device.
-		IDirect3DQuery9* pOccQuery = mMapDeviceToQuery[pCurDevice];
-
-		
-		if (pOccQuery != NULL)
-		{
-			pOccQuery->Issue(D3DISSUE_BEGIN); 
-			mIsQueryResultStillOutstanding = true;
-			mPixelCount = 0;
-		}		
-	}
+namespace BansheeEngine
+{
+	D3D9OcclusionQuery::D3D9OcclusionQuery(bool binary)
+		:OcclusionQuery(binary), mQuery(nullptr), mNumFragments(0), mFinalized(false)
+	{
+		IDirect3DDevice9* device = D3D9RenderSystem::getActiveD3D9Device();
 
-	void D3D9OcclusionQuery::endOcclusionQuery() 
-	{ 
-		IDirect3DDevice9* pCurDevice  = D3D9RenderSystem::getActiveD3D9Device();				
-		DeviceToQueryIterator it      = mMapDeviceToQuery.find(pCurDevice);
-		
-		if (it == mMapDeviceToQuery.end())
+		HRESULT hr = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &mQuery);
+		if (hr != S_OK)
 		{
-			CM_EXCEPT(RenderingAPIException, "End occlusion called without matching begin call !!" );
+			CM_EXCEPT(RenderingAPIException, "Failed to create an occlusion query.");
 		}
-
-		IDirect3DQuery9* pOccQuery = mMapDeviceToQuery[pCurDevice];
-
-		if (pOccQuery != NULL)
-			pOccQuery->Issue(D3DISSUE_END); 
-	}	
-
-	//------------------------------------------------------------------
-	bool D3D9OcclusionQuery::pullOcclusionQuery( unsigned int* NumOfFragments ) 
-	{
-		IDirect3DDevice9* pCurDevice = D3D9RenderSystem::getActiveD3D9Device();
-		DeviceToQueryIterator it     = mMapDeviceToQuery.find(pCurDevice);
-
-		if (it == mMapDeviceToQuery.end())		
-			return false;
-
-		if (it->second == NULL)
-			return false;
-
-        // in case you didn't check if query arrived and want the result now.
-        if (mIsQueryResultStillOutstanding)
-        {
-            // Loop until the data becomes available
-            DWORD pixels;
-            const size_t dataSize = sizeof( DWORD );
-			while (1)
-            {
-                const HRESULT hr = it->second->GetData((void *)&pixels, dataSize, D3DGETDATA_FLUSH);
-
-                if  (hr == S_FALSE)
-                    continue;
-                if  (hr == S_OK)
-                {
-                    mPixelCount = pixels;
-                    *NumOfFragments = pixels;
-                    break;
-                }
-                if (hr == D3DERR_DEVICELOST)
-                {
-                    *NumOfFragments = 0;
-                    mPixelCount = 0;
-                    SAFE_RELEASE(it->second);
-                    break;
-                }
-            } 
-            mIsQueryResultStillOutstanding = false;
-        }
-        else
-        {
-            // we already stored result from last frames.
-            *NumOfFragments = mPixelCount;
-        }		
-		return true;
 	}
 
-	//------------------------------------------------------------------
-	unsigned int D3D9OcclusionQuery::getLastQuerysPixelcount()
+	D3D9OcclusionQuery::~D3D9OcclusionQuery()
 	{
-		return mPixelCount;
+		if (mQuery != nullptr)
+			mQuery->Release();
 	}
 
-    //------------------------------------------------------------------
-    bool D3D9OcclusionQuery::isStillOutstanding(void)
-    {       
-        // in case you already asked for this query
-        if (!mIsQueryResultStillOutstanding)
-            return false;
-
-		IDirect3DDevice9* pCurDevice = D3D9RenderSystem::getActiveD3D9Device();
-		DeviceToQueryIterator it     = mMapDeviceToQuery.find(pCurDevice);
-
-		if (it == mMapDeviceToQuery.end())		
-			return false;
-
-		if (it->second == NULL)
-			return false;
-
-
-        DWORD pixels;
-        const HRESULT hr = it->second->GetData( (void *) &pixels, sizeof( DWORD ), 0);
-
-        if (hr  == S_FALSE)
-            return true;
-
-        if (hr == D3DERR_DEVICELOST)
-        {
-            mPixelCount = 100000;  
-			SAFE_RELEASE(it->second);
-        }
-
-        mPixelCount = pixels;
-        mIsQueryResultStillOutstanding = false;
-        return false;
-	}
-
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::notifyOnDeviceCreate(IDirect3DDevice9* d3d9Device)
+	void D3D9OcclusionQuery::begin()
 	{
-		
-	}
+		mQuery->Issue(D3DISSUE_BEGIN);
 
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::notifyOnDeviceDestroy(IDirect3DDevice9* d3d9Device)
-	{		
-		releaseQuery(d3d9Device);
+		mNumFragments = 0;
+		setActive(true);
 	}
 
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::notifyOnDeviceLost(IDirect3DDevice9* d3d9Device)
-	{		
-		releaseQuery(d3d9Device);		
+	void D3D9OcclusionQuery::end()
+	{
+		mQuery->Issue(D3DISSUE_END);
 	}
 
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::notifyOnDeviceReset(IDirect3DDevice9* d3d9Device)
-	{		
-		
+	bool D3D9OcclusionQuery::isReady() const
+	{
+		BOOL queryData;
+		return mQuery->GetData(&queryData, sizeof(BOOL), 0) == S_OK;
 	}
 
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::createQuery(IDirect3DDevice9* d3d9Device)
+	UINT32 D3D9OcclusionQuery::getNumFragments()
 	{
-		HRESULT hr;
-
-		// Check if query supported.
-		hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
-		if (FAILED(hr))
+		if (!mFinalized && isReady())
 		{
-			mMapDeviceToQuery[d3d9Device] = NULL;
-			return;
+			finalize();
 		}
 
-		// create the occlusion query.
-		IDirect3DQuery9*  pCurQuery;
-		hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pCurQuery);
-				
-		mMapDeviceToQuery[d3d9Device] = pCurQuery;	
+		return mNumFragments;
 	}
 
-	//------------------------------------------------------------------
-	void D3D9OcclusionQuery::releaseQuery(IDirect3DDevice9* d3d9Device)
+	void D3D9OcclusionQuery::finalize()
 	{
-		DeviceToQueryIterator it     = mMapDeviceToQuery.find(d3d9Device);
+		mFinalized = true;
 
-		// Remove from query resource map.
-		if (it != mMapDeviceToQuery.end())		
-		{
-			SAFE_RELEASE(it->second);
-			mMapDeviceToQuery.erase(it);
-		}
+		DWORD numFragments;
+		mQuery->GetData(&numFragments, sizeof(DWORD), 0);
+
+		mNumFragments = (UINT32)numFragments;
 	}
-}
+}

+ 9 - 0
CamelotD3D9Renderer/Source/CmD3D9QueryManager.cpp

@@ -1,6 +1,7 @@
 #include "CmD3D9QueryManager.h"
 #include "CmD3D9EventQuery.h"
 #include "CmD3D9TimerQuery.h"
+#include "CmD3D9OcclusionQuery.h"
 
 namespace BansheeEngine
 {
@@ -19,4 +20,12 @@ namespace BansheeEngine
 
 		return query;
 	}
+
+	OcclusionQueryPtr D3D9QueryManager::createOcclusionQuery(bool binary) const
+	{
+		OcclusionQueryPtr query = std::shared_ptr<D3D9OcclusionQuery>(cm_new<D3D9OcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		mOcclusionQueries.push_back(query.get());
+
+		return query;
+	}
 }

+ 41 - 102
CamelotGLRenderer/Include/CmGLOcclusionQuery.h

@@ -1,108 +1,47 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-
-/*
-The nVidia occlusion query extension is defined in glext.h so you don't 
-need anything else. You do need to look up the function, we provide a 
-GLSupport class to do this, which has platform implementations for 
-getProcAddress. Check the way that extensions like glActiveTextureARB are 
-initialised and used in glRenderSystem and copy what is done there.
-
-
-
-  To do: fix so dx7 and DX9 checks and flags if HW Occlusion is supported
-  See the openGl dito for ideas what to do.
-
-*/
-
-
-
-//GL_ActiveTextureARB_Func* glActiveTextureARB_ptr = (GL_ActiveTextureARB_Func)mGLSupport->getProcAddress("glActiveTextureARB");
-
-#ifndef __GLHARDWAREOCCLUSIONQUERY_H__
-#define __GLHARDWAREOCCLUSIONQUERY_H__
+#pragma once
 
 #include "CmGLPrerequisites.h"
 #include "CmOcclusionQuery.h"
 
-
-namespace BansheeEngine { 
-
-
-// If you use multiple rendering passes you can test only the first pass and all other passes don't have to be rendered 
-// if the first pass result has too few pixels visible.
-
-// Be sure to render all occluder first and whats out so the RenderQue don't switch places on 
-// the occluding objects and the tested objects because it thinks it's more effective..
-
-
-/**
-  * This is a class that is the base class of the query class for 
-  * hardware occlusion.
-  *
-  * @author Lee Sandberg email: [email protected]
-  * Updated on 13/9/2005 by Tuan Kuranes email: [email protected]
-  */
-
-class CM_RSGL_EXPORT GLOcclusionQuery : public OcclusionQuery
+namespace BansheeEngine
 {
-//----------------------------------------------------------------------
-// Public methods
-//--
-public:
-	/**
-	  * Default object constructor
-	  * 
-	  */
-	GLOcclusionQuery();
 	/**
-	  * Object destructor
-	  */
-	~GLOcclusionQuery();
-
-	//------------------------------------------------------------------
-	// Occlusion query functions (see base class documentation for this)
-	//--
-	void beginOcclusionQuery();
-	void endOcclusionQuery();
-	bool pullOcclusionQuery( unsigned int* NumOfFragments); 
-	bool isStillOutstanding(void);
-
-
-    //----------------------------------------------------------------------
-    // private members
-    //--
-    private:
-
-	    GLuint			mQueryID;
-};
-
-}
-
-#endif 
-
+	 * @copydoc OcclusionQuery
+	 */
+	class CM_RSGL_EXPORT GLOcclusionQuery : public OcclusionQuery
+	{
+	public:
+		GLOcclusionQuery(bool binary);
+		~GLOcclusionQuery();
+
+		/**
+		 * @copydoc OcclusionQuery::begin
+		 */
+		virtual void begin();
+
+		/**
+		 * @copydoc OcclusionQuery::end
+		 */
+		virtual void end();
+
+		/**
+		 * @copydoc OcclusionQuery::isReady
+		 */
+		virtual bool isReady() const;
+
+		/**
+		 * @copydoc OcclusionQuery::getNumFragments
+		 */
+		virtual UINT32 getNumFragments();
+
+	private:
+		friend class QueryManager;
+
+		GLuint mQueryObj;
+		bool mFinalized;
+
+		UINT32 mNumFragments;
+
+		void finalize();
+	};
+}

+ 12 - 0
CamelotGLRenderer/Include/CmGLQueryManager.h

@@ -8,7 +8,19 @@ namespace BansheeEngine
 	class CM_RSGL_EXPORT GLQueryManager : public QueryManager
 	{
 	public:
+		/**
+		 * @copydoc		QueryManager::createEventQuery
+		 */
 		EventQueryPtr createEventQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createTimerQuery
+		 */
 		TimerQueryPtr createTimerQuery() const;
+
+		/**
+		 * @copydoc		QueryManager::createOcclusionQuery
+		 */
+		OcclusionQueryPtr createOcclusionQuery(bool binary) const;
 	};
 }

+ 1 - 1
CamelotGLRenderer/Include/CmGLTimerQuery.h

@@ -43,6 +43,6 @@ namespace BansheeEngine
 
 		float mTimeDelta;
 
-		virtual void finalize();
+		void finalize();
 	};
 }

+ 48 - 126
CamelotGLRenderer/Source/CmGLOcclusionQuery.cpp

@@ -1,145 +1,67 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-
 #include "CmGLOcclusionQuery.h"
-#include "CmException.h"
+#include "CmMath.h"
 
-namespace BansheeEngine {
-
-/**
-  * This is a class that is the base class of the query class for 
-  * hardware occlusion testing.
-  *
-  * @author Lee Sandberg email: [email protected]
-  *
-  * Updated on 12/7/2004 by Chris McGuirk
-  * - Implemented ARB_occlusion_query
-  * Updated on 13/9/2005 by Tuan Kuranes email: [email protected]
-  */
-//------------------------------------------------------------------
-/**
-  * Default object constructor
-  * 
-  */
-GLOcclusionQuery::GLOcclusionQuery() 
-{ 
-	// Check for hardware occlusion support
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
-	{
-	    glGenQueriesARB(1, &mQueryID );	
-	}
-	else if (GLEW_NV_occlusion_query)
-	{
-		glGenOcclusionQueriesNV(1, &mQueryID);
-	}
-	else
-    {
-		CM_EXCEPT(InternalErrorException, 
-                    "Cannot allocate a Hardware query. This video card doesn't supports it, sorry.");
-    }
-	
-}
-//------------------------------------------------------------------
-/**
-  * Object destructor
-  */
-GLOcclusionQuery::~GLOcclusionQuery() 
-{ 
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
-	{
-		glDeleteQueriesARB(1, &mQueryID);  
-	}
-	else if (GLEW_NV_occlusion_query)
-	{
-		glDeleteOcclusionQueriesNV(1, &mQueryID);  
-	}
-}
-//------------------------------------------------------------------
-void GLOcclusionQuery::beginOcclusionQuery() 
-{ 
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
-	{
-		glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mQueryID);
-	}
-	else if (GLEW_NV_occlusion_query)
-	{
-		glBeginOcclusionQueryNV(mQueryID);
-	}
-}
-//------------------------------------------------------------------
-void GLOcclusionQuery::endOcclusionQuery() 
-{ 
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
+namespace BansheeEngine
+{
+	GLOcclusionQuery::GLOcclusionQuery(bool binary)
+		:OcclusionQuery(binary), mQueryObj(0), mNumFragments(0), mFinalized(false)
 	{
-	    glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+		glGenQueries(1, &mQueryObj);
 	}
-	else if (GLEW_NV_occlusion_query)
+
+	GLOcclusionQuery::~GLOcclusionQuery()
 	{
-		glEndOcclusionQueryNV();
+		glDeleteQueries(1, &mQueryObj);
 	}
-	
-}
-//------------------------------------------------------------------
-bool GLOcclusionQuery::pullOcclusionQuery( unsigned int* NumOfFragments ) 
-{
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
+
+	void GLOcclusionQuery::begin()
 	{
-		glGetQueryObjectuivARB(mQueryID, GL_QUERY_RESULT_ARB, (GLuint*)NumOfFragments);
-		mPixelCount = *NumOfFragments;
-		return true;
+		glBeginQuery(mBinary ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED, mQueryObj);
+
+		mNumFragments = 0;
+		setActive(true);
 	}
-	else if (GLEW_NV_occlusion_query)
+
+	void GLOcclusionQuery::end()
 	{
-		glGetOcclusionQueryuivNV(mQueryID, GL_PIXEL_COUNT_NV, (GLuint*)NumOfFragments);
-		mPixelCount = *NumOfFragments;
-		return true;
+		glEndQuery(mBinary ? GL_ANY_SAMPLES_PASSED : GL_SAMPLES_PASSED);
 	}
 
-	return false;
-}
-//------------------------------------------------------------------
-bool GLOcclusionQuery::isStillOutstanding(void)
-{    
-      GLuint available;
-
-    if(GLEW_VERSION_1_5 || GLEW_ARB_occlusion_query)
+	bool GLOcclusionQuery::isReady() const
 	{
-	    glGetQueryObjectuivARB(mQueryID, GL_QUERY_RESULT_AVAILABLE_ARB, &available);
+		GLint done = 0;
+		glGetQueryObjectiv(mQueryObj, GL_QUERY_RESULT_AVAILABLE, &done);
+
+		return done == GL_TRUE;
 	}
-	else if (GLEW_NV_occlusion_query)
+
+	UINT32 GLOcclusionQuery::getNumFragments()
 	{
-	    glGetOcclusionQueryuivNV(mQueryID, GL_PIXEL_COUNT_AVAILABLE_NV, &available);
+		if (!mFinalized && isReady())
+		{
+			finalize();
+		}
+
+		return mNumFragments;
 	}
 
-	// GL_TRUE means a wait would occur
-    return !(available == GL_TRUE);  
-} 
+	void GLOcclusionQuery::finalize()
+	{
+		mFinalized = true;
 
-}
+		if (mBinary)
+		{
+			GLboolean anyPassed = GL_FALSE;
+			glGetQueryObjectuiv(mQueryObj, GL_QUERY_RESULT_ARB, (GLuint*)&anyPassed);
 
+			mNumFragments = anyPassed == GL_TRUE ? 1 : 0;
+		}
+		else
+		{
+			GLuint numFragments = 0;
+			glGetQueryObjectuiv(mQueryObj, GL_QUERY_RESULT_ARB, (GLuint*)&numFragments);
 
+			mNumFragments = (UINT32)numFragments;
+		}
+	}
+}

+ 9 - 0
CamelotGLRenderer/Source/CmGLQueryManager.cpp

@@ -1,6 +1,7 @@
 #include "CmGLQueryManager.h"
 #include "CmGLEventQuery.h"
 #include "CmGLTimerQuery.h"
+#include "CmGLOcclusionQuery.h"
 
 namespace BansheeEngine
 {
@@ -19,4 +20,12 @@ namespace BansheeEngine
 
 		return query;
 	}
+
+	OcclusionQueryPtr GLQueryManager::createOcclusionQuery(bool binary) const
+	{
+		OcclusionQueryPtr query = std::shared_ptr<GLOcclusionQuery>(cm_new<GLOcclusionQuery>(binary), &QueryManager::deleteOcclusionQuery, StdAlloc<GenAlloc>());
+		mOcclusionQueries.push_back(query.get());
+
+		return query;
+	}
 }

+ 1 - 1
Notes.txt

@@ -25,7 +25,6 @@ Reminders:
   - Add Unified shader so I can easily switch between HLSL and GLSL shaders (they need same parameters usually, just different code)
     - Maybe just add support for Cg and force everyone to use that? - I'd like to be able to just switch out renderer in a single location and that everything keeps on working without 
 	  further modifications.
-  - Port boost threads to std threads (CmThreadDefines.h)
   - Remove HardwarePixelBuffer (DX11 doesn't use it, and DX9 and OpenGL textures can be rewritten so they have its methods internally)
   - Multihead device
   - Don't forget to check out Unity DX11 documentation on how to implement DX11 features (http://docs.unity3d.com/Documentation/Manual/DirectX11.html)
@@ -61,6 +60,7 @@ Reminders:
 	  - It really helps when you get an error on a Component that hundreds of SceneObjects use
 	- When displaying an error with a callstack, make each line of the callstack clickable where it opens the external editor
   - std::function allocates memory but I have no got way of using custom allocators as I'd have to wrap std::bind and that seems non-trivial
+  - Add a TaskScheduler profiler that neatly shows time slices of each task and on which thread they are run on
 
 Potential optimizations:
  - bulkPixelConversion is EXTREMELY poorly unoptimized. Each pixel it calls a separate method that does redudant operations every pixel.

+ 3 - 0
TODO.txt

@@ -119,6 +119,9 @@ Low priority TODO
     entire buffer. It would be better to handle this differently. Same thing happens in MeshHeap
  - OpenGL also supports texture views using glTextureView but so far I only use them in DX11
  - I don't have a way to set Texture filtering or wrap modes, default ones are always set on initialization
+ - Module does need to be fixed for multi-threading. If it is created on one thread and used on another, a race condition could occurr. But do I use modules on two different threads?
+   - I will with Debug, and probably others
+   - Making the shutdown/destroy variables atomic should be enough
 ----------------------------------------------------------------------------------------------
 Optional:
  - Need better handling for shader techniques. Some Materials are able to run on all renderers yet I can only specify one. This is problematic

+ 0 - 35
TaskScheduler.txt

@@ -1,35 +0,0 @@
-TaskManager (or JobScheduler)
- - Ensure it only uses 6 threads. Two should be reserved for sim and core thread.
-    - Potentially a separate ThreadPool class?
- - Support for task dependencies
- - Support for task priorities
- - Callable from multiple threads
- - When task is queued a Task object is returned (can be copied)
-   - You may use that for chaining dependencies
-   - For waiting on a task
- - HOW DO I CHECK WHEN TASKS ARE COMPLETE?
-   - Check AsyncOp and use that same approach. In fact maybe use AsyncOp itself within the Task
-
- - Ability for threads to wait() until task is complete. And while waiting to complete tasks themselves.
-  - Only main threads can wait (core and sim threads)
-  - When they wait they will actually stop, and the task scheduler will start a new thread to run tasks in their place
-    - Once the task they are waiting for is done, the new thread is returned to thread pool
-  - When calling wait() and starting a new thread, first check if any active thread is being shut-down and if so, cancel the shutdown instead of creating a new thread
-
- - Tasks should have names (later for visualization and profiling purposes)
-
-
-ThreadPool
- - NEVER start threads manually. Only use ThreadPool.
- - This way I can initialize stack allocators and profiler threads just one for the started threads and don't have to worry about user forgetting how to do that.
-
-
-LATER - Profiler should be able to visualize tasks
-
-------------------
-
-Non-task-scheduler:
-
-Module does need to be fixed for multi-threading. If it is created on one thread and used on another, a race condition could occurr. But do I use modules on two different threads?
- - I will with Debug, and probably others
- - Making the shutdown/destroy variables atomic should be enough