private static IEnumerator UpdateLoop()
        {
            var renderEventFunc          = NativeApi.GetRenderEventFunc();
            var shouldConvertToBgra      = SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11;
            var loggedAspectRatioWarning = false;

            // Waits until the end of the first frame until capturing the screen size,
            // because it might be incorrect when first querying it.
            yield return(k_WaitForEndOfFrame);

            // Creates a target texture to capture the preview window onto.
            // Some video encoders prefer the dimensions to be a multiple of 16.
            var           targetWidth   = RoundUpToNearestMultipleOf16(Screen.width);
            var           targetHeight  = RoundUpToNearestMultipleOf16(Screen.height);
            var           screenTexture = new RenderTexture(targetWidth, targetHeight, 0);
            var           targetTexture = screenTexture;
            RenderTexture bgrTexture    = null;

            if (shouldConvertToBgra)
            {
                bgrTexture    = new RenderTexture(screenTexture.width, screenTexture.height, 0, RenderTextureFormat.BGRA32);
                targetTexture = bgrTexture;
            }

            // Begins update loop. The coroutine will cease when the
            // ARCoreSession component it's called from is destroyed.
            for (;;)
            {
                yield return(k_WaitForEndOfFrame);

                NativeApi.Update();
                InstantPreviewInput.Update();
                AddInstantPreviewTrackedPoseDriverWhenNeeded();

                Graphics.Blit(null, screenTexture);

                if (shouldConvertToBgra)
                {
                    Graphics.Blit(screenTexture, bgrTexture);
                }

                var cameraTexture = Frame.CameraImage.Texture;
                if (!loggedAspectRatioWarning && cameraTexture != null)
                {
                    var sourceWidth            = cameraTexture.width;
                    var sourceHeight           = cameraTexture.height;
                    var sourceAspectRatio      = (float)sourceWidth / sourceHeight;
                    var destinationWidth       = Screen.width;
                    var destinationHeight      = Screen.height;
                    var destinationAspectRatio = (float)destinationWidth / destinationHeight;

                    if (Mathf.Abs(sourceAspectRatio - destinationAspectRatio) >
                        k_MaxTolerableAspectRatioDifference)
                    {
                        Debug.LogWarning(string.Format(k_MismatchedAspectRatioWarningFormatString, sourceWidth,
                                                       sourceHeight));
                        loggedAspectRatioWarning = true;
                    }
                }

                NativeApi.SendFrame(targetTexture.GetNativeTexturePtr());
                GL.IssuePluginEvent(renderEventFunc, 1);
            }
        }
        private static IEnumerator UpdateLoop(string adbPath)
        {
            var renderEventFunc     = NativeApi.GetRenderEventFunc();
            var shouldConvertToBgra =
                SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11;
            var loggedAspectRatioWarning = false;

            // Waits until the end of the first frame until capturing the screen size,
            // because it might be incorrect when first querying it.
            yield return(k_WaitForEndOfFrame);

            var currentWidth        = 0;
            var currentHeight       = 0;
            var needToStartActivity = true;
            var prevFrameLandscape  = false;

            RenderTexture screenTexture = null;
            RenderTexture targetTexture = null;
            RenderTexture bgrTexture    = null;

            // Begins update loop. The coroutine will cease when the
            // ARCoreSession component it's called from is destroyed.
            for (;;)
            {
                yield return(k_WaitForEndOfFrame);

                var curFrameLandscape = Screen.width > Screen.height;
                if (prevFrameLandscape != curFrameLandscape)
                {
                    needToStartActivity = true;
                }

                prevFrameLandscape = curFrameLandscape;
                if (needToStartActivity)
                {
                    string activityName = curFrameLandscape ? "InstantPreviewLandscapeActivity" :
                                          "InstantPreviewActivity";
                    string output;
                    string errors;
                    ShellHelper.RunCommand(adbPath,
                                           "shell am start -S -n com.google.ar.core.instantpreview/." + activityName,
                                           out output, out errors);
                    needToStartActivity = false;
                }

                // Creates a target texture to capture the preview window onto.
                // Some video encoders prefer the dimensions to be a multiple of 16.
                var targetWidth  = RoundUpToNearestMultipleOf16(Screen.width);
                var targetHeight = RoundUpToNearestMultipleOf16(Screen.height);

                if (targetWidth != currentWidth || targetHeight != currentHeight)
                {
                    screenTexture = new RenderTexture(targetWidth, targetHeight, 0);
                    targetTexture = screenTexture;

                    if (shouldConvertToBgra)
                    {
                        bgrTexture = new RenderTexture(
                            screenTexture.width, screenTexture.height, 0,
                            RenderTextureFormat.BGRA32);
                        targetTexture = bgrTexture;
                    }

                    currentWidth  = targetWidth;
                    currentHeight = targetHeight;
                }

                NativeApi.Update();
                InstantPreviewInput.Update();

                if (NativeApi.AppShowedTouchWarning())
                {
                    Debug.LogWarning(k_InstantPreviewInputWarning);
                    NativeApi.UnityLoggedTouchWarning();
                }

                AddInstantPreviewTrackedPoseDriverWhenNeeded();

                Graphics.Blit(null, screenTexture);

                if (shouldConvertToBgra)
                {
                    Graphics.Blit(screenTexture, bgrTexture);
                }

                var cameraTexture = Frame.CameraImage.Texture;
                if (!loggedAspectRatioWarning && cameraTexture != null)
                {
                    var sourceWidth            = cameraTexture.width;
                    var sourceHeight           = cameraTexture.height;
                    var sourceAspectRatio      = (float)sourceWidth / sourceHeight;
                    var destinationWidth       = Screen.width;
                    var destinationHeight      = Screen.height;
                    var destinationAspectRatio = (float)destinationWidth / destinationHeight;

                    if (Mathf.Abs(sourceAspectRatio - destinationAspectRatio) >
                        k_MaxTolerableAspectRatioDifference)
                    {
                        Debug.LogWarningFormat(
                            k_MismatchedAspectRatioWarningFormatString, sourceAspectRatio,
                            destinationAspectRatio, sourceWidth, sourceHeight);
                        loggedAspectRatioWarning = true;
                    }
                }

                NativeApi.SendFrame(targetTexture.GetNativeTexturePtr());
                GL.IssuePluginEvent(renderEventFunc, (int)ApiRenderEvent.UpdateCubemapTexture);
            }
        }