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);
        }
        public override void OnInspectorGUI()
        {
            ARAugmentedImageDatabase database = target as ARAugmentedImageDatabase;

            if (database == null)
            {
                return;
            }

            _RunDirtyQualityJobs(database);

            m_PageIndex = Mathf.Min(m_PageIndex, database.Count / k_PageSize);

            _DrawTitle();
            _DrawContainer();
            _DrawColumnNames();

            int displayedImageCount = 0;
            int removeAt            = -1;
            int pageStartIndex      = m_PageIndex * k_PageSize;
            int pageEndIndex        = Mathf.Min(database.Count, pageStartIndex + k_PageSize);

            for (int i = pageStartIndex; i < pageEndIndex; i++, displayedImageCount++)
            {
                ARAugmentedImageDatabaseEntry updatedImage;
                bool wasRemoved;

                _DrawImageField(database[i], out updatedImage, out wasRemoved);

                if (wasRemoved)
                {
                    removeAt = i;
                }
                else if (!database[i].Equals(updatedImage))
                {
                    database[i] = updatedImage;
                }
            }

            if (removeAt > -1)
            {
                database.RemoveAt(removeAt);
            }

            _DrawImageSpacers(displayedImageCount);
            _DrawPageField(database.Count);
        }
        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);
        }