public void FlagTime(TimingFlagType flagType) { int flagId = (int)flagType; _timingFlags[_timingFlagIndex] = new TimingFlag() { FlagType = flagType, Timestamp = PerformanceCounter.ElapsedTicks }; _timingFlagCount = Math.Max(_timingFlagCount + 1, _maxFlags); // Work out average if (_timingFlagLast[flagId] != 0) { _timingFlagLastDelta[flagId] = _timingFlags[_timingFlagIndex].Timestamp - _timingFlagLast[flagId]; _timingFlagAverages[flagId] = (_timingFlagAverages[flagId] == 0) ? _timingFlagLastDelta[flagId] : (_timingFlagLastDelta[flagId] + _timingFlagAverages[flagId]) >> 1; } _timingFlagLast[flagId] = _timingFlags[_timingFlagIndex].Timestamp; // Notify subscribers _timingFlagCallback?.Invoke(_timingFlags[_timingFlagIndex]); if (++_timingFlagIndex >= _maxFlags) { _timingFlagIndex = 0; } }
public static void FlagTime(TimingFlagType flagType) { if (!ProfilingEnabled()) { return; } _profileInstance.FlagTime(flagType); }
private void DrawGraph(float xOffset, float yOffset, float width, SKCanvas canvas) { if (_sortedProfileData.Count != 0) { int left, right; float top, bottom; float graphRight = xOffset + width; float barHeight = (LineHeight - LinePadding); long history = Profile.HistoryLength; double timeWidthTicks = history / (double)_graphZoom; long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond); long ticksPerPixel = (long)(timeWidthTicks / width); // Reset start point if out of bounds if (timeWidthTicks + graphPositionTicks > history) { graphPositionTicks = history - (long)timeWidthTicks; _graphPosition = (float)graphPositionTicks / PerformanceCounter.TicksPerMillisecond; } graphPositionTicks = _captureTime - graphPositionTicks; // Draw timing flags if (_showFlags.Active) { TimingFlagType prevType = TimingFlagType.Count; SKPaint timingPaint = new SKPaint { Color = _timingFlagColors.First() }; foreach (TimingFlag timingFlag in _timingFlags) { if (prevType != timingFlag.FlagType) { prevType = timingFlag.FlagType; timingPaint.Color = _timingFlagColors[(int)prevType]; } int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width); if (x > xOffset) { canvas.DrawLine(new SKPoint(x, yOffset), new SKPoint(x, _rendererHeight), timingPaint); } } } SKPaint barPaint = new SKPaint() { Color = SKColors.Green, }; // Draw bars for (int verticalIndex = 0; verticalIndex < _sortedProfileData.Count; verticalIndex++) { KeyValuePair <ProfileConfig, TimingInfo> entry = _sortedProfileData[verticalIndex]; long furthest = 0; bottom = GetLineY(yOffset, LineHeight, LinePadding, false, verticalIndex); top = bottom + barHeight; // Skip rendering out of bounds bars if (top < 0 || bottom > _rendererHeight) { continue; } barPaint.Color = SKColors.Green; foreach (Timestamp timestamp in entry.Value.GetAllTimestamps()) { // Skip drawing multiple timestamps on same pixel if (timestamp.EndTime < furthest) { continue; } furthest = timestamp.EndTime + ticksPerPixel; left = (int)(graphRight - ((graphPositionTicks - timestamp.BeginTime) / timeWidthTicks) * width); right = (int)(graphRight - ((graphPositionTicks - timestamp.EndTime) / timeWidthTicks) * width); left = (int)Math.Max(xOffset + 1, left); // Make sure width is at least 1px right = Math.Max(left + 1, right); canvas.DrawRect(new SKRect(left, top, right, bottom), barPaint); } // Currently capturing timestamp barPaint.Color = SKColors.Red; long entryBegin = entry.Value.BeginTime; if (entryBegin != -1) { left = (int)(graphRight - ((graphPositionTicks - entryBegin) / timeWidthTicks) * width); // Make sure width is at least 1px left = Math.Min(left - 1, (int)graphRight); left = (int)Math.Max(xOffset + 1, left); canvas.DrawRect(new SKRect(left, top, graphRight, bottom), barPaint); } } string label = $"-{MathF.Round(_graphPosition, 2)} ms"; SKPaint labelPaint = new SKPaint() { Color = SKColors.White, TextSize = LineHeight }; float labelWidth = labelPaint.MeasureText(label); canvas.DrawText(label, new SKPoint(graphRight - labelWidth - LinePadding, FilterHeight + LinePadding), labelPaint); canvas.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", new SKPoint(xOffset + LinePadding, FilterHeight + LinePadding), labelPaint); } }
private void DrawGraph(float xOffset, float yOffset, float width) { if (_sortedProfileData.Count != 0) { int left, right; float top, bottom; int verticalIndex = 0; float graphRight = xOffset + width; float barHeight = (LineHeight - LinePadding); long history = Profile.HistoryLength; double timeWidthTicks = history / (double)_graphZoom; long graphPositionTicks = (long)(_graphPosition * PerformanceCounter.TicksPerMillisecond); long ticksPerPixel = (long)(timeWidthTicks / width); // Reset start point if out of bounds if (timeWidthTicks + graphPositionTicks > history) { graphPositionTicks = history - (long)timeWidthTicks; _graphPosition = (float)graphPositionTicks / PerformanceCounter.TicksPerMillisecond; } graphPositionTicks = _captureTime - graphPositionTicks; GL.Enable(EnableCap.ScissorTest); // Draw timing flags if (_displayFlags) { TimingFlagType prevType = TimingFlagType.Count; GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); GL.Begin(PrimitiveType.Lines); foreach (TimingFlag timingFlag in _timingFlags) { if (prevType != timingFlag.FlagType) { prevType = timingFlag.FlagType; GL.Color4(_timingFlagColors[(int)prevType]); } int x = (int)(graphRight - ((graphPositionTicks - timingFlag.Timestamp) / timeWidthTicks) * width); GL.Vertex2(x, 0); GL.Vertex2(x, Height); } GL.End(); GL.Disable(EnableCap.Blend); } // Draw bars GL.Begin(PrimitiveType.Triangles); foreach (var entry in _sortedProfileData) { long furthest = 0; bottom = GetLineY(yOffset, LineHeight, LinePadding, true, verticalIndex); top = bottom + barHeight; // Skip rendering out of bounds bars if (top < 0 || bottom > Height) { verticalIndex++; continue; } GL.Color3(Color.Green); foreach (Timestamp timestamp in entry.Value.GetAllTimestamps()) { // Skip drawing multiple timestamps on same pixel if (timestamp.EndTime < furthest) { continue; } furthest = timestamp.EndTime + ticksPerPixel; left = (int)(graphRight - ((graphPositionTicks - timestamp.BeginTime) / timeWidthTicks) * width); right = (int)(graphRight - ((graphPositionTicks - timestamp.EndTime) / timeWidthTicks) * width); // Make sure width is at least 1px right = Math.Max(left + 1, right); GL.Vertex2(left, bottom); GL.Vertex2(left, top); GL.Vertex2(right, top); GL.Vertex2(right, top); GL.Vertex2(right, bottom); GL.Vertex2(left, bottom); } // Currently capturing timestamp GL.Color3(Color.Red); long entryBegin = entry.Value.BeginTime; if (entryBegin != -1) { left = (int)(graphRight - ((graphPositionTicks - entryBegin) / timeWidthTicks) * width); // Make sure width is at least 1px left = Math.Min(left - 1, (int)graphRight); GL.Vertex2(left, bottom); GL.Vertex2(left, top); GL.Vertex2(graphRight, top); GL.Vertex2(graphRight, top); GL.Vertex2(graphRight, bottom); GL.Vertex2(left, bottom); } verticalIndex++; } GL.End(); GL.Disable(EnableCap.ScissorTest); string label = $"-{MathF.Round(_graphPosition, 2)} ms"; // Dummy draw for measure float labelWidth = _fontService.DrawText(label, 0, 0, LineHeight, false); _fontService.DrawText(label, graphRight - labelWidth - LinePadding, FilterHeight + LinePadding, LineHeight); _fontService.DrawText($"-{MathF.Round((float)((timeWidthTicks / PerformanceCounter.TicksPerMillisecond) + _graphPosition), 2)} ms", xOffset + LinePadding, FilterHeight + LinePadding, LineHeight); } }