forked from MonoGame/MonoGame
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Threading.cs
137 lines (125 loc) · 4.09 KB
/
Threading.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// MonoGame - Copyright (C) The MonoGame Team
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.Xna.Framework.Graphics;
#if IOS
using Foundation;
using OpenGLES;
#endif
#if DESKTOPGL || ANGLE || GLES
using MonoGame.OpenGL;
#endif
namespace Microsoft.Xna.Framework
{
internal class Threading
{
public const int kMaxWaitForUIThread = 750; // In milliseconds
static int mainThreadId;
#if ANDROID || WINDOWS || DESKTOPGL || ANGLE
static List<Action> actions = new List<Action>();
//static Mutex actionsMutex = new Mutex();
#elif IOS
public static EAGLContext BackgroundContext;
#endif
static Threading()
{
mainThreadId = Thread.CurrentThread.ManagedThreadId;
}
#if ANDROID
internal static void ResetThread (int id)
{
mainThreadId = id;
}
#endif
/// <summary>
/// Checks if the code is currently running on the UI thread.
/// </summary>
/// <returns>true if the code is currently running on the UI thread.</returns>
public static bool IsOnUIThread()
{
return mainThreadId == Thread.CurrentThread.ManagedThreadId;
}
/// <summary>
/// Throws an exception if the code is not currently running on the UI thread.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if the code is not currently running on the UI thread.</exception>
public static void EnsureUIThread()
{
if (!IsOnUIThread())
throw new InvalidOperationException("Operation not called on UI thread.");
}
/// <summary>
/// Runs the given action on the UI thread and blocks the current thread while the action is running.
/// If the current thread is the UI thread, the action will run immediately.
/// </summary>
/// <param name="action">The action to be run on the UI thread</param>
internal static void BlockOnUIThread(Action action)
{
if (action == null)
throw new ArgumentNullException("action");
#if DIRECTX || PSM
action();
#else
// If we are already on the UI thread, just call the action and be done with it
if (IsOnUIThread())
{
action();
return;
}
#if IOS
lock (BackgroundContext)
{
// Make the context current on this thread if it is not already
if (!Object.ReferenceEquals(EAGLContext.CurrentContext, BackgroundContext))
EAGLContext.SetCurrentContext(BackgroundContext);
// Execute the action
action();
// Must flush the GL calls so the GPU asset is ready for the main context to use it
GL.Flush();
GraphicsExtensions.CheckGLError();
}
#else
ManualResetEventSlim resetEvent = new ManualResetEventSlim(false);
Add(() =>
{
#if ANDROID
//if (!Game.Instance.Window.GraphicsContext.IsCurrent)
((AndroidGameWindow)Game.Instance.Window).GameView.MakeCurrent();
#endif
action();
resetEvent.Set();
});
resetEvent.Wait();
#endif
#endif
}
#if ANDROID || WINDOWS || DESKTOPGL || ANGLE
static void Add(Action action)
{
lock (actions)
{
actions.Add(action);
}
}
/// <summary>
/// Runs all pending actions. Must be called from the UI thread.
/// </summary>
internal static void Run()
{
EnsureUIThread();
lock (actions)
{
foreach (Action action in actions)
{
action();
}
actions.Clear();
}
}
#endif
}
}