summaryrefslogtreecommitdiff
path: root/Runtime/Misc/BatchDeleteObjects.cpp
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Misc/BatchDeleteObjects.cpp
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Misc/BatchDeleteObjects.cpp')
-rw-r--r--Runtime/Misc/BatchDeleteObjects.cpp221
1 files changed, 221 insertions, 0 deletions
diff --git a/Runtime/Misc/BatchDeleteObjects.cpp b/Runtime/Misc/BatchDeleteObjects.cpp
new file mode 100644
index 0000000..07ab974
--- /dev/null
+++ b/Runtime/Misc/BatchDeleteObjects.cpp
@@ -0,0 +1,221 @@
+#include "UnityPrefix.h"
+#include "BatchDeleteObjects.h"
+#include "Runtime/Threads/Thread.h"
+#include "Runtime/BaseClasses/BaseObject.h"
+#include "Runtime/Mono/MonoIncludes.h"
+#include "Runtime/Profiler/Profiler.h"
+#include "Runtime/Threads/ThreadedStreamBuffer.h"
+
+PROFILER_INFORMATION(gBatchDeleteObjects, "BatchDeleteObjects", kProfilerLoading)
+PROFILER_INFORMATION(gBatchDeleteObjectsThread, "BatchDeleteObjectsThread", kProfilerLoading)
+
+// @TODO: On Angrybots on OS X. We spent 4ms deleting objects in singlethreaded mode on the main thread and 1ms in multithreaded mode on the main thread.
+#define MULTI_THREADED_DELETE 0
+
+// Some classes do not support being deallocated on the main thread.
+bool DoesClassRequireMainThreadDeallocation (int classID)
+{
+ if (classID == ClassID(Shader) || classID == ClassID(PhysicMaterial) || classID == ClassID(Mesh) ||
+ classID == ClassID(Texture) || classID == ClassID(Texture2D) || classID == ClassID(Texture3D) || classID == ClassID(Cubemap) )
+ return true;
+ else
+ return false;
+}
+
+#if MULTI_THREADED_DELETE
+
+#define kTerminateInstruction reinterpret_cast<Object*> (0x1)
+
+struct BatchDeleteManager;
+static BatchDeleteManager* gBatchDeleteManager = NULL;
+
+static void* BatchDeleteStep2Threaded (void* userData);
+
+struct BatchDeleteManager
+{
+ Thread thread;
+ ThreadedStreamBuffer streamBuffer;
+
+ ///////@TODO: Handle when we are out of ring buffer memory.
+
+ BatchDeleteManager ()
+ : streamBuffer (ThreadedStreamBuffer::kModeThreaded, 1024 * 256 * sizeof(Object*) )
+ {
+
+ }
+};
+
+void InitializeBatchDelete ()
+{
+ gBatchDeleteManager = UNITY_NEW(BatchDeleteManager, kMemGarbageCollector);
+ gBatchDeleteManager->thread.SetName ("BatchDeleteObjects");
+ gBatchDeleteManager->thread.Run(BatchDeleteStep2Threaded, mono_domain_get());
+}
+
+void CleanupBatchDelete ()
+{
+ // Send terminate instruction & wait for thread to complete
+ gBatchDeleteManager->streamBuffer.WriteValueType<Object*> (kTerminateInstruction);
+ gBatchDeleteManager->streamBuffer.WriteSubmitData ();
+
+ gBatchDeleteManager->thread.WaitForExit();
+
+ UNITY_DELETE(gBatchDeleteManager, kMemGarbageCollector);
+}
+
+BatchDelete CreateBatchDelete (size_t size)
+{
+ size_t allocationSize = sizeof(Object*)*size;
+ void* objectArray = gBatchDeleteManager->streamBuffer.GetWriteDataPointer (allocationSize, sizeof(Object*));
+
+ BatchDelete batchInfo;
+ batchInfo.reservedObjectCount = size;
+ batchInfo.objectCount = 0;
+ batchInfo.objects = reinterpret_cast<Object**> (objectArray);
+
+ return batchInfo;
+}
+
+static void* BatchDeleteStep2Threaded (void* userData)
+{
+ // Attach mono thread
+ MonoThread* thread = mono_thread_attach((MonoDomain*)userData);
+
+ ThreadedStreamBuffer& threadedStreamBuffer = gBatchDeleteManager->streamBuffer;
+
+ while (true)
+ {
+ Object* object = threadedStreamBuffer.ReadValueType<Object*> ();
+
+ // Terminate instruction. Stop the thread.
+ if (object == kTerminateInstruction)
+ return NULL;
+
+ // Delete the object
+ if (object != NULL)
+ delete_object_internal_step2 (object);
+
+ threadedStreamBuffer.ReadReleaseData ();
+ }
+
+ // Detach mono thread
+ mono_thread_detach(thread);
+
+ return NULL;
+}
+
+void SharkBeginRemoteProfiling ();
+void SharkEndRemoteProfiling ();
+
+/// Callbacks like ScriptableObject.OnDestroy etc must be called before invoking this function.
+void BatchDeleteObjectInternal (const SInt32* unloadObjects, int size)
+{
+ if (size == 0)
+ return;
+
+ PROFILER_AUTO(gBatchDeleteObjects, NULL)
+
+ BatchDelete batch = CreateBatchDelete (size);
+ int destroyObjectIndex = 0;
+ for (int i=0;i<size;i++)
+ {
+ Object* object = Object::IDToPointer(unloadObjects[i]);
+ batch.objects[destroyObjectIndex] = object;
+ }
+ batch.objectCount = destroyObjectIndex;
+
+ CommitBatchDelete(batch);
+}
+
+void CommitBatchDelete (BatchDelete& batchDelete)
+{
+ Assert(batchDelete.reservedObjectCount >= batchDelete.objectCount);
+
+ LockObjectCreation();
+
+ for (int i=0;i<batchDelete.objectCount;i++)
+ {
+ Object* object = batchDelete.objects[i];
+
+ if (object == NULL)
+ continue;
+
+ delete_object_internal_step1 (object);
+
+ int classID = object->GetClassID();
+ if (DoesClassRequireMainThreadDeallocation (classID))
+ {
+ bool requiresThreadCleanup = object->MainThreadCleanup ();
+ /// DoesClassRequireMainThreadDeallocation does not agree with MainThreadCleanup
+ /// Fix DoesClassRequireMainThreadDeallocation or MainThreadCleanup for that class.
+ Assert(requiresThreadCleanup);
+ }
+ }
+
+ for (int i=batchDelete.objectCount;i<batchDelete.reservedObjectCount;i++)
+ batchDelete.objects[i] = NULL;
+
+ UnlockObjectCreation();
+
+ gBatchDeleteManager->streamBuffer.WriteSubmitData ();
+}
+
+
+#else
+
+BatchDelete CreateBatchDelete (size_t size)
+{
+ BatchDelete batch;
+
+ batch.objects = (Object**)UNITY_MALLOC(kMemGarbageCollector, sizeof(Object*)*size);
+ batch.reservedObjectCount = size;
+ batch.objectCount = 0;
+
+ return batch;
+}
+
+void CommitBatchDelete (BatchDelete& batchDelete)
+{
+ PROFILER_AUTO(gBatchDeleteObjectsThread, NULL)
+
+ Assert(batchDelete.reservedObjectCount >= batchDelete.objectCount);
+
+ LockObjectCreation();
+
+ for (int i=0;i<batchDelete.objectCount;i++)
+ {
+ Object* object = batchDelete.objects[i];
+ if (object != NULL)
+ {
+ delete_object_internal_step1 (object);
+ delete_object_internal_step2 (object);
+ }
+ }
+
+ UnlockObjectCreation();
+
+ // Cleanup temp storage
+ UNITY_FREE(kMemGarbageCollector, batchDelete.objects);
+}
+
+void BatchDeleteObjectInternal (const SInt32* unloadObjects, int size)
+{
+ PROFILER_AUTO(gBatchDeleteObjectsThread, NULL)
+
+ BatchDelete batchInfo = CreateBatchDelete (size);
+ batchInfo.objectCount = size;
+ for (int i=0;i<size;i++)
+ batchInfo.objects[i] = Object::IDToPointer(unloadObjects[i]);
+
+ CommitBatchDelete (batchInfo);
+}
+
+void InitializeBatchDelete ()
+{
+}
+
+void CleanupBatchDelete ()
+{
+}
+
+#endif