Browse Source

Solved some more problems with freeing core objects on shutdown

Marko Pintera 11 years ago
parent
commit
6dc2337e53

+ 1 - 1
BansheeCore/Include/BsMeshHeap.h

@@ -195,7 +195,7 @@ namespace BansheeEngine
 		 * @brief	Called by an GPU event query when GPU processes the query. Normally
 		 *			signals the heap that the GPU is done with the mesh.
 		 */
-		void queryTriggered(UINT32 meshId, UINT32 queryId);
+		static void queryTriggered(MeshHeapPtr thisPtr, UINT32 meshId, UINT32 queryId);
 
 		/**
 		 * @brief	Attempts to reorganize the vertex and index buffer chunks in order to 

+ 12 - 0
BansheeCore/Include/BsQueryManager.h

@@ -51,22 +51,34 @@ namespace BansheeEngine
 
 		/**
 		 * @brief	Deletes an Event query. Always use this method and don't delete them manually.
+		 *			Actual deletion will be delayed until next update.
 		 */
 		static void deleteEventQuery(EventQuery* query);
 
 		/**
 		* @brief	Deletes a Timer query. Always use this method and don't delete them manually.
+		*			Actual deletion will be delayed until next update.
 		*/
 		static void deleteTimerQuery(TimerQuery* query);
 
 		/**
 		* @brief	Deletes an Occlusion query. Always use this method and don't delete them manually.
+		*			Actual deletion will be delayed until next update.
 		*/
 		static void deleteOcclusionQuery(OcclusionQuery* query);
 
+		/**
+		 * @brief	Deletes any queued queries.
+		 */
+		void processDeletedQueue();
+
 	protected:
 		mutable Vector<EventQuery*> mEventQueries;
 		mutable Vector<TimerQuery*> mTimerQueries;
 		mutable Vector<OcclusionQuery*> mOcclusionQueries;
+
+		mutable Vector<EventQuery*> mDeletedEventQueries;
+		mutable Vector<TimerQuery*> mDeletedTimerQueries;
+		mutable Vector<OcclusionQuery*> mDeletedOcclusionQueries;
 	};
 }

+ 15 - 10
BansheeCore/Source/BsMeshHeap.cpp

@@ -550,23 +550,26 @@ namespace BansheeEngine
 		if(allocData.useFlags == UseFlags::GPUFree)
 			allocData.useFlags = UseFlags::Used;
 
+		MeshHeapPtr thisPtr = std::static_pointer_cast<MeshHeap>(getThisPtr());
+
 		QueryData& queryData = mEventQueries[allocData.eventQueryIdx];
 		queryData.queryId = mNextQueryId++;
 		queryData.query->onTriggered.clear();
-		queryData.query->onTriggered.connect(std::bind(&MeshHeap::queryTriggered, this, meshId, queryData.queryId));
+		queryData.query->onTriggered.connect(std::bind(&MeshHeap::queryTriggered, thisPtr, meshId, queryData.queryId));
 		queryData.query->begin();
 	}
 
-	void MeshHeap::queryTriggered(UINT32 meshId, UINT32 queryId)
+	// Note: Need to use a shared ptr here to ensure MeshHeap doesn't get deallocated sometime during this callback
+	void MeshHeap::queryTriggered(MeshHeapPtr thisPtr, UINT32 meshId, UINT32 queryId)
 	{
-		auto findIter = mMeshAllocData.find(meshId);
-		assert(findIter != mMeshAllocData.end());
+		auto findIter = thisPtr->mMeshAllocData.find(meshId);
+		assert(findIter != thisPtr->mMeshAllocData.end());
 
 		AllocatedData& allocData = findIter->second;
 
 		// If query ids don't match then it means there either a more recent query or
 		// the buffer was discarded and we are not interested in query result
-		QueryData& queryData = mEventQueries[allocData.eventQueryIdx];
+		QueryData& queryData = thisPtr->mEventQueries[allocData.eventQueryIdx];
 		if(queryId == queryData.queryId) 
 		{
 			assert(allocData.useFlags != UseFlags::Free && allocData.useFlags != UseFlags::GPUFree);
@@ -574,18 +577,20 @@ namespace BansheeEngine
 			if(allocData.useFlags == UseFlags::CPUFree)
 			{
 				allocData.useFlags = UseFlags::Free;
-				freeEventQuery(allocData.eventQueryIdx);
+				thisPtr->freeEventQuery(allocData.eventQueryIdx);
 
-				mFreeVertChunks.push_back(allocData.vertChunkIdx);
-				mFreeIdxChunks.push_back(allocData.idxChunkIdx);
+				thisPtr->mFreeVertChunks.push_back(allocData.vertChunkIdx);
+				thisPtr->mFreeIdxChunks.push_back(allocData.idxChunkIdx);
 
-				mergeWithNearbyChunks(allocData.vertChunkIdx, allocData.idxChunkIdx);
+				thisPtr->mergeWithNearbyChunks(allocData.vertChunkIdx, allocData.idxChunkIdx);
 
-				mMeshAllocData.erase(findIter);
+				thisPtr->mMeshAllocData.erase(findIter);
 			}
 			else
 				allocData.useFlags = UseFlags::GPUFree;
 		}
+
+		queryData.query->onTriggered.clear();
 	}
 
 	void MeshHeap::mergeWithNearbyChunks(UINT32 chunkVertIdx, UINT32 chunkIdxIdx)

+ 44 - 16
BansheeCore/Source/BsQueryManager.cpp

@@ -31,6 +31,8 @@ namespace BansheeEngine
 			if (query->isActive())
 				query->onComplete(query->getNumSamples());
 		}
+
+		processDeletedQueue();
 	}
 
 	void QueryManager::_update()
@@ -61,35 +63,61 @@ namespace BansheeEngine
 				query->setActive(false);
 			}
 		}
+
+		processDeletedQueue();
 	}
 
 	void QueryManager::deleteEventQuery(EventQuery* query)
 	{
-		auto iterFind = std::find(instance().mEventQueries.begin(), instance().mEventQueries.end(), query);
-
-		if(iterFind != instance().mEventQueries.end())
-			instance().mEventQueries.erase(iterFind);
-
-		bs_delete(query);
+		instance().mDeletedEventQueries.push_back(query);
 	}
 
 	void QueryManager::deleteTimerQuery(TimerQuery* query)
 	{
-		auto iterFind = std::find(instance().mTimerQueries.begin(), instance().mTimerQueries.end(), query);
-
-		if(iterFind != instance().mTimerQueries.end())
-			instance().mTimerQueries.erase(iterFind);
-
-		bs_delete(query);
+		instance().mDeletedTimerQueries.push_back(query);
 	}
 
 	void QueryManager::deleteOcclusionQuery(OcclusionQuery* query)
 	{
-		auto iterFind = std::find(instance().mOcclusionQueries.begin(), instance().mOcclusionQueries.end(), query);
+		instance().mDeletedOcclusionQueries.push_back(query);
+	}
+
+	void QueryManager::processDeletedQueue()
+	{
+		for (auto& query : mDeletedEventQueries)
+		{
+			auto iterFind = std::find(mEventQueries.begin(), mEventQueries.end(), query);
+
+			if (iterFind != mEventQueries.end())
+				mEventQueries.erase(iterFind);
+
+			bs_delete(query);
+		}
+
+		mDeletedEventQueries.clear();
+
+		for (auto& query : mDeletedTimerQueries)
+		{
+			auto iterFind = std::find(mTimerQueries.begin(), mTimerQueries.end(), query);
+
+			if (iterFind != mTimerQueries.end())
+				mTimerQueries.erase(iterFind);
+
+			bs_delete(query);
+		}
+
+		mDeletedTimerQueries.clear();
+
+		for (auto& query : mDeletedOcclusionQueries)
+		{
+			auto iterFind = std::find(mOcclusionQueries.begin(), mOcclusionQueries.end(), query);
+
+			if (iterFind != mOcclusionQueries.end())
+				mOcclusionQueries.erase(iterFind);
 
-		if (iterFind != instance().mOcclusionQueries.end())
-			instance().mOcclusionQueries.erase(iterFind);
+			bs_delete(query);
+		}
 
-		bs_delete(query);
+		mDeletedOcclusionQueries.clear();
 	}
 }

+ 12 - 3
BansheeUtility/Include/BsEvent.h

@@ -134,7 +134,10 @@ namespace BansheeEngine
 			// the notify callback
 			UINT32 numConnections = (UINT32)internalData->mConnections.size(); // Remember current num. connections as we don't want to notify new ones
 			for (UINT32 i = 0; i < numConnections; i++)
-				internalData->mConnections[i]->func(args...);
+			{
+				if (internalData->mConnections[i]->func != nullptr)
+					internalData->mConnections[i]->func(args...);
+			}
 		}
 
 		/**
@@ -145,7 +148,10 @@ namespace BansheeEngine
 			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
 
 			for (auto& connection : mInternalData->mConnections)
+			{
 				connection->isValid = false;
+				connection->func = nullptr;
+			}
 
 			if (mInternalData->mConnections.size() > 0)
 				mInternalData->mHasDisconnectedCallbacks = true;
@@ -184,11 +190,14 @@ namespace BansheeEngine
 		{
 			BS_LOCK_RECURSIVE_MUTEX(mInternalData->mMutex);
 
+			std::shared_ptr<ConnectionData> myConnData = std::static_pointer_cast<ConnectionData>(connData);
+
 			for (auto& iter = mInternalData->mConnections.begin(); iter != mInternalData->mConnections.end(); ++iter)
 			{
-				if((*iter) == connData)
+				if ((*iter) == myConnData)
 				{
-					connData->isValid = false;
+					myConnData->isValid = false;
+					myConnData->func = nullptr;
 					mInternalData->mHasDisconnectedCallbacks = true;
 					return;
 				}

+ 2 - 0
Notes.txt

@@ -60,6 +60,8 @@ Reminders:
   - DDS file import
   - Make hierarchical documentation. Organize stuff based on type. Once I actually generate the documentation add Doxygen grouping tags (or whatever they're called)
   - Make a Getting Started guide, along with the example project. Or just finish up the manual.
+  - I'm not too happy with HStrings using so many events. They use one internally which I think I can replace completely quite easily. And one externally for notifying GUI components, replacing
+    which would require more thought.
 
 Potential optimizations:
  - bulkPixelConversion is EXTREMELY poorly unoptimized. Each pixel it calls a separate method that does redudant operations every pixel.