private static void _UpdateDatabaseQuality(ARAugmentedImageDatabase database)
        {
            lock (s_UpdatedQualityScores)
            {
                if (s_UpdatedQualityScores.Count == 0)
                {
                    return;
                }

                for (int i = 0; i < database.Count; ++i)
                {
                    if (s_UpdatedQualityScores.ContainsKey(database[i].TextureGUID))
                    {
                        ARAugmentedImageDatabaseEntry updatedImage = database[i];
                        updatedImage.Quality = s_UpdatedQualityScores[updatedImage.TextureGUID];
                        database[i]          = updatedImage;
                    }
                }

                s_UpdatedQualityScores.Clear();
            }

            // For refreshing inspector UI for updated quality scores.
            EditorUtility.SetDirty(database);
        }
        private void _DrawImageField(ARAugmentedImageDatabaseEntry image, out ARAugmentedImageDatabaseEntry updatedImage, out bool wasRemoved)
        {
            updatedImage = new ARAugmentedImageDatabaseEntry();

            EditorGUILayout.BeginVertical();
            GUILayout.Space(5);
            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(15);

            var buttonStyle = new GUIStyle(GUI.skin.button);

            buttonStyle.margin = new RectOffset(10, 10, 13, 0);

            wasRemoved = GUILayout.Button("X", buttonStyle);

            var textFieldStyle = new GUIStyle(GUI.skin.textField);

            textFieldStyle.margin = new RectOffset(5, 5, 15, 0);
            updatedImage.Name     = EditorGUILayout.TextField(image.Name, textFieldStyle, GUILayout.MaxWidth(80f));

            GUILayout.Space(5);
            updatedImage.Width = EditorGUILayout.FloatField(image.Width, textFieldStyle, GUILayout.MaxWidth(80f));

            var labelStyle = new GUIStyle(GUI.skin.label);

            labelStyle.alignment = TextAnchor.MiddleLeft;
            GUILayout.Space(5);
            EditorGUILayout.LabelField(_QualityForDisplay(image.Quality), labelStyle,
                                       GUILayout.Height(42), GUILayout.MaxWidth(80f));

            GUILayout.FlexibleSpace();

            updatedImage.Texture = EditorGUILayout.ObjectField(image.Texture, typeof(Texture2D), false,
                                                               GUILayout.Height(45), GUILayout.Width(45)) as Texture2D;
            if (updatedImage.TextureGUID == image.TextureGUID)
            {
                updatedImage.Quality = image.Quality;
            }

            GUILayout.Space(15);
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(5);
            EditorGUILayout.EndVertical();
        }
        private static void _RunDirtyQualityJobs(ARAugmentedImageDatabase database)
        {
            if (database == null)
            {
                return;
            }

            if (s_DatabaseForQualityJobs != database)
            {
                // If another database is already running quality evaluation,
                // stop all pending jobs to prioritise the current database.
                if (s_DatabaseForQualityJobs != null)
                {
                    s_QualityBackgroundExecutor.RemoveAllPendingJobs();
                }

                s_DatabaseForQualityJobs = database;
            }

            _UpdateDatabaseQuality(database);

            // Set database dirty to refresh inspector UI for each frame that there are still pending jobs.
            // Otherwise if there exists one frame with no newly finished jobs, the UI will never get refreshed.
            // EditorUtility.SetDirty can only be called from main thread.
            if (s_QualityBackgroundExecutor.PendingJobsCount > 0)
            {
                EditorUtility.SetDirty(database);
                return;
            }

            List <ARAugmentedImageDatabaseEntry> dirtyEntries = database.GetDirtyQualityEntries();

            if (dirtyEntries.Count == 0)
            {
                return;
            }

            string cliBinaryPath;

            if (!ARAugmentedImageDatabase.FindCliBinaryPath(out cliBinaryPath))
            {
                return;
            }

            for (int i = 0; i < dirtyEntries.Count; ++i)
            {
                ARAugmentedImageDatabaseEntry image = dirtyEntries[i];
                var imagePath   = AssetDatabase.GetAssetPath(image.Texture);
                var textureGUID = image.TextureGUID;
                s_QualityBackgroundExecutor.PushJob(() =>
                {
                    string quality;
                    string error;
                    ShellHelper.RunCommand(cliBinaryPath,
                                           string.Format("eval-img --input_image_path {0}", imagePath), out quality, out error);

                    lock (s_UpdatedQualityScores)
                    {
                        s_UpdatedQualityScores.Add(textureGUID, quality);
                    }
                });
            }

            // For refreshing inspector UI as new jobs have been enqueued.
            EditorUtility.SetDirty(database);
        }