using System; using System.Collections.Generic; #if ENABLE_SPRINGBONE_BURST using Unity.Burst; #endif using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine.Jobs; using UnityEngine.Profiling; using VRM.FastSpringBones.Blittables; using VRM.FastSpringBones.NativeWrappers; using VRM.FastSpringBones.Registries; namespace VRM.FastSpringBones.Schedulers { /// /// GameObjectの世界からBlittableな世界へTransformを複製する処理を行うクラス /// public sealed unsafe class PullTransformJobScheduler : IDisposable { private BlittableTransform** _transformPointers; private TransformAccessArray _transformAccessArray; private readonly CustomSampler _sampler = CustomSampler.Create("Schedule CopyFromTransformJob"); private readonly TransformRegistry _transformRegistry; private bool _dirty = true; private IReadOnlyList Targets => _transformRegistry.PullTargets; public PullTransformJobScheduler(TransformRegistry transformRegistry) { _transformRegistry = transformRegistry; _transformRegistry.SubscribeOnValueChanged(OnTransformChanged); } private void OnTransformChanged() { _dirty = true; } public JobHandle Schedule(JobHandle dependOn = default(JobHandle)) { if (Targets.Count == 0) { return dependOn; } _sampler.Begin(); // リストが変更されていたらバッファを再構築 if (_dirty) { ReconstructBuffers(); _dirty = false; } // ジョブを発火 var job = new Job { TransformPointers = _transformPointers }; var jobHandle = job.Schedule(_transformAccessArray, dependOn); _sampler.End(); return jobHandle; } private void ReconstructBuffers() { ReleaseBuffers(); var transforms = Targets; _transformPointers = (BlittableTransform**)UnsafeUtility.Malloc( sizeof(BlittableTransform*) * transforms.Count, 16, Allocator.Persistent ); _transformAccessArray = new TransformAccessArray(transforms.Count); for (var i = 0; i < transforms.Count; i++) { _transformPointers[i] = transforms[i].GetUnsafePtr(); _transformAccessArray.Add(transforms[i].Transform); } } public void Dispose() { ReleaseBuffers(); _transformRegistry.UnSubscribeOnValueChanged(OnTransformChanged); } private void ReleaseBuffers() { if (_transformAccessArray.isCreated) _transformAccessArray.Dispose(); if (_transformPointers != null) { UnsafeUtility.Free(_transformPointers, Allocator.Persistent); _transformPointers = null; } } #if ENABLE_SPRINGBONE_BURST [BurstCompile] #endif private struct Job : IJobParallelForTransform { [NativeDisableUnsafePtrRestriction] public BlittableTransform** TransformPointers; public void Execute(int index, TransformAccess transform) { TransformPointers[index]->PullFrom(transform); } } } }