Exemple #1
0
 public HistoryLock(MyProfiler profiler, FastResourceLock historyLock)
 {
     m_profiler = profiler;
     m_lock     = historyLock;
     m_lock.AcquireExclusive();
     m_profiler.OnHistorySafe();
 }
Exemple #2
0
 public HistoryLock(MyProfiler profiler, FastResourceLock historyLock)
 {
     m_profiler = profiler;
     m_lock = historyLock;
     m_lock.AcquireExclusive();
     m_profiler.OnHistorySafe();
 }
        internal void DestroyThread()
        {
            m_threadProfilers.Remove(m_threadProfiler);
            if (m_selectedProfiler == m_threadProfiler)
            {
                m_selectedProfiler = m_threadProfilers.Count > 0 ? m_threadProfilers[0] : null;
            }

            m_threadProfiler = null;
        }
 /// <summary>
 /// Creates new profiler which can be used to profile anything (e.g. network stats).
 /// </summary>
 public static MyProfiler CreateProfiler(string name, string axisName = null, bool memoryProfiling = false)
 {
     lock (m_threadProfilers)
     {
         var profiler = new MyProfiler(memoryProfiling, name, axisName ?? "[ms]");
         m_threadProfilers.Add(profiler);
         profiler.SetNewLevelLimit(m_profilerProcessingEnabled ? m_levelLimit : 0);
         if (m_selectedProfiler == null)
         {
             m_selectedProfiler = profiler;
         }
         return(profiler);
     }
 }
Exemple #5
0
 static NetProfiler()
 {
     m_profiler = MyRenderProfiler.CreateProfiler("Network", "B");
     m_profiler.AutoCommit = false;
 }
Exemple #6
0
 static NetProfiler()
 {
     m_profiler            = MyRenderProfiler.CreateProfiler("Network", "B");
     m_profiler.AutoCommit = false;
 }
 protected override void Draw(VRage.Profiler.MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw)
 {
 }
 protected abstract void Draw(MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw);
 /// <summary>
 /// Creates new profiler which can be used to profile anything (e.g. network stats).
 /// </summary>
 public static MyProfiler CreateProfiler(string name, string axisName = null, bool memoryProfiling = false)
 {
     lock (m_threadProfilers)
     {
         var profiler = new MyProfiler(memoryProfiling, name, axisName ?? "[ms]");
         m_threadProfilers.Add(profiler);
         profiler.SetNewLevelLimit(m_profilerProcessingEnabled ? m_levelLimit : 0);
         if (m_selectedProfiler == null)
             m_selectedProfiler = profiler;
         return profiler;
     }
 }
 static MyRenderProfiler()
 {
     m_levelLimit = VRage.MyCompilationSymbols.ProfileFromStart ? -1 : 0;
     // Create block, some unique id
     m_fpsBlock = MyProfiler.CreateExternalBlock("FPS", -2);
 }
        public void DrawEvent(float textPosY, MyProfiler.MyProfilerBlock profilerBlock, int blockIndex, int frameIndex, int lastValidFrame)
        {
            Color color = IndexToColor(blockIndex);
            float miliseconds = 0;
            float managedMemory = 0;
            float processMemory = 0;
            int numCalls = -1; // To show update window in profiler
            float customValue = 0;

            if (IsValidIndex(frameIndex, lastValidFrame))
            {
                miliseconds = profilerBlock.Miliseconds[frameIndex];
                managedMemory = profilerBlock.ManagedMemory[frameIndex];
                processMemory = profilerBlock.ProcessMemory[frameIndex];
                numCalls = profilerBlock.NumCallsArray[frameIndex];
                customValue = profilerBlock.CustomValues[frameIndex];
            }

            float Y_TEXT_POSITION = MyRender.GraphicsDevice.Viewport.Height / 2;

            float textScale = 0.7f;

            m_text.Clear().Append(blockIndex + 1).Append(" ").Append(profilerBlock.Name);
            MyRender.DrawTextShadow(new Vector2(20, textPosY), m_text, color, textScale);

            float length = 500;

            m_text.Clear();
            m_text.Append("(").Append(profilerBlock.Children.Count).Append(") ");
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 50 * textScale;

            m_text.Clear();
            //text.Append(((index != -1 ? profilerBlock.TimePercentage[index] : profilerBlock.averagePctg)).ToString("#,#0.0%"));
            //MyDebugDraw.DrawTextShadow(new Vector2(20 + length, textPosY), text, color, textScale);
            length += 155 * textScale;

            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.TimeFormat ?? "{0:.00}ms", miliseconds);
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 155 * textScale;

            m_text.Clear();
            m_text.Concat(managedMemory, 3).Append(" GC");
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 40 + 158 * textScale;

            m_text.Clear();
            if (MemoryProfiling)
            {
                m_text.Concat(processMemory, 3).Append(" MB");
                MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
                length += 158 * textScale;

                m_text.Clear();
            }

            length += 40 + 40 * textScale;
            m_text.Append(numCalls);
            m_text.Append(" calls");
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            length += 150 * textScale;
            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.ValueFormat ?? "Custom: {0:.00}", customValue);
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            int maxIndex;
            length += 250 * textScale;
            float max = FindMaxWrap(profilerBlock.Miliseconds, frameIndex - m_frameLocalArea / 2, frameIndex + m_frameLocalArea / 2, lastValidFrame, out maxIndex);
            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.TimeFormat ?? "{0:.00}ms", max);
            MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            length += MyRender.DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
        }
        protected override void Draw(MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw)
        {
            Debug.Assert(frameToDraw >= 0 && frameToDraw < MyProfiler.MAX_FRAMES, "Invalid selected frame");

            // Init linebatch
            if (m_lineBatch == null)
            {
                SharpDX.Direct3D9.Device device = MyRender.GraphicsDevice;
                m_lineBatch = new MyLineBatch(Matrix.Identity, Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 0, -1), 50000);

                m_fpsBlock.Start(false);
            }

            // Handle FPS timer
            m_fpsBlock.End(false);

            float elapsedTime = (float)m_fpsBlock.Elapsed.Seconds;
            float invElapsedTime = elapsedTime > 0 ? 1 / elapsedTime : 0;
            m_fpsPctg = 0.9f * m_fpsPctg + 0.1f * invElapsedTime;

            if (MemoryProfiling)
            {
                // Handle memory usage for frame
                float processDeltaMB = m_fpsBlock.ProcessDeltaMB;
                m_fpsBlock.ProcessMemory[lastFrameIndex] = processDeltaMB;
            }

            float managedDeltaMB = m_fpsBlock.ManagedDeltaMB;
            m_fpsBlock.ManagedMemory[lastFrameIndex] = managedDeltaMB;
            m_fpsBlock.CustomValues[lastFrameIndex] = m_fpsBlock.CustomValue;

            m_fpsBlock.Reset();

            m_fpsBlock.Start(false);

            if (m_enabled)
            {
                // Draw events as text 
                float eventLineSize = 20;
                float largeTextLineSize = 28;
                float textOffsetY = MyRender.GraphicsDevice.Viewport.Height / 2 - 8 * largeTextLineSize;

                // Draw thread name and level limit
                m_text.Clear();
                m_text.ConcatFormat("\"{2}\" ({0}/{1})", m_selectedProfiler.GlobalProfilerIndex + 1, m_threadProfilers.Count, m_selectedProfiler.OwnerThread.Name).AppendLine();
                m_text.Append("Level limit: ").AppendInt32(m_levelLimit).AppendLine();
                MyRender.DrawText(new Vector2(20, textOffsetY), m_text, Color.LightGray, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw frame number and local area
                m_text.Clear();
                m_text.Append("Frame: ").AppendInt32(frameToDraw).AppendLine();
                m_text.Append("Local area: ").AppendInt32(m_frameLocalArea);
                MyRender.DrawText(new Vector2(20, textOffsetY), m_text, Color.Yellow, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw fps and total calls
                m_text.Clear();
                m_text.Append(m_fpsBlock.Name).Append(" ");
                if (!m_useCustomFrame) // Show FPS only when not using custom frame
                    m_text.AppendDecimal(m_fpsPctg, 3);
                m_text.AppendLine();
                m_text.Append("Total calls: ").AppendInt32(IsValidIndex(frameToDraw, lastFrameIndex) ? m_selectedProfiler.TotalCalls[frameToDraw] : -1);
                MyRender.DrawText(new Vector2(20, textOffsetY), m_text, Color.Red, 1);
                textOffsetY += largeTextLineSize;

                textOffsetY = MyRender.GraphicsDevice.Viewport.Height / 2;
                var children = m_selectedProfiler.SelectedRootChildren;
                for (int i = 0; i < children.Count; i++)
                {
                    MyProfiler.MyProfilerBlock profilerBlock = children[i];

                    DrawEvent(textOffsetY, profilerBlock, i, frameToDraw, lastFrameIndex);
                    textOffsetY += eventLineSize;
                }

                // Draw graphs
                m_lineBatch.Begin();
                DrawPerfEvents(lastFrameIndex);

                VRageRender.Graphics.BlendState.Opaque.Apply();
                m_lineBatch.End();
            }

            // Update horizontal offset
            if (!Paused && !m_useCustomFrame)
            {
                m_selectedFrame = lastFrameIndex;
            }
        }
        public void StartProfilingBlock(string blockName = null, float customValue = 0, [CallerMemberName] string member = "", [CallerLineNumber] int line = 0, [CallerFilePath] string file = "")
        {
            ThreadProfiler.StartBlock(blockName, member, line, file);

            if (m_selectedProfiler == null)
            {
                m_selectedProfiler = ThreadProfiler;
            }
        }
        public static void HandleInput(RenderProfilerCommand command, int index)
        {
            switch (command)
            {
                case RenderProfilerCommand.Enable:
                    {
                        // Enable or Disable profiler drawing
                        if (m_enabled && m_selectedProfiler.SelectedRoot == null)
                        {
                            m_enabled = false;
                            m_useCustomFrame = false;
                        }
                        else if (!m_enabled)
                        {
                            m_enabled = true;
                        }
                        else
                        {
                            // Go to parent node
                            if (m_selectedProfiler.SelectedRoot != null)
                            {
                                m_selectedProfiler.SelectedRoot = m_selectedProfiler.SelectedRoot.Parent;
                            }
                        }
                        break;
                    }

                case RenderProfilerCommand.JumpToLevel:
                    {
                        m_selectedProfiler.SelectedRoot = FindBlockByIndex(index - 1); // On screen it's indexed from 1 (zero is level up)
                        break;
                    }

                case RenderProfilerCommand.FindMaxChild:
                    {
                        MyProfiler.MyProfilerBlock block;
                        int lastFrameIndex;
                        using (m_selectedProfiler.LockHistory(out lastFrameIndex))
                        {
                            block = FindBlockByMax(m_selectedFrame, lastFrameIndex);
                        }
                        if (block != null)
                        {
                            m_selectedProfiler.SelectedRoot = block;
                        }
                        break;
                    }

                case RenderProfilerCommand.Pause:
                    {
                        Paused = !Paused;
                        m_useCustomFrame = false; // Turn-off custom frame after ALT + ENTER

                        break;
                    }

                case RenderProfilerCommand.NextThread:
                    {
                        lock (m_threadProfilers)
                        {
                            int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) + 1) % m_threadProfilers.Count;
                            m_selectedProfiler = m_threadProfilers[profilerIndex];
                        }
                        break;
                    }

                case RenderProfilerCommand.PreviousThread:
                    {
                        lock (m_threadProfilers)
                        {
                            int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) - 1 + m_threadProfilers.Count) % m_threadProfilers.Count;
                            m_selectedProfiler = m_threadProfilers[profilerIndex];
                        }
                        break;
                    }

                case RenderProfilerCommand.NextFrame:
                    {
                        MyRenderProfiler.NextFrame();
                        break;
                    }

                case RenderProfilerCommand.PreviousFrame:
                    {
                        MyRenderProfiler.PreviousFrame();
                        break;
                    }

                case RenderProfilerCommand.IncreaseLevel:
                    {
                        m_levelLimit++;
                        SetLevel();
                        break;
                    }

                case RenderProfilerCommand.DecreaseLevel:
                    {
                        m_levelLimit--;
                        if (m_levelLimit < -1)
                            m_levelLimit = -1;
                        SetLevel();
                        break;
                    }

                case RenderProfilerCommand.DecreaseLocalArea:
                    m_frameLocalArea = Math.Max(2, m_frameLocalArea / 2);
                    break;

                case RenderProfilerCommand.IncreaseLocalArea:
                    m_frameLocalArea = Math.Min(MyProfiler.MAX_FRAMES, m_frameLocalArea * 2);
                    break;

                case RenderProfilerCommand.IncreaseRange:
                    m_milisecondsGraphScale.IncreaseYRange();
                    break;

                case RenderProfilerCommand.DecreaseRange:
                    m_milisecondsGraphScale.DecreaseYRange();
                    break;

                default:
                    System.Diagnostics.Debug.Assert(false, "Unknown command");
                    break;
            }
        }
        void DrawEvent(float textPosY, MyProfiler.MyProfilerBlock profilerBlock, int blockIndex, int frameIndex, int lastValidFrame, ref Color color)
        {
            float miliseconds = 0;
            long managedMemory = 0;
            float processMemory = 0;
            int numCalls = -1; // To show update window in profiler
            float customValue = 0;

            if (IsValidIndex(frameIndex, lastValidFrame))
            {
                miliseconds = profilerBlock.Miliseconds[frameIndex];
                managedMemory = profilerBlock.ManagedMemoryBytes[frameIndex];
                processMemory = profilerBlock.ProcessMemory[frameIndex];
                numCalls = profilerBlock.NumCallsArray[frameIndex];
                customValue = profilerBlock.CustomValues[frameIndex];
            }

            float Y_TEXT_POSITION = ViewportSize.Y / 2;

            float textScale = 0.7f;

            m_text.Clear().Append(blockIndex + 1).Append(" ").Append(profilerBlock.Name);
            DrawTextShadow(new Vector2(20, textPosY), m_text, color, textScale);

            float length = 500;

            m_text.Clear();
            m_text.Append("(").Append(profilerBlock.Children.Count).Append(") ");
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 50 * textScale;

            m_text.Clear();
            //text.Append(((index != -1 ? profilerBlock.TimePercentage[index] : profilerBlock.averagePctg)).ToString("#,#0.0%"));
            //MyDebugDraw.DrawTextShadow(new Vector2(20 + length, textPosY), text, color, textScale);
            length += 155 * textScale;

            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.TimeFormat ?? "{0:.00}ms", miliseconds);
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 155 * textScale;

            m_text.Clear();
            if (managedMemory < 1024 && managedMemory > -1024) // Still in bytes?
            {
                m_text.Append(managedMemory.ToString()).Append(" B");
            }
            else if (managedMemory < 1048576 && managedMemory > -1048576) // Still in kilobytes?
            {
                float managedMemoryKB = managedMemory / 1024f;
                m_text.Concat(managedMemoryKB, 3).Append(" KB");
            }
            else // Else display in megabytes
            {
                float managedMemoryKB = managedMemory / 1048576;
                m_text.Concat(managedMemoryKB, 3).Append(" MB");
            }
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
            length += 40 + 158 * textScale;

            m_text.Clear();
            if (MemoryProfiling)
            {
                m_text.Concat(processMemory, 3).Append(" MB");
                DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
                length += 158 * textScale;

                m_text.Clear();
            }

            length += 40 + 40 * textScale;
            m_text.ConcatFormat(profilerBlock.CallFormat ?? "{0} calls", numCalls);
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            length += 150 * textScale;
            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.ValueFormat ?? "Custom: {0:.00}", customValue);
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            int maxIndex;
            length += 250 * textScale;
            float max = FindMaxWrap(profilerBlock.Miliseconds, frameIndex - m_frameLocalArea / 2, frameIndex + m_frameLocalArea / 2, lastValidFrame, out maxIndex);
            m_text.Clear();
            m_text.ConcatFormat(profilerBlock.TimeFormat ?? "{0:.00}ms", max);
            DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);

            length += DrawTextShadow(new Vector2(20 + length, textPosY), m_text, color, textScale);
        }
        protected sealed override void Draw(MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw)
        {
            Debug.Assert(frameToDraw >= 0 && frameToDraw < MyProfiler.MAX_FRAMES, "Invalid selected frame");

            if (!m_initialized)
            {
                // Init linebatch
                Init();
                m_initialized = true;
                m_fpsBlock.Start(false);
            }

            // Handle FPS timer
            m_fpsBlock.End(false);

            float elapsedTime = (float)m_fpsBlock.Elapsed.Seconds;
            float invElapsedTime = elapsedTime > 0 ? 1 / elapsedTime : 0;
            m_fpsPctg = 0.9f * m_fpsPctg + 0.1f * invElapsedTime;

            if (MemoryProfiling)
            {
                // Handle memory usage for frame
                float processDeltaMB = m_fpsBlock.ProcessDeltaMB;
                m_fpsBlock.ProcessMemory[lastFrameIndex] = processDeltaMB;
            }

            long managedDeltaMB = m_fpsBlock.ManagedDeltaMB;
            m_fpsBlock.ManagedMemoryBytes[lastFrameIndex] = managedDeltaMB;
            m_fpsBlock.CustomValues[lastFrameIndex] = m_fpsBlock.CustomValue;

            m_fpsBlock.Reset();

            m_fpsBlock.Start(false);

            if (m_enabled)
            {
                // Draw events as text 
                float eventLineSize = 20;
                float largeTextLineSize = 28;
                float textOffsetY = ViewportSize.Y / 2 - 8 * largeTextLineSize;

                // Draw thread name and level limit
                m_text.Clear();
                m_text.ConcatFormat("\"{2}\" ({0}/{1})", m_threadProfilers.IndexOf(m_selectedProfiler) + 1, m_threadProfilers.Count, m_selectedProfiler.DisplayedName).AppendLine();
                m_text.Append("Level limit: ").AppendInt32(m_selectedProfiler.LevelLimit).AppendLine();
                DrawText(new Vector2(20, textOffsetY), m_text, Color.LightGray, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw frame number and local area
                m_text.Clear();
                m_text.Append("Frame: ").AppendInt32(frameToDraw).AppendLine();
                m_text.Append("Local area: ").AppendInt32(m_frameLocalArea);
                DrawText(new Vector2(20, textOffsetY), m_text, Color.Yellow, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw fps and total calls
                m_text.Clear();
                m_text.Append(m_fpsBlock.Name).Append(" ");
                if (!m_useCustomFrame) // Show FPS only when not using custom frame
                    m_text.AppendDecimal(m_fpsPctg, 3);
                m_text.AppendLine();
                m_text.Append("Total calls: ").AppendInt32(IsValidIndex(frameToDraw, lastFrameIndex) ? m_selectedProfiler.TotalCalls[frameToDraw] : -1);
                DrawText(new Vector2(20, textOffsetY), m_text, Color.Red, 1);
                textOffsetY += largeTextLineSize;

                m_text.Clear();
                if (!VRage.MyCompilationSymbols.PerformanceProfiling)
                {
                    m_text.Append("MyCompilationSymbols.PerformanceProfiling NOT ENABLED!").AppendLine();
                }
                if (!ProfilerProcessingEnabled)
                {
                    m_text.Append("Profiler processing disabled, F12 -> Profiler").AppendLine();
                }
                DrawText(new Vector2(0, 0), m_text, Color.Yellow, 0.6f);

                textOffsetY = ViewportSize.Y / 2;
                List<MyProfilerBlock> children = m_selectedProfiler.SelectedRootChildren;
                List<MyProfilerBlock> sortedChildren = GetSortedChildren(frameToDraw);

                // Draw the 'stack trace'
                m_text.Clear();
                MyProfilerBlock currentBlock = m_selectedProfiler.SelectedRoot;

                while (currentBlock != null)
                {
                    // Stop inserting new elements if the path becomes too long
                    if (currentBlock.Name.Length + 3 + m_text.Length > 170)
                    {
                        m_text.Insert(0, "... > ");
                        break;
                    }

                    if (m_text.Length > 0)
                        m_text.Insert(0, " > ");
                    m_text.Insert(0, currentBlock.Name);
                    currentBlock = currentBlock.Parent;
                }

                DrawTextShadow(new Vector2(20, textOffsetY), m_text, Color.White, 0.7f);
                textOffsetY += eventLineSize;

                if (m_selectedProfiler.SelectedRoot != null)
                {
                    Color whiteColor = Color.White;
                    DrawEvent(textOffsetY, m_selectedProfiler.SelectedRoot, -1, frameToDraw, lastFrameIndex, ref whiteColor);
                    textOffsetY += eventLineSize;
                }

                if (sortedChildren.Count > 0)
                {
                    // Draw the sorting order indicator
                    m_text.Clear().Append("\\/");
                    switch (m_sortingOrder)
                    {
                        case RenderProfilerSortingOrder.Id:
                            m_text.Append(" ASC");
                            DrawTextShadow(new Vector2(20, textOffsetY), m_text, Color.White, 0.7f);
                            break;
                        case RenderProfilerSortingOrder.MillisecondsLastFrame:
                            m_text.Append(" DESC");
                            DrawTextShadow(new Vector2(660, textOffsetY), m_text, Color.White, 0.7f);
                            break;
                        case RenderProfilerSortingOrder.MillisecondsAverage:
                            m_text.Append(" DESC");
                            DrawTextShadow(new Vector2(1270, textOffsetY), m_text, Color.White, 0.7f);
                            break;
                    }
                    textOffsetY += eventLineSize;

                    // Draw the profiler blocks
                    for (int i = 0; i < sortedChildren.Count; i++)
                    {
                        MyProfilerBlock profilerBlock = sortedChildren[i];

                        Color lineColor = IndexToColor(children.IndexOf(profilerBlock));

                        DrawEvent(textOffsetY, profilerBlock, i, frameToDraw, lastFrameIndex, ref lineColor);
                        textOffsetY += eventLineSize;
                    }
                }
                else
                {
                    m_text.Clear().Append("No more blocks at this point!");
                    textOffsetY += eventLineSize;
                    DrawTextShadow(new Vector2(20, textOffsetY), m_text, Color.White, 0.7f);
                    textOffsetY += eventLineSize;
                }

                // Draw graphs
                BeginLineBatch();
                DrawPerfEvents(lastFrameIndex);
                EndLineBatch();
            }

            // Update horizontal offset
            if (!Paused && !m_useCustomFrame)
            {
                m_selectedFrame = lastFrameIndex;
            }
        }
        public static void HandleInput(RenderProfilerCommand command, int index)
        {
            switch (command)
            {
            case RenderProfilerCommand.Enable:
            {
                if (!m_enabled)
                {
                    m_enabled = true;
                    m_profilerProcessingEnabled = true;         // Enable when disabled and keep enabled
                    SetLevel();
                }
                break;
            }

            case RenderProfilerCommand.ToggleEnabled:
            {
                // Enable or Disable profiler drawing
                if (m_enabled)
                {
                    m_enabled        = false;
                    m_useCustomFrame = false;
                }
                else
                {
                    m_enabled = true;
                    m_profilerProcessingEnabled = true;         // Enable when disabled and keep enabled
                }
                break;
            }

            case RenderProfilerCommand.JumpToRoot:
                m_selectedProfiler.SelectedRoot = null;
                break;

            case RenderProfilerCommand.JumpToLevel:
            {
                // Enable when disabled, added this for programmers who are too used to using the numpad 0 to open the profiler.
                if (index == 0 && !m_enabled)
                {
                    m_enabled = true;
                    m_profilerProcessingEnabled = true;         // Enable when disabled and keep enabled
                }
                else
                {
                    m_selectedProfiler.SelectedRoot = FindBlockByIndex(index - 1);         // On screen it's indexed from 1 (zero is level up)
                }
                break;
            }

            case RenderProfilerCommand.Pause:
            {
                Paused = !Paused;
                GpuProfiler.AutoCommit = !Paused;
                break;
            }

            case RenderProfilerCommand.NextThread:
            {
                lock (m_threadProfilers)
                {
                    int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) + 1) % m_threadProfilers.Count;
                    m_selectedProfiler = m_threadProfilers[profilerIndex];
                }
                break;
            }

            case RenderProfilerCommand.PreviousThread:
            {
                lock (m_threadProfilers)
                {
                    int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) - 1 + m_threadProfilers.Count) % m_threadProfilers.Count;
                    m_selectedProfiler = m_threadProfilers[profilerIndex];
                }
                break;
            }

            case RenderProfilerCommand.Reset:
            {
                lock (m_threadProfilers)
                {
                    foreach (var profiler in m_threadProfilers)
                    {
                        profiler.Reset();
                    }
                    m_selectedFrame = 0;
                }
                break;
            }

            case RenderProfilerCommand.NextFrame:
            {
                MyRenderProfiler.NextFrame(index);
                break;
            }

            case RenderProfilerCommand.PreviousFrame:
            {
                MyRenderProfiler.PreviousFrame(index);
                break;
            }

            case RenderProfilerCommand.DisableFrameSelection:
            {
                m_useCustomFrame = false;
                break;
            }

            case RenderProfilerCommand.IncreaseLevel:
            {
                m_levelLimit++;
                SetLevel();
                break;
            }

            case RenderProfilerCommand.DecreaseLevel:
            {
                m_levelLimit--;
                if (m_levelLimit < -1)
                {
                    m_levelLimit = -1;
                }
                SetLevel();
                break;
            }

            case RenderProfilerCommand.CopyPathToClipboard:
            {
                StringBuilder   pathBuilder  = new StringBuilder(200);
                MyProfilerBlock currentBlock = m_selectedProfiler.SelectedRoot;

                while (currentBlock != null)
                {
                    if (pathBuilder.Length > 0)
                    {
                        pathBuilder.Insert(0, " > ");
                    }
                    pathBuilder.Insert(0, currentBlock.Name);
                    currentBlock = currentBlock.Parent;
                }

                if (pathBuilder.Length > 0)
                {
                    // Clipboard can only be accessed from a thread on the STA apartment
                    System.Threading.Thread thread = new System.Threading.Thread(() => System.Windows.Forms.Clipboard.SetText(pathBuilder.ToString()));
                    thread.SetApartmentState(System.Threading.ApartmentState.STA);
                    thread.Start();
                    thread.Join();
                }
                break;
            }

            case RenderProfilerCommand.TryGoToPathInClipboard:
            {
                string fullPath = string.Empty;

                Exception threadEx = null;
                System.Threading.Thread staThread = new System.Threading.Thread(
                    delegate()
                    {
                        try
                        {
                            fullPath = System.Windows.Forms.Clipboard.GetText();
                        }

                        catch (Exception ex)
                        {
                            threadEx = ex;
                        }
                    });
                staThread.SetApartmentState(System.Threading.ApartmentState.STA);
                staThread.Start();
                staThread.Join();

                if (!string.IsNullOrEmpty(fullPath))
                {
                    string[] split = fullPath.Split(new string[] { " > " }, StringSplitOptions.None);

                    MyProfilerBlock        pathBlock = null;
                    List <MyProfilerBlock> blockSet  = m_selectedProfiler.RootBlocks;
                    for (int i = 0; i < split.Length; i++)
                    {
                        string          blockName = split[i];
                        MyProfilerBlock oldPath   = pathBlock;

                        for (int j = 0; j < blockSet.Count; j++)
                        {
                            MyProfilerBlock block = blockSet[j];
                            if (block.Name == blockName)
                            {
                                pathBlock = block;
                                blockSet  = pathBlock.Children;
                                break;
                            }
                        }

                        // If the path did not change, we cannot go any deeper, break out of this loop
                        if (oldPath == pathBlock)
                        {
                            break;
                        }
                    }

                    if (pathBlock != null)
                    {
                        m_selectedProfiler.SelectedRoot = pathBlock;
                    }
                }
                break;
            }

            case RenderProfilerCommand.SetLevel:
            {
                m_levelLimit = index;
                if (m_levelLimit < -1)
                {
                    m_levelLimit = -1;
                }
                SetLevel();
                break;
            }

            case RenderProfilerCommand.DecreaseLocalArea:
                m_frameLocalArea = Math.Max(2, m_frameLocalArea / 2);
                break;

            case RenderProfilerCommand.IncreaseLocalArea:
                m_frameLocalArea = Math.Min(MyProfiler.MAX_FRAMES, m_frameLocalArea * 2);
                break;

            case RenderProfilerCommand.IncreaseRange:
                m_milisecondsGraphScale.IncreaseYRange();
                break;

            case RenderProfilerCommand.DecreaseRange:
                m_milisecondsGraphScale.DecreaseYRange();
                break;

            case RenderProfilerCommand.ChangeSortingOrder:
                m_sortingOrder += 1;
                if (m_sortingOrder >= RenderProfilerSortingOrder.NumSortingTypes)
                {
                    m_sortingOrder = RenderProfilerSortingOrder.Id;
                }
                break;

            default:
                System.Diagnostics.Debug.Assert(false, "Unknown command");
                break;
            }
        }
        public static void HandleInput(RenderProfilerCommand command, int index)
        {
            switch (command)
            {
                case RenderProfilerCommand.Enable:
                    {
                        if (!m_enabled)
                        {
                            m_enabled = true;
                            m_profilerProcessingEnabled = true; // Enable when disabled and keep enabled
                            SetLevel();
                        }
                        break;
                    }

                case RenderProfilerCommand.ToggleEnabled:
                    {
                        // Enable or Disable profiler drawing
                        if (m_enabled)
                        {
                            m_enabled = false;
                            m_useCustomFrame = false;
                        }
                        else
                        {
                            m_enabled = true;
                            m_profilerProcessingEnabled = true; // Enable when disabled and keep enabled
                        }
                        break;
                    }

                case RenderProfilerCommand.JumpToRoot:
                    m_selectedProfiler.SelectedRoot = null;
                    break;

                case RenderProfilerCommand.JumpToLevel:
                    {
                        // Enable when disabled, added this for programmers who are too used to using the numpad 0 to open the profiler.
                        if (index == 0 && !m_enabled)
                        {
                            m_enabled = true;
                            m_profilerProcessingEnabled = true; // Enable when disabled and keep enabled
                        }
                        else
                            m_selectedProfiler.SelectedRoot = FindBlockByIndex(index - 1); // On screen it's indexed from 1 (zero is level up)
                        break;
                    }
                case RenderProfilerCommand.Pause:
                    {
                        Paused = !Paused;
                        break;
                    }

                case RenderProfilerCommand.NextThread:
                    {
                        lock (m_threadProfilers)
                        {
                            int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) + 1) % m_threadProfilers.Count;
                            m_selectedProfiler = m_threadProfilers[profilerIndex];
                        }
                        break;
                    }

                case RenderProfilerCommand.PreviousThread:
                    {
                        lock (m_threadProfilers)
                        {
                            int profilerIndex = (m_threadProfilers.IndexOf(m_selectedProfiler) - 1 + m_threadProfilers.Count) % m_threadProfilers.Count;
                            m_selectedProfiler = m_threadProfilers[profilerIndex];
                        }
                        break;
                    }

                case RenderProfilerCommand.Reset:
                    {
                        lock (m_threadProfilers)
                        {
                            foreach (var profiler in m_threadProfilers)
                            {
                                profiler.Reset();
                            }
                            m_selectedFrame = 0;
                        }
                        break;
                    }

                case RenderProfilerCommand.NextFrame:
                    {
                        MyRenderProfiler.NextFrame(index);
                        break;
                    }

                case RenderProfilerCommand.PreviousFrame:
                    {
                        MyRenderProfiler.PreviousFrame(index);
                        break;
                    }

                case RenderProfilerCommand.DisableFrameSelection:
                    {
                        m_useCustomFrame = false;
                        break;
                    }

                case RenderProfilerCommand.IncreaseLevel:
                    {
                        m_levelLimit++;
                        SetLevel();
                        break;
                    }

                case RenderProfilerCommand.DecreaseLevel:
                    {
                        m_levelLimit--;
                        if (m_levelLimit < -1)
                            m_levelLimit = -1;
                        SetLevel();
                        break;
                    }

                case RenderProfilerCommand.CopyPathToClipboard:
                    {
                        StringBuilder pathBuilder = new StringBuilder(200);
                        MyProfilerBlock currentBlock = m_selectedProfiler.SelectedRoot;

                        while (currentBlock != null)
                        {
                            if (pathBuilder.Length > 0)
                                pathBuilder.Insert(0, " > ");
                            pathBuilder.Insert(0, currentBlock.Name);
                            currentBlock = currentBlock.Parent;
                        }

                        if (pathBuilder.Length > 0)
                        {
                            // Clipboard can only be accessed from a thread on the STA apartment
                            System.Threading.Thread thread = new System.Threading.Thread(() => System.Windows.Forms.Clipboard.SetText(pathBuilder.ToString()));
                            thread.SetApartmentState(System.Threading.ApartmentState.STA);
                            thread.Start();
                            thread.Join();
                        }
                        break;
                    }

                case RenderProfilerCommand.TryGoToPathInClipboard:
                    {
                        string fullPath = string.Empty;

                        Exception threadEx = null;
                        System.Threading.Thread staThread = new System.Threading.Thread(
                            delegate()
                            {
                                try
                                {
                                    fullPath = System.Windows.Forms.Clipboard.GetText();
                                }

                                catch (Exception ex)
                                {
                                    threadEx = ex;
                                }
                            });
                        staThread.SetApartmentState(System.Threading.ApartmentState.STA);
                        staThread.Start();
                        staThread.Join();

                        if (!string.IsNullOrEmpty(fullPath))
                        {
                            string[] split = fullPath.Split(new string[] { " > " }, StringSplitOptions.None);

                            MyProfilerBlock pathBlock = null;
                            List<MyProfilerBlock> blockSet = m_selectedProfiler.RootBlocks;
                            for (int i = 0; i<split.Length; i++)
                            {
                                string blockName = split[i];
                                MyProfilerBlock oldPath = pathBlock;

                                for (int j = 0; j<blockSet.Count; j++)
                                {
                                    MyProfilerBlock block = blockSet[j];
                                    if (block.Name == blockName)
                                    {
                                        pathBlock = block;
                                        blockSet = pathBlock.Children;
                                        break;
                                    }
                                }

                                // If the path did not change, we cannot go any deeper, break out of this loop
                                if (oldPath == pathBlock)
                                    break;
                            }

                            if (pathBlock != null)
                                m_selectedProfiler.SelectedRoot = pathBlock;
                        }
                        break;
                    }

                case RenderProfilerCommand.SetLevel:
                    {
                        m_levelLimit = index;
                        if (m_levelLimit < -1)
                            m_levelLimit = -1;
                        SetLevel();
                        break;
                    }

                case RenderProfilerCommand.DecreaseLocalArea:
                    m_frameLocalArea = Math.Max(2, m_frameLocalArea / 2);
                    break;

                case RenderProfilerCommand.IncreaseLocalArea:
                    m_frameLocalArea = Math.Min(MyProfiler.MAX_FRAMES, m_frameLocalArea * 2);
                    break;

                case RenderProfilerCommand.IncreaseRange:
                    m_milisecondsGraphScale.IncreaseYRange();
                    break;

                case RenderProfilerCommand.DecreaseRange:
                    m_milisecondsGraphScale.DecreaseYRange();
                    break;

                case RenderProfilerCommand.ChangeSortingOrder:
                    m_sortingOrder += 1;
                    if (m_sortingOrder >= RenderProfilerSortingOrder.NumSortingTypes)
                        m_sortingOrder = RenderProfilerSortingOrder.Id;
                    break;

                default:
                    System.Diagnostics.Debug.Assert(false, "Unknown command");
                    break;
            }
        }
 protected abstract void Draw(MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw);
        internal void DestroyThread()
        {
            m_threadProfilers.Remove(m_threadProfiler);
            if (m_selectedProfiler == m_threadProfiler)
                m_selectedProfiler = m_threadProfilers.Count > 0 ? m_threadProfilers[0] : null;

            m_threadProfiler = null;
        }
        protected sealed override void Draw(MyProfiler drawProfiler, int lastFrameIndex, int frameToDraw)
        {
            Debug.Assert(frameToDraw >= 0 && frameToDraw < MyProfiler.MAX_FRAMES, "Invalid selected frame");

            if (!m_initialized)
            {
                // Init linebatch
                Init();
                m_initialized = true;
                m_fpsBlock.Start(false);
            }

            // Handle FPS timer
            m_fpsBlock.End(false);

            float elapsedTime = (float)m_fpsBlock.Elapsed.Seconds;
            float invElapsedTime = elapsedTime > 0 ? 1 / elapsedTime : 0;
            m_fpsPctg = 0.9f * m_fpsPctg + 0.1f * invElapsedTime;

            if (MemoryProfiling)
            {
                // Handle memory usage for frame
                float processDeltaMB = m_fpsBlock.ProcessDeltaMB;
                m_fpsBlock.ProcessMemory[lastFrameIndex] = processDeltaMB;
            }

            float managedDeltaMB = m_fpsBlock.ManagedDeltaMB;
            m_fpsBlock.ManagedMemory[lastFrameIndex] = managedDeltaMB;
            m_fpsBlock.CustomValues[lastFrameIndex] = m_fpsBlock.CustomValue;

            m_fpsBlock.Reset();

            m_fpsBlock.Start(false);

            if (m_enabled)
            {
                // Draw events as text 
                float eventLineSize = 20;
                float largeTextLineSize = 28;
                float textOffsetY = ViewportSize.Y / 2 - 8 * largeTextLineSize;

                // Draw thread name and level limit
                m_text.Clear();
                m_text.ConcatFormat("\"{2}\" ({0}/{1})", m_selectedProfiler.GlobalProfilerIndex + 1, m_threadProfilers.Count, m_selectedProfiler.DisplayedName).AppendLine();
                m_text.Append("Level limit: ").AppendInt32(m_selectedProfiler.LevelLimit).AppendLine();
                DrawText(new Vector2(20, textOffsetY), m_text, Color.LightGray, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw frame number and local area
                m_text.Clear();
                m_text.Append("Frame: ").AppendInt32(frameToDraw).AppendLine();
                m_text.Append("Local area: ").AppendInt32(m_frameLocalArea);
                DrawText(new Vector2(20, textOffsetY), m_text, Color.Yellow, 1);
                textOffsetY += largeTextLineSize * 2 + 10;

                // Draw fps and total calls
                m_text.Clear();
                m_text.Append(m_fpsBlock.Name).Append(" ");
                if (!m_useCustomFrame) // Show FPS only when not using custom frame
                    m_text.AppendDecimal(m_fpsPctg, 3);
                m_text.AppendLine();
                m_text.Append("Total calls: ").AppendInt32(IsValidIndex(frameToDraw, lastFrameIndex) ? m_selectedProfiler.TotalCalls[frameToDraw] : -1);
                DrawText(new Vector2(20, textOffsetY), m_text, Color.Red, 1);
                textOffsetY += largeTextLineSize;

                m_text.Clear();
                if (!VRage.MyCompilationSymbols.PerformanceProfiling)
                {
                    m_text.Append("MyCompilationSymbols.PerformanceProfiling NOT ENABLED!").AppendLine();
                }
                if (!ProfilerProcessingEnabled)
                {
                    m_text.Append("Profiler processing disabled, F12 -> Profiler").AppendLine();
                }
                DrawText(new Vector2(0, 0), m_text, Color.Yellow, 0.6f);

                textOffsetY = ViewportSize.Y / 2;
                var children = m_selectedProfiler.SelectedRootChildren;
                for (int i = 0; i < children.Count; i++)
                {
                    MyProfiler.MyProfilerBlock profilerBlock = children[i];

                    DrawEvent(textOffsetY, profilerBlock, i, frameToDraw, lastFrameIndex);
                    textOffsetY += eventLineSize;
                }

                // Draw graphs
                BeginLineBatch();
                DrawPerfEvents(lastFrameIndex);
                EndLineBatch();
            }

            // Update horizontal offset
            if (!Paused && !m_useCustomFrame)
            {
                m_selectedFrame = lastFrameIndex;
            }
        }