private void GuardedRun()

in source/SkiaSharp.Views/SkiaSharp.Views/Platform/Android/GLTextureView.cs [770:1074]


			private void GuardedRun()
			{
				eglHelper = new EglHelper(textureViewWeakRef);
				haveEglContext = false;
				haveEglSurface = false;
				try
				{
					IGL10 gl = null;
					var createEglContext = false;
					var createEglSurface = false;
					var createGlInterface = false;
					var lostEglContext = false;
					var sizeChanged = false;
					var wantRenderNotification = false;
					var doRenderNotification = false;
					var askedToReleaseEglContext = false;
					var w = 0;
					var h = 0;
					Java.Lang.IRunnable ev = null;

					while (true)
					{
						lock (threadManager)
						{
							while (true)
							{
								if (shouldExit)
								{
									return;
								}

								if (eventQueue.Count > 0)
								{
									ev = eventQueue.Dequeue();
									break;
								}

								// Update the pause state.
								var pausing = false;
								if (paused != requestPaused)
								{
									pausing = requestPaused;
									paused = requestPaused;
									Monitor.PulseAll(threadManager);

									LogDebug($"[GLThread {Id}] paused is now {paused}");
								}

								// Do we need to give up the EGL context?
								if (shouldReleaseEglContext)
								{
									LogDebug($"[GLThread {Id}] Releasing EGL context because asked to");

									StopEglSurfaceLocked();
									StopEglContextLocked();
									shouldReleaseEglContext = false;
									askedToReleaseEglContext = true;
								}

								// Have we lost the EGL context?
								if (lostEglContext)
								{
									StopEglSurfaceLocked();
									StopEglContextLocked();
									lostEglContext = false;
								}

								// When pausing, release the EGL surface:
								if (pausing && haveEglSurface)
								{
									LogDebug($"[GLThread {Id}] Releasing EGL surface because paused");

									StopEglSurfaceLocked();
								}

								// When pausing, optionally release the EGL Context:
								if (pausing && haveEglContext)
								{
									textureViewWeakRef.TryGetTarget(out GLTextureView view);
									var preserveEglContextOnPause = view == null ? false : view.PreserveEGLContextOnPause;
									if (!preserveEglContextOnPause || threadManager.ShouldReleaseEGLContextWhenPausing())
									{
										StopEglContextLocked();

										LogDebug($"[GLThread {Id}] Releasing EGL context because paused");
									}
								}

								// When pausing, optionally terminate EGL:
								if (pausing)
								{
									if (threadManager.ShouldTerminateEGLWhenPausing())
									{
										eglHelper.Finish();

										LogDebug($"[GLThread {Id}] Terminating EGL because paused");
									}
								}

								// Have we lost the TextureView surface?
								if ((!hasSurface) && (!waitingForSurface))
								{
									LogDebug($"[GLThread {Id}] Noticed TextureView surface lost");

									if (haveEglSurface)
									{
										StopEglSurfaceLocked();
									}
									waitingForSurface = true;
									surfaceIsBad = false;
									Monitor.PulseAll(threadManager);
								}

								// Have we acquired the surface view surface?
								if (hasSurface && waitingForSurface)
								{
									LogDebug($"[GLThread {Id}] Noticed TextureView surface acquired");

									waitingForSurface = false;
									Monitor.PulseAll(threadManager);
								}

								if (doRenderNotification)
								{
									LogDebug($"[GLThread {Id}] Sending render notification");

									wantRenderNotification = false;
									doRenderNotification = false;
									renderComplete = true;
									Monitor.PulseAll(threadManager);
								}

								// Ready to draw?
								if (IsReadyToDraw())
								{
									// If we don't have an EGL context, try to acquire one.
									if (!haveEglContext)
									{
										if (askedToReleaseEglContext)
										{
											askedToReleaseEglContext = false;
										}
										else if (threadManager.TryAcquireEglContextLocked(this))
										{
											try
											{
												eglHelper.Start();
											}
											catch (Exception)
											{
												threadManager.ReleaseEglContextLocked(this);
												throw;
											}
											haveEglContext = true;
											createEglContext = true;

											Monitor.PulseAll(threadManager);
										}
									}

									if (haveEglContext && !haveEglSurface)
									{
										haveEglSurface = true;
										createEglSurface = true;
										createGlInterface = true;
										sizeChanged = true;
									}

									if (haveEglSurface)
									{
										if (surfaceSizeChanged)
										{
											sizeChanged = true;
											w = width;
											h = height;
											wantRenderNotification = true;

											LogDebug($"[GLThread {Id}] Noticing that we want render notification");

											// Destroy and recreate the EGL surface.
											createEglSurface = true;
											surfaceSizeChanged = false;
										}
										requestRender = false;
										Monitor.PulseAll(threadManager);
										break;
									}
								}

								LogDebug($"[GLThread {Id}] Waiting mHaveEglContext={haveEglContext} mHaveEglSurface={haveEglSurface} mFinishedCreatingEglSurface={finishedCreatingEglSurface} paused={paused} hasSurface={hasSurface} surfaceIsBad={surfaceIsBad} mWaitingForSurface={waitingForSurface} mWidth={width} mHeight={height} mRequestRender={requestRender} mRenderMode={renderMode}");

								// By design, this is the only place in a GLThread thread where we Wait().
								Monitor.Wait(threadManager);
							}
						} // end of lock(sGLThreadManager)

						if (ev != null)
						{
							ev.Run();
							ev = null;
							continue;
						}

						if (createEglSurface)
						{
							LogDebug($"[GLThread {Id}] EGL create surface");

							if (eglHelper.CreateSurface())
							{
								lock (threadManager)
								{
									finishedCreatingEglSurface = true;
									Monitor.PulseAll(threadManager);
								}
							}
							else
							{
								lock (threadManager)
								{
									finishedCreatingEglSurface = true;
									surfaceIsBad = true;
									Monitor.PulseAll(threadManager);
								}
								continue;
							}
							createEglSurface = false;
						}

						if (createGlInterface)
						{
							gl = eglHelper.CreateGL().JavaCast<IGL10>();

							threadManager.CheckGLDriver(gl);
							createGlInterface = false;
						}

						if (createEglContext)
						{
							LogDebug($"[GLThread {Id}] OnSurfaceCreated");

							if (textureViewWeakRef.TryGetTarget(out GLTextureView view))
							{
								view.renderer.OnSurfaceCreated(gl, eglHelper.EglConfig);
							}
							createEglContext = false;
						}

						if (sizeChanged)
						{
							LogDebug($"[GLThread {Id}] OnSurfaceChanged({w}, {h})");

							if (textureViewWeakRef.TryGetTarget(out GLTextureView view))
							{
								view.renderer.OnSurfaceChanged(gl, w, h);
							}
							sizeChanged = false;
						}

						{
							LogDebug($"[GLThread {Id}] OnDrawFrame");

							if (textureViewWeakRef.TryGetTarget(out GLTextureView view))
							{
								view.renderer.OnDrawFrame(gl);
							}
						}

						var swapError = eglHelper.Swap();
						switch (swapError)
						{
							case EGL10.EglSuccess:
								break;
							case EGL11.EglContextLost:
								LogDebug($"[GLThread {Id}] EGL context lost");
								lostEglContext = true;
								break;
							default:
								// Other errors typically mean that the current surface is bad,
								// probably because the TextureView surface has been destroyed,
								// but we haven't been notified yet.
								LogError($"[GLThread {Id}] eglSwapBuffers failed: {swapError}");

								lock (threadManager)
								{
									surfaceIsBad = true;
									Monitor.PulseAll(threadManager);
								}
								break;
						}

						if (wantRenderNotification)
						{
							doRenderNotification = true;
						}
					}
				}
				finally
				{
					lock (threadManager)
					{
						StopEglSurfaceLocked();
						StopEglContextLocked();
					}
				}
			}