/// <summary>
        /// Display all screen info objects like fps, frame counter, lag counter, and input display
        /// </summary>
        public void DrawScreenInfo(IBlitter g)
        {
            if (_config.DisplayFrameCounter && !_emulator.IsNull())
            {
                string message = MakeFrameCounter();
                var    point   = GetCoordinates(g, _config.FrameCounter, message);
                DrawOsdMessage(g, message, Color.FromArgb(_config.MessagesColor), point.X, point.Y);

                if (_emulator.CanPollInput() && _emulator.AsInputPollable().IsLagFrame)
                {
                    DrawOsdMessage(g, _emulator.Frame.ToString(), FixedAlertMessageColor, point.X, point.Y);
                }
            }

            if (_config.DisplayInput)
            {
                var moviePlaying = _movieSession.Movie.IsPlaying();
                // After the last frame of the movie, we want both the last movie input and the current inputs.
                var atMovieEnd = _movieSession.Movie.IsFinished() && _movieSession.Movie.IsAtEnd();
                if (moviePlaying || atMovieEnd)
                {
                    var   input = InputStrMovie();
                    var   point = GetCoordinates(g, _config.InputDisplay, input);
                    Color c     = Color.FromArgb(_config.MovieInput);
                    g.DrawString(input, MessageFont, c, point.X, point.Y);
                }

                if (!moviePlaying)                 // TODO: message config -- allow setting of "mixed", and "auto"
                {
                    var   previousColor  = Color.FromArgb(_config.LastInputColor);
                    Color immediateColor = Color.FromArgb(_config.MessagesColor);
                    var   autoColor      = Color.Pink;
                    var   changedColor   = Color.PeachPuff;

                    //we need some kind of string for calculating position when right-anchoring, of something like that
                    var bgStr = InputStrOrAll();
                    var point = GetCoordinates(g, _config.InputDisplay, bgStr);

                    // now, we're going to render these repeatedly, with higher-priority things overriding

                    // first display previous frame's input.
                    // note: that's only available in case we're working on a movie
                    var previousStr = InputPrevious();
                    g.DrawString(previousStr, MessageFont, previousColor, point.X, point.Y);

                    // next, draw the immediate input.
                    // that is, whatever is being held down interactively right this moment even if the game is paused
                    // this includes things held down due to autohold or autofire
                    // I know, this is all really confusing
                    var immediate = InputStrImmediate();
                    g.DrawString(immediate, MessageFont, immediateColor, point.X, point.Y);

                    // next draw anything that's pressed because it's sticky.
                    // this applies to autofire and autohold both. somehow. I don't understand it.
                    // basically we're tinting whatever is pressed because it's sticky specially
                    // in order to achieve this we want to avoid drawing anything pink that isn't actually held down right now
                    // so we make an AND adapter and combine it using immediate & sticky
                    var autoString = MakeStringFor(_inputManager.StickyXorAdapter.Source.Xor(_inputManager.AutofireStickyXorAdapter).And(_inputManager.AutofireStickyXorAdapter));
                    g.DrawString(autoString, MessageFont, autoColor, point.X, point.Y);

                    //recolor everything that's changed from the previous input
                    var immediateOverlay = MakeIntersectImmediatePrevious();
                    g.DrawString(immediateOverlay, MessageFont, changedColor, point.X, point.Y);
                }
            }

            if (_config.DisplayFps && Fps != null)
            {
                var point = GetCoordinates(g, _config.Fps, Fps);
                DrawOsdMessage(g, Fps, FixedMessagesColor, point.X, point.Y);
            }

            if (_config.DisplayLagCounter && _emulator.CanPollInput())
            {
                var counter = _emulator.AsInputPollable().LagCount.ToString();
                var point   = GetCoordinates(g, _config.LagCounter, counter);
                DrawOsdMessage(g, counter, FixedAlertMessageColor, point.X, point.Y);
            }

            if (_config.DisplayRerecordCount)
            {
                string rerecordCount = MakeRerecordCount();
                var    point         = GetCoordinates(g, _config.ReRecordCounter, rerecordCount);
                DrawOsdMessage(g, rerecordCount, FixedMessagesColor, point.X, point.Y);
            }

            if (_inputManager.ClientControls["Autohold"] || _inputManager.ClientControls["Autofire"])
            {
                var sb = new StringBuilder("Held: ");

                foreach (string sticky in _inputManager.StickyXorAdapter.CurrentStickies)
                {
                    sb.Append(sticky).Append(' ');
                }

                foreach (string autoSticky in _inputManager.AutofireStickyXorAdapter.CurrentStickies)
                {
                    sb
                    .Append("Auto-")
                    .Append(autoSticky)
                    .Append(' ');
                }

                var message = sb.ToString();
                var point   = GetCoordinates(g, _config.Autohold, message);
                g.DrawString(message, MessageFont, Color.White, point.X, point.Y);
            }

            if (_movieSession.Movie.IsActive() && _config.DisplaySubtitles)
            {
                var subList = _movieSession.Movie.Subtitles.GetSubtitles(_emulator.Frame);

                foreach (var sub in subList)
                {
                    DrawOsdMessage(g, sub.Message, Color.FromArgb((int)sub.Color), sub.X, sub.Y);
                }
            }
        }