From 40d1ffdf2a61ca5947bc38979e3410a6ac9108ea Mon Sep 17 00:00:00 2001 From: Junrou Nishida Date: Mon, 12 Aug 2024 17:38:21 +0900 Subject: [PATCH] refactor: use AsyncGlContext.Request to get GlContext --- .../Runtime/Scripts/Unity/AsyncGlContext.cs | 74 ++++++++++++++++ .../Scripts/Unity/AsyncGlContext.cs.meta | 11 +++ .../Runtime/Scripts/Unity/GpuManager.cs | 87 ++++++++----------- 3 files changed, 120 insertions(+), 52 deletions(-) create mode 100644 Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs create mode 100644 Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs.meta diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs new file mode 100644 index 000000000..711b8c1b0 --- /dev/null +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2021 homuler +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +using System; +using System.Runtime.InteropServices; +using System.Threading; +using UnityEngine; + +namespace Mediapipe.Unity +{ + public static class AsyncGlContext + { + public static AsyncGlContextRequest Request(Action callback) => new AsyncGlContextRequest(callback); + } + + public class AsyncGlContextRequest + { + private static int _Counter = 0; + private static readonly GlobalInstanceTable _InstanceTable = new GlobalInstanceTable(5); + + private delegate void GLEventCallback(int eventId); + + private readonly int _id; + private readonly Action _callback; + + public IntPtr platformGlContext { get; private set; } + public bool done { get; private set; } + public Exception error { get; private set; } + + internal AsyncGlContextRequest(Action callback) + { + _id = Interlocked.Increment(ref _Counter); + _callback = callback; + _InstanceTable.Add(_id, this); + + GLEventCallback gLEventCallback = PluginCallback; + var fp = Marshal.GetFunctionPointerForDelegate(gLEventCallback); + + GL.IssuePluginEvent(fp, _id); + } + + [AOT.MonoPInvokeCallback(typeof(GLEventCallback))] + private static void PluginCallback(int eventId) + { + if (!_InstanceTable.TryGetValue(eventId, out var request)) + { + Logger.LogWarning($"AsyncGlContextRequest with id {eventId} is not found, maybe already GCed"); + return; + } + + try + { +#if UNITY_ANDROID + // Currently, it works only on Android + request.platformGlContext = Egl.GetCurrentContext(); +#endif + + request._callback?.Invoke(request); + } + catch (Exception e) + { + request.error = e; + } + finally + { + request.done = true; + _InstanceTable.Remove(eventId); + } + } + } +} diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs.meta b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs.meta new file mode 100644 index 000000000..00c124179 --- /dev/null +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/AsyncGlContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b00da44238db55fdc90b51fd7edd8419 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/GpuManager.cs b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/GpuManager.cs index dd20243c7..1fc8e3674 100644 --- a/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/GpuManager.cs +++ b/Packages/com.github.homuler.mediapipe/Runtime/Scripts/Unity/GpuManager.cs @@ -9,10 +9,6 @@ using UnityEngine; using UnityEngine.Rendering; -#if UNITY_ANDROID -using System.Runtime.InteropServices; -#endif - namespace Mediapipe.Unity { public static class GpuManager @@ -22,10 +18,7 @@ public static class GpuManager private delegate void PluginCallback(int eventId); private static readonly object _SetupLock = new object(); -#pragma warning disable IDE0044 - private static IntPtr _CurrentContext = IntPtr.Zero; -#pragma warning restore IDE0044 - private static bool _IsContextInitialized = false; + private static IntPtr _PlatformGlContext = IntPtr.Zero; public static GpuResources GpuResources { get; private set; } public static GlCalculatorHelper GlCalculatorHelper { get; private set; } @@ -50,48 +43,21 @@ public static IEnumerator Initialize() yield break; } -#if UNITY_ANDROID - _IsContextInitialized = SystemInfo.graphicsDeviceType != GraphicsDeviceType.OpenGLES3; - if (!_IsContextInitialized) - { - PluginCallback callback = GetCurrentContext; - - var fp = Marshal.GetFunctionPointerForDelegate(callback); - GL.IssuePluginEvent(fp, 1); - } -#else - _IsContextInitialized = true; -#endif - - var count = 100; - yield return new WaitUntil(() => - { - return --count < 0 || _IsContextInitialized; - }); - - if (!_IsContextInitialized) - { - Logger.LogError(_TAG, "Failed to get GlContext"); - yield break; - } - -#if UNITY_ANDROID - if (_CurrentContext == IntPtr.Zero) - { - Logger.LogWarning(_TAG, "EGL context is not found, so MediaPipe won't share their EGL contexts with Unity"); - } - else + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.OpenGLES3) { - Logger.LogVerbose(_TAG, $"EGL context is found: {_CurrentContext}"); + var req = AsyncGlContext.Request(OnGetEglContext); + yield return new WaitUntil(() => req.done); + + if (req.error != null) + { + Logger.LogException(req.error); + yield break; + } } -#endif try { - Logger.LogInfo(_TAG, "Initializing GpuResources..."); - GpuResources = GpuResources.Create(_CurrentContext); - - Logger.LogInfo(_TAG, "Initializing GlCalculatorHelper..."); + GpuResources = GpuResources.Create(_PlatformGlContext); GlCalculatorHelper = new GlCalculatorHelper(); GlCalculatorHelper.InitializeForTest(GpuResources); @@ -133,13 +99,30 @@ public static void Shutdown() IsInitialized = false; } - // Currently, it works only on Android -#if UNITY_ANDROID - [AOT.MonoPInvokeCallback(typeof(PluginCallback))] - private static void GetCurrentContext(int eventId) { - _CurrentContext = Egl.GetCurrentContext(); - _IsContextInitialized = true; + public static void ResetGpuResources(IntPtr platformGlContext) + { + if (!IsInitialized) + { + throw new InvalidOperationException("GpuManager is not initialized"); + } + GpuResources?.Dispose(); + + GpuResources = new GpuResources(platformGlContext); + GlCalculatorHelper.InitializeForTest(GpuResources); + } + + public static GlContext GetGlContext() => GlCalculatorHelper?.GetGlContext(); + + private static void OnGetEglContext(AsyncGlContextRequest request) + { + if (request.platformGlContext == IntPtr.Zero) + { + Logger.LogWarning(_TAG, "EGL context is not found, so MediaPipe won't share their EGL contexts with Unity"); + return; + } + Logger.LogVerbose(_TAG, $"EGL context is found: {request.platformGlContext}"); + + _PlatformGlContext = request.platformGlContext; } -#endif } }