Explorar el Código

[unity] Added option for unsafe data loading avoiding some allocations on skel.bytes data. Closes #2851.

Harald Csaszar hace 3 meses
padre
commit
fb8bc402e7

+ 1 - 0
CHANGELOG.md

@@ -175,6 +175,7 @@
     2. Add a `RenderExistingMeshGraphic` component.
     2. Add a `RenderExistingMeshGraphic` component.
     3. In the `RenderExistingMeshGraphic` component Inspector at `Reference Skeleton Graphic` assign the original `SkeletonGraphic` object.
     3. In the `RenderExistingMeshGraphic` component Inspector at `Reference Skeleton Graphic` assign the original `SkeletonGraphic` object.
     4. At `Replacement Material` assign e.g. the included _SkeletonGraphicDefaultOutline_ material to replace all materials with this material. Alternatively, if `Multiple CanvasRenderers` is enabled at the reference SkeletonGraphic, you can add entries to the `Replacement Materials` list and at each entry assign the original SkeletonGraphic material (e.g. _SkeletonGraphicDefault_) to be replaced and the respective `Replacement Material` (e.g. _SkeletonGraphicDefaultOutline_).
     4. At `Replacement Material` assign e.g. the included _SkeletonGraphicDefaultOutline_ material to replace all materials with this material. Alternatively, if `Multiple CanvasRenderers` is enabled at the reference SkeletonGraphic, you can add entries to the `Replacement Materials` list and at each entry assign the original SkeletonGraphic material (e.g. _SkeletonGraphicDefault_) to be replaced and the respective `Replacement Material` (e.g. _SkeletonGraphicDefaultOutline_).
+  - Added option for unsafe direct data loading when loading skeleton binary data to avoid some allocations, enabled via build define `SPINE_ALLOW_UNSAFE`. This define can be set via Spine Preferences, setting `Unsafe Build Defines - Direct data access`. The define is disabled by default to maintain existing behaviour. Changed asmdef setting for spine-unity assembly to allow unsafe code, has no effect other than allowing setting the `SPINE_ALLOW_UNSAFE` define.
 
 
 - **Breaking changes**
 - **Breaking changes**
 
 

+ 26 - 18
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/BuildSettings.cs

@@ -83,6 +83,8 @@ namespace Spine.Unity.Editor {
 	}
 	}
 
 
 	public static class SpineBuildEnvUtility {
 	public static class SpineBuildEnvUtility {
+		public const string SPINE_ALLOW_UNSAFE_CODE = "SPINE_ALLOW_UNSAFE";
+
 		static bool IsInvalidGroup (BuildTargetGroup group) {
 		static bool IsInvalidGroup (BuildTargetGroup group) {
 			int gi = (int)group;
 			int gi = (int)group;
 			return
 			return
@@ -99,15 +101,18 @@ namespace Spine.Unity.Editor {
 				if (IsInvalidGroup(group))
 				if (IsInvalidGroup(group))
 					continue;
 					continue;
 
 
-				string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
-				if (!defines.Contains(define)) {
-					wasDefineAdded = true;
-					if (defines.EndsWith(";", System.StringComparison.Ordinal))
-						defines += define;
-					else
-						defines += ";" + define;
-
-					PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
+				try {
+					string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
+					if (!defines.Contains(define)) {
+						wasDefineAdded = true;
+						if (defines.EndsWith(";", System.StringComparison.Ordinal))
+							defines += define;
+						else
+							defines += ";" + define;
+
+						PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
+					}
+				} catch (System.Exception) {
 				}
 				}
 			}
 			}
 			Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" above");
 			Debug.LogWarning("Please ignore errors \"PlayerSettings Validation: Requested build target group doesn't exist\" above");
@@ -127,15 +132,18 @@ namespace Spine.Unity.Editor {
 				if (IsInvalidGroup(group))
 				if (IsInvalidGroup(group))
 					continue;
 					continue;
 
 
-				string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
-				if (defines.Contains(define)) {
-					wasDefineRemoved = true;
-					if (defines.Contains(define + ";"))
-						defines = defines.Replace(define + ";", "");
-					else
-						defines = defines.Replace(define, "");
-
-					PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
+				try {
+					string defines = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
+					if (defines.Contains(define)) {
+						wasDefineRemoved = true;
+						if (defines.Contains(define + ";"))
+							defines = defines.Replace(define + ";", "");
+						else
+							defines = defines.Replace(define, "");
+
+						PlayerSettings.SetScriptingDefineSymbolsForGroup(group, defines);
+					}
+				} catch (System.Exception) {
 				}
 				}
 			}
 			}
 
 

+ 20 - 0
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SpinePreferences.cs

@@ -39,6 +39,14 @@
 #define HAS_ON_POSTPROCESS_PREFAB
 #define HAS_ON_POSTPROCESS_PREFAB
 #endif
 #endif
 
 
+#if UNITY_2021_2_OR_NEWER
+#define TEXT_ASSET_HAS_GET_DATA_BYTES
+#endif
+
+#if TEXT_ASSET_HAS_GET_DATA_BYTES
+#define HAS_ANY_UNSAFE_OPTIONS
+#endif
+
 using System.Threading;
 using System.Threading;
 using UnityEditor;
 using UnityEditor;
 using UnityEngine;
 using UnityEngine;
@@ -356,6 +364,18 @@ namespace Spine.Unity.Editor {
 				}
 				}
 #endif
 #endif
 
 
+#if HAS_ANY_UNSAFE_OPTIONS
+				GUILayout.Space(20);
+				EditorGUILayout.LabelField("Unsafe Build Defines", EditorStyles.boldLabel);
+				using (new GUILayout.HorizontalScope()) {
+					EditorGUILayout.PrefixLabel(new GUIContent("Direct data access", "Allow unsafe direct data access. Currently affects reading .skel.bytes files, reading with fewer allocations."));
+					if (GUILayout.Button("Enable", GUILayout.Width(64)))
+						SpineBuildEnvUtility.EnableBuildDefine(SpineBuildEnvUtility.SPINE_ALLOW_UNSAFE_CODE);
+					if (GUILayout.Button("Disable", GUILayout.Width(64)))
+						SpineBuildEnvUtility.DisableBuildDefine(SpineBuildEnvUtility.SPINE_ALLOW_UNSAFE_CODE);
+				}
+#endif
+
 #if SPINE_TK2D_DEFINE
 #if SPINE_TK2D_DEFINE
 				bool isTK2DDefineSet = true;
 				bool isTK2DDefineSet = true;
 #else
 #else

+ 2 - 1
spine-unity/Assets/Spine/Runtime/spine-unity.asmdef

@@ -1,4 +1,5 @@
 {
 {
 	"name": "spine-unity",
 	"name": "spine-unity",
-	"references": [ "spine-csharp" ]
+	"references": [ "spine-csharp" ],
+    "allowUnsafeCode": true
 }
 }

+ 37 - 3
spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/SkeletonDataAsset.cs

@@ -27,14 +27,37 @@
  * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *****************************************************************************/
  *****************************************************************************/
 
 
+//#define SPINE_ALLOW_UNSAFE // note: this define can be set via Edit - Preferences - Spine.
+
+#if UNITY_2021_2_OR_NEWER
+#define TEXT_ASSET_HAS_GET_DATA_BYTES
+#endif
+
+#if SPINE_ALLOW_UNSAFE && TEXT_ASSET_HAS_GET_DATA_BYTES
+#define UNSAFE_DIRECT_ACCESS_TEXT_ASSET_DATA
+#endif
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
+using Unity.Collections;
 using UnityEngine;
 using UnityEngine;
-
 using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
 using CompatibilityProblemInfo = Spine.Unity.SkeletonDataCompatibility.CompatibilityProblemInfo;
 
 
 namespace Spine.Unity {
 namespace Spine.Unity {
+#if UNSAFE_DIRECT_ACCESS_TEXT_ASSET_DATA
+	public static class TextAssetExtensions {
+		public static Stream GetStreamUnsafe (this TextAsset textAsset) {
+			NativeArray<byte> dataNativeArray = textAsset.GetData<byte>();
+			return dataNativeArray.GetUnmanagedMemoryStream();
+		}
+
+		public static unsafe UnmanagedMemoryStream GetUnmanagedMemoryStream<T> (this NativeArray<T> nativeArray) where T : struct {
+			return new UnmanagedMemoryStream((byte*)global::Unity.Collections.LowLevel.Unsafe.
+				NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr(nativeArray), nativeArray.Length);
+		}
+	}
+#endif
 
 
 	[CreateAssetMenu(fileName = "New SkeletonDataAsset", menuName = "Spine/SkeletonData Asset")]
 	[CreateAssetMenu(fileName = "New SkeletonDataAsset", menuName = "Spine/SkeletonData Asset")]
 	public class SkeletonDataAsset : ScriptableObject {
 	public class SkeletonDataAsset : ScriptableObject {
@@ -188,9 +211,13 @@ namespace Spine.Unity {
 			SkeletonData loadedSkeletonData = null;
 			SkeletonData loadedSkeletonData = null;
 
 
 			try {
 			try {
-				if (hasBinaryExtension)
+				if (hasBinaryExtension) {
+#if UNSAFE_DIRECT_ACCESS_TEXT_ASSET_DATA
+					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.GetStreamUnsafe(), attachmentLoader, skeletonDataScale);
+#else
 					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.bytes, attachmentLoader, skeletonDataScale);
 					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.bytes, attachmentLoader, skeletonDataScale);
-				else
+#endif
+				} else
 					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.text, attachmentLoader, skeletonDataScale);
 					loadedSkeletonData = SkeletonDataAsset.ReadSkeletonData(skeletonJSON.text, attachmentLoader, skeletonDataScale);
 			} catch (Exception ex) {
 			} catch (Exception ex) {
 				if (!quiet)
 				if (!quiet)
@@ -287,6 +314,13 @@ namespace Spine.Unity {
 			}
 			}
 		}
 		}
 
 
+		internal static SkeletonData ReadSkeletonData (Stream assetStream, AttachmentLoader attachmentLoader, float scale) {
+			SkeletonBinary binary = new SkeletonBinary(attachmentLoader) {
+				Scale = scale
+			};
+			return binary.ReadSkeletonData(assetStream);
+		}
+
 		internal static SkeletonData ReadSkeletonData (string text, AttachmentLoader attachmentLoader, float scale) {
 		internal static SkeletonData ReadSkeletonData (string text, AttachmentLoader attachmentLoader, float scale) {
 			StringReader input = new StringReader(text);
 			StringReader input = new StringReader(text);
 			SkeletonJson json = new SkeletonJson(attachmentLoader) {
 			SkeletonJson json = new SkeletonJson(attachmentLoader) {

+ 1 - 1
spine-unity/Assets/Spine/package.json

@@ -2,7 +2,7 @@
 	"name": "com.esotericsoftware.spine.spine-unity",
 	"name": "com.esotericsoftware.spine.spine-unity",
 	"displayName": "spine-unity Runtime",
 	"displayName": "spine-unity Runtime",
 	"description": "This plugin provides the spine-unity runtime core.",
 	"description": "This plugin provides the spine-unity runtime core.",
-	"version": "4.2.104",
+	"version": "4.2.105",
 	"unity": "2018.3",
 	"unity": "2018.3",
 	"author": {
 	"author": {
 		"name": "Esoteric Software",
 		"name": "Esoteric Software",