Quellcode durchsuchen

WIP: Linux port
- Fixing a Mono crash related to incorrectly holding references to managed objects
- Fixed an issue where mouse button states weren't reflecting the most recent state

Marko Pintera vor 8 Jahren
Ursprung
Commit
2dd8b70c85

+ 11 - 4
Source/BansheeCore/Linux/BsLinuxPlatform.cpp

@@ -812,20 +812,28 @@ namespace bs
 			{
 				UINT32 button = event.xbutton.button;
 
+				OSPointerButtonStates btnStates;
+				btnStates.mouseButtons[0] = (event.xbutton.state & Button1Mask) != 0;
+				btnStates.mouseButtons[1] = (event.xbutton.state & Button2Mask) != 0;
+				btnStates.mouseButtons[2] = (event.xbutton.state & Button3Mask) != 0;
+
 				OSMouseButton mouseButton;
 				bool validPress = false;
 				switch(button)
 				{
 				case Button1:
 					mouseButton = OSMouseButton::Left;
+					btnStates.mouseButtons[0] = true;
 					validPress = true;
 					break;
 				case Button2:
 					mouseButton = OSMouseButton::Middle;
+					btnStates.mouseButtons[1] = true;
 					validPress = true;
 					break;
 				case Button3:
 					mouseButton = OSMouseButton::Right;
+					btnStates.mouseButtons[2] = true;
 					validPress = true;
 					break;
 
@@ -840,12 +848,8 @@ namespace bs
 					pos.x = event.xbutton.x_root;
 					pos.y = event.xbutton.y_root;
 
-					OSPointerButtonStates btnStates;
 					btnStates.ctrl = (event.xbutton.state & ControlMask) != 0;
 					btnStates.shift = (event.xbutton.state & ShiftMask) != 0;
-					btnStates.mouseButtons[0] = (event.xbutton.state & Button1Mask) != 0;
-					btnStates.mouseButtons[1] = (event.xbutton.state & Button2Mask) != 0;
-					btnStates.mouseButtons[2] = (event.xbutton.state & Button3Mask) != 0;
 
 					onCursorButtonPressed(pos, mouseButton, btnStates);
 
@@ -890,12 +894,15 @@ namespace bs
 				switch(button)
 				{
 				case Button1:
+					btnStates.mouseButtons[0] = false;
 					onCursorButtonReleased(pos, OSMouseButton::Left, btnStates);
 					break;
 				case Button2:
+					btnStates.mouseButtons[1] = false;
 					onCursorButtonReleased(pos, OSMouseButton::Middle, btnStates);
 					break;
 				case Button3:
+					btnStates.mouseButtons[2] = false;
 					onCursorButtonReleased(pos, OSMouseButton::Right, btnStates);
 					break;
 				case Button4: // Vertical mouse wheel

+ 6 - 1
Source/BansheeMono/BsMonoUtil.cpp

@@ -125,7 +125,7 @@ namespace bs
 
 	UINT32 MonoUtil::newGCHandle(MonoObject* object)
 	{
-		return mono_gchandle_new(object, false);
+		return mono_gchandle_new(object, true);
 	}
 
 	void MonoUtil::freeGCHandle(UINT32 handle)
@@ -133,6 +133,11 @@ namespace bs
 		mono_gchandle_free(handle);
 	}
 
+	MonoObject* MonoUtil::getObjectFromGCHandle(UINT32 handle)
+	{
+		return mono_gchandle_get_target(handle);
+	}
+
 	MonoObject* MonoUtil::box(::MonoClass* klass, void* value)
 	{
 		return mono_value_box(MonoManager::instance().getDomain(), klass, value);

+ 8 - 1
Source/BansheeMono/BsMonoUtil.h

@@ -47,12 +47,19 @@ namespace bs
 		/** Returns the type of the provided class. */
 		static MonoReflectionType* getType(::MonoClass* klass);
 
-		/** Creates a new GC handle for the provided managed object, ensuring it doesn't go out of scope. */
+		/**
+		 * Creates a new GC handle for the provided managed object, ensuring it doesn't go out of scope.
+		 * Note that after creating a handle you MUST call getObjectFromGCHandle() to get the latest MonoObject*, as
+		 * GC could have potentially moved the object to a new address.
+		 *  */
 		static UINT32 newGCHandle(MonoObject* object);
 
 		/** Frees a GC handle previously allocated with newGCHandle. */
 		static void freeGCHandle(UINT32 handle);
 
+		/** Returns a MonoObject from an allocated GC handle. */
+		static MonoObject* getObjectFromGCHandle(UINT32 handle);
+
 		/** Converts a managed value type into a reference type by boxing it. */
 		static MonoObject* box(::MonoClass* klass, void* value);
 

+ 6 - 5
Source/BansheeUtility/Linux/BsUnixPlatformUtility.cpp

@@ -123,14 +123,15 @@ namespace bs
 		return output;
 	}
 
-	String PlatformUtility::generateUUID()
+	UUID PlatformUtility::generateUUID()
 	{
 		uuid_t nativeUUID;
 		uuid_generate(nativeUUID);
 
-		char uuidChars[37];
-		uuid_unparse(nativeUUID, uuidChars);
-
-		return String(uuidChars);
+		return UUID(
+				*(UINT32*)&nativeUUID[0],
+				*(UINT32*)&nativeUUID[4],
+				*(UINT32*)&nativeUUID[8],
+				*(UINT32*)&nativeUUID[12]);
 	}
 }

+ 8 - 2
Source/BansheeUtility/Utility/BsAny.h

@@ -76,13 +76,19 @@ namespace bs
 		template <typename ValueType>
 		Any& operator= (const ValueType& rhs)
 		{
-			Any(rhs).swap(*this);
+			if(mData)
+				bs_delete(mData);
+
+			mData = bs_new<Data<ValueType>>(rhs);
 			return *this;
 		}
 
 		Any& operator= (const Any& rhs)
 		{
-			Any(rhs).swap(*this);
+			if(mData)
+				bs_delete(mData);
+
+			mData = rhs.mData != nullptr ? rhs.mData->clone() : nullptr;
 			return *this;
 		}
 

+ 19 - 4
Source/SBansheeEditor/BsManagedEditorCommand.cpp

@@ -62,6 +62,21 @@ namespace bs
 		mManagedCommand = nullptr;
 	}
 
+	void ScriptCmdManaged::allocGCHandle()
+	{
+		if (mGCHandle == 0)
+		{
+			mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
+			mManagedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle);
+		}
+	}
+
+	void ScriptCmdManaged::freeGCHandle()
+	{
+		if(mGCHandle != 0)
+			MonoUtil::freeGCHandle(mGCHandle);
+	}
+
 	CmdManaged::CmdManaged(ScriptCmdManaged* scriptObj)
 		: EditorCommand(L""), mScriptObj(scriptObj), mGCHandle(0), mRefCount(0)
 	{
@@ -106,8 +121,8 @@ namespace bs
 
 	void CmdManaged::onCommandAdded()
 	{
-		if (mGCHandle == 0 && mScriptObj != nullptr)
-			mGCHandle = MonoUtil::newGCHandle(mScriptObj->getManagedInstance());
+		if(mScriptObj)
+			mScriptObj->allocGCHandle();
 
 		mRefCount++;
 	}
@@ -118,8 +133,8 @@ namespace bs
 
 		mRefCount--;
 
-		if (mRefCount == 0 && mGCHandle != 0)
-			MonoUtil::freeGCHandle(mGCHandle);
+		if (mRefCount == 0)
+			mScriptObj->freeGCHandle();
 	}
 
 	void CmdManaged::notifyScriptInstanceDestroyed()

+ 10 - 0
Source/SBansheeEditor/BsManagedEditorCommand.h

@@ -36,10 +36,20 @@ namespace bs
 		/** Triggers the Revert() method on the managed object instance. */
 		void triggerRevert();
 
+		/**
+		 * Allocates a GC handle that ensures the object doesn't get GC collected. Must eventually be followed by
+		 * freeGCHandle().
+		 */
+		void allocGCHandle();
+
+		/** Frees a GC handle previously allocated from allocGCHandle(). */
+		void freeGCHandle();
+
 		/** Notifies the script instance that the underlying managed command was destroyed. */
 		void notifyCommandDestroyed();
 
 		SPtr<CmdManaged> mManagedCommand;
+		UINT32 mGCHandle = 0;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/

+ 14 - 13
Source/SBansheeEditor/BsScriptHandleManager.cpp

@@ -40,11 +40,11 @@ namespace bs
 		{
 			MonoObject* newHandleInstance = handle->createInstance();
 
-			mActiveGlobalHandles.push_back(ActiveCustomHandleData());
-			ActiveCustomHandleData& newHandleData = mActiveGlobalHandles.back();
+			ActiveCustomHandleData data;
+			data.gcHandle = MonoUtil::newGCHandle(newHandleInstance);
+			data.object = MonoUtil::getObjectFromGCHandle(data.gcHandle);
 
-			newHandleData.object = newHandleInstance;
-			newHandleData.gcHandle = MonoUtil::newGCHandle(newHandleInstance);
+			mActiveGlobalHandles.push_back(data);
 		}
 
 		mGlobalHandlesToCreate.clear();
@@ -92,19 +92,21 @@ namespace bs
 					void* params[1] = { mc->getManagedInstance() };
 					handleData.ctor->invoke(newHandleInstance, params);
 
-					mActiveHandleData.handles.push_back(ActiveCustomHandleData());
-					ActiveCustomHandleData& newHandleData = mActiveHandleData.handles.back();
+					ActiveCustomHandleData data;
+					data.gcHandle = MonoUtil::newGCHandle(newHandleInstance);
+					data.object = MonoUtil::getObjectFromGCHandle(data.gcHandle);
 
-					newHandleData.object = newHandleInstance;
-					newHandleData.gcHandle = MonoUtil::newGCHandle(newHandleInstance);
+					mActiveHandleData.handles.push_back(data);
 				}
 			}
 		}
 
 		if (mDefaultHandleManager == nullptr)
 		{
-			mDefaultHandleManager = mDefaultHandleManagerClass->createInstance(true);
-			mDefaultHandleManagerGCHandle = MonoUtil::newGCHandle(mDefaultHandleManager);
+			MonoObject* defaultHandleManager = mDefaultHandleManagerClass->createInstance(true);
+
+			mDefaultHandleManagerGCHandle = MonoUtil::newGCHandle(defaultHandleManager);
+			mDefaultHandleManager = MonoUtil::getObjectFromGCHandle(mDefaultHandleManagerGCHandle);
 		}
 
 		callPreInput(mDefaultHandleManager);
@@ -129,8 +131,7 @@ namespace bs
 
 	void ScriptHandleManager::queueDrawCommands()
 	{
-		if (mDefaultHandleManager != nullptr)
-			callDraw(mDefaultHandleManager);
+		callDraw(mDefaultHandleManager);
 
 		for (auto& handle : mActiveGlobalHandles)
 			callDraw(handle.object);
@@ -246,7 +247,7 @@ namespace bs
 			::MonoClass* attribMonoClass = MonoUtil::getClass(attribReflType);
 
 			MonoClass* attribClass = MonoManager::instance().findClass(attribMonoClass);
-			if (attribClass != nullptr)
+			if (attribClass == nullptr)
 				return false;
 
 			MonoClass* componentClass = mScriptObjectManager.getComponentClass();

+ 1 - 0
Source/SBansheeEditor/Wrappers/BsScriptDropDownWindow.cpp

@@ -178,6 +178,7 @@ namespace bs
 		, mScriptParent(nullptr), mContentsPanel(nullptr)
 	{
 		mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
+		mManagedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 
 		MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContents);
 		mContentsPanel = ScriptGUILayout::toNative(guiPanel);

+ 10 - 3
Source/SBansheeEditor/Wrappers/BsScriptEditorWindow.cpp

@@ -137,10 +137,10 @@ namespace bs
 		auto iterFind = OpenScriptEditorWindows.find(mName);
 		if (iterFind != OpenScriptEditorWindows.end())
 		{
-			EditorWindowHandle handle = iterFind->second;
+			EditorWindowHandle& handle = iterFind->second;
 
 			MonoUtil::freeGCHandle(handle.gcHandle);
-			iterFind->second.gcHandle = 0;
+			handle.gcHandle = 0;
 		}
 
 		return PersistentScriptObjectBase::beginRefresh();
@@ -159,7 +159,12 @@ namespace bs
 		{
 			auto iterFind = OpenScriptEditorWindows.find(mName);
 			if (iterFind != OpenScriptEditorWindows.end())
-				iterFind->second.gcHandle = MonoUtil::newGCHandle(mManagedInstance);
+			{
+				EditorWindowHandle& handle = iterFind->second;
+
+				handle.gcHandle = MonoUtil::newGCHandle(mManagedInstance);
+				mManagedInstance = MonoUtil::getObjectFromGCHandle(handle.gcHandle);
+			}
 		}
 		else
 		{
@@ -395,6 +400,8 @@ namespace bs
 			newHandle.nativeObj = editorWindow;
 			newHandle.gcHandle = MonoUtil::newGCHandle(editorWindow->mManagedInstance);
 
+			editorWindow->mManagedInstance = MonoUtil::getObjectFromGCHandle(newHandle.gcHandle);
+
 			OpenScriptEditorWindows[editorWindow->mName] = newHandle;
 		}
 	}

+ 2 - 0
Source/SBansheeEditor/Wrappers/BsScriptModalWindow.cpp

@@ -131,6 +131,7 @@ namespace bs
 		, mGCHandle(0), mScriptParent(nullptr), mContentsPanel(nullptr)
 	{
 		mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
+		mManagedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 
 		MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContents);
 		mContentsPanel = ScriptGUILayout::toNative(guiPanel);
@@ -163,6 +164,7 @@ namespace bs
 			{
 				mManagedInstance = editorWindowClass->createInstance(false);
 				mGCHandle = MonoUtil::newGCHandle(mManagedInstance);
+				mManagedInstance = MonoUtil::getObjectFromGCHandle(mGCHandle);
 
 				MonoObject* guiPanel = ScriptGUIPanel::createFromExisting(mContents);
 				mContentsPanel = ScriptGUILayout::toNative(guiPanel);

+ 2 - 1
Source/SBansheeEngine/BsManagedComponent.cpp

@@ -140,8 +140,9 @@ namespace bs
 		if (mManagedInstance != nullptr)
 		{
 			mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
+			mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
-			::MonoClass* monoClass = MonoUtil::getClass(object);
+			::MonoClass* monoClass = MonoUtil::getClass(mManagedInstance);
 			mRuntimeType = MonoUtil::getType(monoClass);
 
 			mManagedClass = MonoManager::instance().findClass(monoClass);

+ 3 - 2
Source/SBansheeEngine/BsManagedResource.cpp

@@ -75,6 +75,7 @@ namespace bs
 		if (mManagedInstance != nullptr)
 		{
 			mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
+			mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
 			if (data.data != nullptr)
 			{
@@ -118,8 +119,8 @@ namespace bs
 
 	void ManagedResource::setHandle(MonoObject* object, const HManagedResource& myHandle)
 	{
-		mManagedInstance = object;
-		mManagedHandle = MonoUtil::newGCHandle(mManagedInstance);
+		mManagedHandle = MonoUtil::newGCHandle(object);
+		mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 		mMyHandle = myHandle.getWeak();
 
 		ScriptResourceManager::instance().createManagedScriptResource(myHandle, object);

+ 2 - 0
Source/SBansheeEngine/Wrappers/BsScriptComponent.h

@@ -57,6 +57,7 @@ namespace bs
 			:ScriptObject<ScriptClass, BaseType>(instance), mComponent(component)
 		{
 			mManagedHandle = MonoUtil::newGCHandle(instance);
+			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
 			BS_DEBUG_ONLY(mHandleValid = true);
 		}
@@ -71,6 +72,7 @@ namespace bs
 		{
 			BS_ASSERT(!mHandleValid);
 			mManagedHandle = MonoUtil::newGCHandle(this->mManagedInstance);
+			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
 			ScriptObject<ScriptClass, BaseType>::endRefresh(backupData);
 		}

+ 2 - 0
Source/SBansheeEngine/Wrappers/BsScriptResource.h

@@ -66,6 +66,7 @@ namespace bs
 			:ScriptObject<ScriptClass, BaseType>(instance), mResource(resource)
 		{
 			mManagedHandle = MonoUtil::newGCHandle(instance);
+			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
 			BS_DEBUG_ONLY(mHandleValid = true);
 		}
@@ -80,6 +81,7 @@ namespace bs
 		{
 			BS_ASSERT(!mHandleValid);
 			mManagedHandle = MonoUtil::newGCHandle(this->mManagedInstance);
+			this->mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 
 			ScriptObject<ScriptClass, BaseType>::endRefresh(backupData);
 		}

+ 2 - 2
Source/SBansheeEngine/Wrappers/BsScriptSceneObject.cpp

@@ -16,6 +16,7 @@ namespace bs
 		:ScriptObject(instance), mSceneObject(sceneObject)
 	{
 		mManagedHandle = MonoUtil::newGCHandle(instance);
+		mManagedInstance = MonoUtil::getObjectFromGCHandle(mManagedHandle);
 	}
 
 	void ScriptSceneObject::initRuntimeData()
@@ -413,8 +414,7 @@ namespace bs
 	{
 		MonoObject* managedInstance = metaData.scriptClass->createInstance(construct);
 		mManagedHandle = MonoUtil::newGCHandle(managedInstance);
-
-		return managedInstance;
+		return MonoUtil::getObjectFromGCHandle(mManagedHandle);
 	}
 
 	void ScriptSceneObject::_notifyDestroyed()