// An instruction exits from a stage. private void ProcessInsnEndStage(string[] cols) { // 0 1 2 3 // field: E id stage segment ulong id = ParseUInt64(cols[1]); Insn insn = GetAliveInsn(id); if (insn == null) { m_errors.Add(string.Format("An unknown instruction ({0}) ends at line {1}.", id, m_currentLine)); return; } int segmentID = (int)ParseUInt64(cols[2]); string stageStr = cols[3]; Insn.Stage stage = GetStage(insn.Id, segmentID, stageStr); stage.EndRelCycle = (Int32)(m_currentCycle - insn.StartCycle); insn.AddStage(segmentID, stage); EndStage(insn.Id, segmentID, stageStr); if (stage == null) { m_errors.Add(string.Format("An unknown stage({0}) is finished at line {1}.", stageStr, m_currentLine)); } }
// An instruction retires from a processor. private void ProcessInsnRetire(string[] cols) { ulong id = ulong.Parse(cols[1]); // Instructions with the same retirement id are retired. if (m_retiredInsnMap.ContainsKey(id)) { m_errors.Add(string.Format("Instructions with the same retirement id({0}) are retired at line {1}.", id, m_currentLine)); return; } Insn insn = GetAliveInsn(id); if (insn == null) { m_errors.Add(string.Format("An unknown instruction ({0}) is retired at line {1}.", id, m_currentLine)); return; } insn.EndCycle = m_currentCycle; insn.Rid = ulong.Parse(cols[2]); insn.Flushed = ulong.Parse(cols[3]) == 0 ? false : true; WriteInsnToDB(insn); m_retiredInsnMap.Add(insn.Id, null); RemoveInsn(insn.Id); }
// Process a instruction dependency private void ProcessInsnDependency(string[] cols) { ulong id = ulong.Parse(cols[1]); Insn insn = GetAliveInsn(id); if (insn == null) { m_errors.Add(string.Format("Dpendencies of an unknown instruction ({0}) are dumped at line {1}.", id, m_currentLine)); return; } Insn.Relation rel = new Insn.Relation(); rel.id = ulong.Parse(cols[2]); if (cols.Length > 3) { rel.type = int.Parse(cols[3]); } else { rel.type = 0; // wakeup } insn.AddProducer(rel); }
// Update an instruction data base. private void WriteInsnToDB(Insn insn) { //m_db.Write( insn ); m_maxInsnId = Math.Max(insn.Id, m_maxInsnId); m_minInsnId = Math.Min(insn.Id, m_minInsnId); m_insnDB.Add(insn.Id, insn); }
// Create a new instruction from source strings. private void ProcessInsnInit(string[] cols) { Insn insn = NewInsnAtProcess(ulong.Parse(cols[1])); insn.Gsid = ulong.Parse(cols[2]); insn.Tid = ulong.Parse(cols[3]); }
// Get an instruction object from its id. // If there is no instruction related to an id, returns null. private Insn GetAliveInsn(ulong id) { /* * Debug.Assert( * m_insnMap.ContainsKey( id ), * String.Format( "Unknown insn({0})", id ) * );*/ Insn insn = null; m_insnMap.TryGetValue(id, out insn); return(insn); }
// oldY, newY の位置にあるInsnのX座標の差を得る private int CalculateInsnXDiffByY(int oldY, int newY) { Insn oldTop = GetInsn(coordinateSystem.InsnIdAtY(oldY)); Insn newTop = GetInsn(coordinateSystem.InsnIdAtY(newY)); if (oldTop == null || newTop == null) { return(0); } return(coordinateSystem.XAtCycle(newTop.StartCycle) - coordinateSystem.XAtCycle(oldTop.StartCycle)); }
private void DrawLabelView(Graphics g, Rectangle rect) { //g.TranslateTransform( 0, -panelMainView.ScrollPosition.Y ); //rect.Offset( 0, +panelMainView.ScrollPosition.Y ); g.Clear(panelLabel.BackColor); // 上下+1の範囲から描画しないと端が化ける ulong viewidfrom = coordinateSystem.InsnIdAtY(rect.Top + panelMainView.ScrollPosition.Y); ulong viewidto = coordinateSystem.InsnIdAtY(rect.Bottom + panelMainView.ScrollPosition.Y) + 1; if (viewidfrom > 0) { viewidfrom--; } if (ZoomedOut) { } else { for (ulong id = viewidfrom; id <= viewidto; id++) { if (!IsVisibleInsnId(id)) { continue; } Insn insn = GetInsn(id); string name = insn == null ? "" : insn.Name; ulong rid = insn == null ? 0 : insn.Rid; ulong tid = insn == null ? 0 : insn.Tid; ulong gsid = insn == null ? 0 : insn.Gsid; string s = string.Format( "{0}: {1} (T{2} : R{3}) : {4}", (id - coordinateSystem.IdFrom).ToString("D3"), // line gsid.ToString("D3"), // gsid tid, // tid rid.ToString("D3"), // rid name ); SizeF size = g.MeasureString(s, LabelFont); PointF p = new Point( 0, coordinateSystem.YAtInsnId(id) - panelMainView.ScrollPosition.Y ); p.Y += CellMarginHeight / 2.0f + coordinateSystem.Cell.Height / 2.0f - size.Height / 2.0f; g.DrawString(s, LabelFont, Brushes.Black, p); } } }
private void DrawDependency(Graphics g, ulong drawIdFrom, ulong drawIdTo, ulong viewIdFrom, ulong viewIdTo) { if (!(currentViewSetting.DrawDependencyLeftCurve && DrawDependencyLeftCurve) && !(currentViewSetting.DrawDependencyInsideCurve && DrawDependencyInsideCurve) && !(currentViewSetting.DrawDependencyInsideLine && DrawDependencyInsideLine) ) { return; } List <Dependency> deps = new List <Dependency>(); for (ulong id = drawIdFrom; id <= drawIdTo; id++) { Insn insn = GetInsn(id); if (insn == null) { continue; } var prodConsList = new[] { insn.Producers, insn.Consumers }; foreach (var insnList in prodConsList) { foreach (Insn.Relation rel in insnList) { Insn relInsn = GetInsn(rel.id); if (relInsn == null) { continue; } ulong prodID = Math.Min(id, rel.id); ulong consID = Math.Max(id, rel.id); if (!(viewIdFrom > consID || viewIdTo < prodID)) { Dependency dep = new Dependency(prodID, consID, rel.type); if (!deps.Contains(dep)) { deps.Add(dep); } } } } } foreach (Dependency dep in deps) { DrawDependencyArrow(g, dep.Producer, dep.Consumer, dep.Type); } }
// Create a new instruction. private Insn NewInsnAtProcess(ulong id) { Insn n = new Insn(); n.Init(); n.Id = id; n.StartCycle = m_currentCycle; m_insnMap.Add(id, n); foreach (var s in m_segments) { s.stageMap.Add(id, null); } return(n); }
private void panelLabel_MouseClick(object sender, MouseEventArgs e) { int y = e.Y + panelMainView.ScrollPosition.Y; ulong id = coordinateSystem.InsnIdAtY(y); Insn insn = GetInsn(id); if (insn == null) { return; } int x = coordinateSystem.XAtCycle(insn.StartCycle); panelMainView.ScrollPosition = new Point(x, panelMainView.ScrollPosition.Y); }
private void ChangeZoom(Point basePoint, int zoomValue, bool changeTrackBar, bool mousePointBaseX) { //Trace.WriteLine( string.Format( "({0}, {1})", basePoint.X, basePoint.Y ) ); // 基準座標と拡大率 if (zoomValue > trackBarZoom.Maximum) { zoomValue = trackBarZoom.Maximum; } else if (zoomValue < trackBarZoom.Minimum) { zoomValue = trackBarZoom.Minimum; } int baseY = basePoint.Y; int offsetY = (basePoint.Y - panelMainView.ScrollPosition.Y); int offsetX = (basePoint.X - panelMainView.ScrollPosition.X); // 対応するInsn を取得 ulong id = coordinateSystem.InsnIdAtY(baseY); Insn insn = GetInsn(id); if (insn == null) { return; } long offsetCycle = coordinateSystem.CycleAtX(basePoint.X); // 拡大 ZoomFactor = zoomValue; if (changeTrackBar) { trackBarZoom.Value = zoomValue; } // 位置を直す int y = coordinateSystem.YAtInsnId(insn.Id) - offsetY; int x = mousePointBaseX ? coordinateSystem.XAtCycle(offsetCycle) - offsetX : coordinateSystem.XAtCycle(GetInsn(coordinateSystem.InsnIdAtY(y)).StartCycle); panelMainView.ScrollPosition = new Point(x, y); }
// バックグラウンドの描画 private void DrawMainViewBackGround(Graphics g, Rectangle backGroundRect) { if (config.MainViewTransparent) { g.Clear(panelMainView.BackColor); return; } float cellHeight = coordinateSystem.Grid.Height; int bottom = backGroundRect.Bottom + (int)cellHeight; if (!IsYVisible(backGroundRect.Bottom - 1)) { bottom = GetVisibleBottom(); // Draw the background out of valid insn range Rectangle rect = new Rectangle( backGroundRect.Left, bottom, backGroundRect.Width, backGroundRect.Bottom - bottom ); g.FillRectangle(invalidBackGroundBrush, rect); } for (float y = backGroundRect.Top; y < bottom; y += cellHeight) { ulong insnID = coordinateSystem.InsnIdAtY((int)y); int top = coordinateSystem.YAtInsnId(insnID); Insn insn = GetInsn(insnID); if (insn == null) { continue; } ulong tid = insn.Tid; Rectangle rect = new Rectangle( backGroundRect.Left, top, backGroundRect.Width, (int)cellHeight ); Brush brush = GetBackGroundBrush((int)tid); g.FillRectangle(brush, rect); } }
// ラベル上でマウスオーバー位置のInsnの情報を表示する private void panelLabel_MouseMove(object sender, MouseEventArgs e) { Point mousePos = new Point(e.X, e.Y); if (lastMousePos == mousePos) { return; } lastMousePos = mousePos; ulong id = coordinateSystem.InsnIdAtY(e.Y + panelMainView.ScrollPosition.Y) - coordinateSystem.IdFrom; if (!IsVisibleInsnId(id)) { toolTip.SetToolTip(panelLabel, ""); return; } Insn insn = GetInsn(id); if (insn != null) { String msg = String.Format( "{0}\n" + "{1}\n" + "Line :\t\t{2}\n" + "Global Serial ID:\t{3}\n" + "Thread ID:\t\t{4}\n" + "Retire ID:\t\t{5}\n", insn.Name, insn.Detail, insn.Id, insn.Gsid, insn.Tid, insn.Rid ); if (insn.Flushed) { msg += "# This op is flushed."; } toolTip.SetToolTip(panelLabel, msg); } }
// An instruction enters a new stage. private void ProcessInsnBeginStage(string[] cols) { // 0 1 2 3 // field: S id segment stage ulong id = ParseUInt64(cols[1]); Insn insn = GetAliveInsn(id); if (insn == null) { m_errors.Add(string.Format("An unknown instruction ({0}) begins at line {1}.", id, m_currentLine)); return; } int segmentID = (int)ParseUInt64(cols[2]); string stageStr = cols[3]; Insn.Stage stage = NewStage(insn.Id, segmentID, stageStr); stage.Id = GetStageId(segmentID, stageStr); stage.BeginRelCycle = (Int32)(m_currentCycle - insn.StartCycle); }
// Process an instruction label. private void ProcessInsnLabel(string[] cols) { ulong id = ulong.Parse(cols[1]); ulong type = ulong.Parse(cols[2]); Insn insn = GetAliveInsn(id); if (insn == null) { m_errors.Add(string.Format("An unknown instruction ({0}) is labeled at line {1}.", id, m_currentLine)); return; } // "\\n" is converted to "\n" StringBuilder labelStr = new StringBuilder(cols[3]); labelStr.Replace("\\n", "\n"); labelStr.Replace("\\t", "\t"); if (type == 0) { insn.Name += labelStr; } else if (type == 1) { insn.Detail += labelStr; } else if (type == 2) { // Labels strings to a current stage. var stage = m_segments[0].stageMap[id]; if (stage != null) { stage.Comment += labelStr; } } else { m_errors.Add(string.Format("An unknown label type ({0}) at line {1}.", type, m_currentLine)); return; } }
// Close all unclosed stages. private void CloseStages() { foreach (var segment in m_segments) { var stageMap = segment.stageMap; foreach (ulong id in stageMap.Keys) { Insn.Stage stage = stageMap[id]; if (stage != null) { Insn insn = GetAliveInsn(id); stage.EndRelCycle = (Int32)(m_currentCycle - insn.StartCycle); insn.AddStage(segment.SegmentID, stage); } } } foreach (var insn in m_insnMap.Values) { WriteInsnToDB(insn); } }
// loader からデータを読みだして配列を作成、MainForm::insnsに置き換え // この時AddConsumerしている private void LoadInsns() { if (loader == null) { return; } coordinateSystem.SetInsnRange(loginfo.MinInsnId, loginfo.MaxInsnId); insns = new Insn[coordinateSystem.ViewInsnCount]; dependencyRanges = new DependencyRange[coordinateSystem.ViewInsnCount]; long cycleFrom = long.MaxValue; long cycleTo = long.MinValue; ulong idFrom = coordinateSystem.IdFrom; ulong idTo = coordinateSystem.IdTo; for (ulong id = idFrom; id <= idTo; id++) { Insn insn = null; try { //insn = db.Read(id); insn = loader.GetInsnFromDB(id); } catch (ArgumentOutOfRangeException) { insn = null; } insns[id - idFrom] = insn; dependencyRanges[id - idFrom] = new DependencyRange(id, id); if (insn == null) { continue; } if (cycleFrom > insn.StartCycle) { cycleFrom = insn.StartCycle; } if (cycleTo < insn.EndCycle) { cycleTo = insn.EndCycle; } } if (cycleFrom == long.MaxValue) { cycleTo = cycleFrom = 0; } coordinateSystem.SetCycleRange(cycleFrom, cycleTo); // Extract dependencies. foreach (Insn consinsn in insns) { if (consinsn == null) { continue; } foreach (Insn.Relation r in consinsn.Producers) { Insn prodinsn = GetInsn(r.id); if (prodinsn != null) { Insn.Relation rel = new Insn.Relation(); rel.id = consinsn.Id; rel.type = r.type; prodinsn.AddConsumer(rel); // i を横切る依存関係のうち最大と最小の範囲を登録 ulong front = Math.Min(r.id, consinsn.Id); ulong back = Math.Max(r.id, consinsn.Id); for (ulong i = front; i <= back; i++) { dependencyRanges[i - idFrom].SetRange(front, back); } } } } // Extract execution stages. // Stage names including "X" are regarded as execution stages. for (int i = 0; i < loginfo.SegmentCount; ++i) { foreach (var stageName in loginfo.StageNames[i]) { if (stageName.Contains("X")) { int id = loginfo.GetStageId(i, stageName); if (id >= 0) { ExecStageInfo info; info.lane = i; info.id = id; ExecStageId.Add(info); } } } } }
private void DrawDependencyArrow(Graphics g, ulong prodid, ulong consid, int type) { Insn prodinsn = GetInsn(prodid); Insn consinsn = GetInsn(consid); if (prodinsn == null || consinsn == null) { return; } float prodBaseY = coordinateSystem.YAtInsnId(prodid) + CellMarginHeight + coordinateSystem.Cell.Height * 0.5f; float consBaseY = coordinateSystem.YAtInsnId(consid) + CellMarginHeight + coordinateSystem.Cell.Height * 0.5f; float prody = prodBaseY; float consy = consBaseY; if (type >= dependencyArrows.Count) { type = 0; } DependencyArrow arrow = dependencyArrows[type]; Brush dependencyArrowBrush = arrow.brush; Pen dependencyArrowPen = arrow.pen; if (currentViewSetting.DrawDependencyLeftCurve && DrawDependencyLeftCurve) { float prodx = coordinateSystem.XAtCycle(prodinsn.StartCycle); float consx = coordinateSystem.XAtCycle(consinsn.StartCycle); float dy = consy - prody; float left = Math.Min(prodx, consx) - coordinateSystem.Grid.Width; PointF[] pts = new PointF[4]; pts[0] = new PointF(prodx, prody); pts[1] = new PointF(left, prody); pts[2] = new PointF(left, consy); pts[3] = new PointF(consx, consy); DrawArrowhead(g, dependencyArrowBrush, pts[3], new PointF(currentViewSetting.DependencyArrowheadLength, 0), 0.8f); g.DrawBezier(dependencyArrowPen, pts[0], pts[1], pts[2], pts[3]); } if ((currentViewSetting.DrawDependencyInsideCurve && DrawDependencyInsideCurve) || (currentViewSetting.DrawDependencyInsideLine && DrawDependencyInsideLine) ) { float prodx = 0; // prodx, consyが初期化されていないと文句を言われるので…… float consx = 0; // Find an execution stage from a producer and // decide the beginning point of a dependency line. { bool found = false; int prodLane = 0; float prodLaneY = prodBaseY; foreach (var segment in prodinsn.StageSegments) { if (prodLane != 0 && config.DrawInSeparateLane[prodLane]) { prodLaneY += coordinateSystem.Cell.Height; prody = prodLaneY; } else { prody = prodBaseY; } List <Insn.Stage> prodStages = segment; // 0 is a normal stage segment. for (int i = prodStages.Count - 1; i >= 0; i--) { Insn.Stage stage = prodStages[i]; if (IsExecStageId(prodLane, stage.Id)) { prodx = coordinateSystem.XAtCycle(prodinsn.StartCycle + stage.EndRelCycle) - coordinateSystem.Grid.Width * 0.2f; if (stage.Length == 0) { prodx += coordinateSystem.Grid.Width; } found = true; break; } } if (found) { break; } prodLane++; } if (!found) { return; } } // Find an execution stage from a consumer. // decide the end point of a dependency line. { bool found = false; int consLane = 0; float consLaneY = consBaseY; foreach (var segment in consinsn.StageSegments) { if (consLane != 0 && config.DrawInSeparateLane[consLane]) { consLaneY += coordinateSystem.Cell.Height; consy = consLaneY; } else { consy = consBaseY; } List <Insn.Stage> consStages = segment; for (int i = consStages.Count - 1; i >= 0; i--) { Insn.Stage stage = consStages[i]; if (IsExecStageId(consLane, stage.Id)) { consx = coordinateSystem.XAtCycle(consinsn.StartCycle + stage.BeginRelCycle) + coordinateSystem.Grid.Width * 0.2f; found = true; break; } } if (found) { break; } consLane++; } if (!found) { return; } } // Draw a dependency line. if (currentViewSetting.DrawDependencyInsideCurve && DrawDependencyInsideCurve) { float xDiff = (consx - prodx) * 0.6f; float yDiff = 0; { PointF[] pts = new PointF[4]; pts[0] = new PointF(prodx, prody); pts[1] = new PointF(prodx + xDiff, prody + yDiff); pts[2] = new PointF(consx - xDiff, consy - yDiff); pts[3] = new PointF(consx, consy); g.DrawBezier(dependencyArrowPen, pts[0], pts[1], pts[2], pts[3]); } // Draw a dependency arrow head. { PointF arrowVector = new PointF( (consx - prodx) * 3, consy - prody ); float norm = (float)Math.Sqrt(arrowVector.X * arrowVector.X + arrowVector.Y * arrowVector.Y); float f = currentViewSetting.DependencyArrowheadLength / norm; arrowVector.X *= f; arrowVector.Y *= f; DrawArrowhead( g, dependencyArrowBrush, new PointF(consx, consy), arrowVector, 0.8f ); } } if (currentViewSetting.DrawDependencyInsideLine && DrawDependencyInsideLine) { g.DrawLine(dependencyArrowPen, prodx, prody, consx, consy); PointF v = new PointF(consx - prodx, consy - prody); float norm = (float)Math.Sqrt(v.X * v.X + v.Y * v.Y); float f = currentViewSetting.DependencyArrowheadLength / norm; v.X *= f; v.Y *= f; DrawArrowhead(g, dependencyArrowBrush, new PointF(consx, consy), v, 0.8f); } } }
// メインビューの描画 private void DrawMainView(Graphics g, Rectangle rect) { // Results of FillRectangle may be corrupt in an AntiAlias mode, // thus set a None mode for drawing a background and stages. g.SmoothingMode = SmoothingMode.None; DrawMainViewBackGround(g, rect); // Resume g.SmoothingMode = SmoothingMode.AntiAlias; if (!loaded) { return; } // 命令の描画 if (ZoomedOut) { // ズームアウト時 // 枠線のみ描画 for (int y = rect.Top; y <= rect.Bottom; y++) { ulong viewidfrom = coordinateSystem.InsnIdAtY(y); ulong viewidto = coordinateSystem.InsnIdAtY(y + 1); if (viewidto != coordinateSystem.IdTo) { viewidto -= 1; } long mincycle = long.MaxValue; long maxcycle = long.MinValue; bool insnpresent = false; for (ulong id = viewidfrom; id <= viewidto; id++) { Insn insn = GetInsn(id); if (insn == null) { continue; } mincycle = Math.Min(mincycle, insn.StartCycle); maxcycle = Math.Max(maxcycle, insn.EndCycle); insnpresent = true; } if (insnpresent) { int x1 = coordinateSystem.XAtCycle(mincycle); int x2 = coordinateSystem.XAtCycle(maxcycle); Pen pen; if (config.ColorScheme == ColorScheme.Default) { pen = Pens.DimGray; } else if (config.ColorScheme == ColorScheme.Blue) { pen = Pens.Cyan; } else { pen = Pens.Salmon; } g.DrawLine(pen, x1, y, x2, y); } if (viewidto == coordinateSystem.IdTo) { break; } } long cycle = coordinateSystem.CycleAtX(rect.Left); } else { // 最大ズーム時 long cycle = coordinateSystem.CycleAtX(rect.Left); ulong viewIDFrom = coordinateSystem.InsnIdAtY(rect.Top); ulong viewIDTo = coordinateSystem.InsnIdAtY(rect.Bottom); for (ulong id = viewIDFrom; id <= viewIDTo; id++) { Insn insn = GetInsn(id); if (insn != null) { DrawInsn(g, insn); } } // depViewIDFrom から depViewIDTo の間にある命令の依存関係のみが,更新領域に関わる. // depViewIDFrom:viewIDFrom の命令を横切る依存関係のうち,もっとも上(ID が小さい)命令 // depViewIDTo :viewIDTo の命令を横切る依存関係のうち,もっとも下(ID が大きい)命令 ulong depViewIDFrom = GetDependencyRange(viewIDFrom).GetFront(); ulong depViewIDTo = GetDependencyRange(viewIDTo).GetBack(); DrawDependency( g, depViewIDFrom, depViewIDTo, viewIDFrom, viewIDTo ); } }
private void panelMainView_MouseMove(object sender, MouseEventArgs e) { Point mousePos = new Point(e.X, e.Y); if (lastMousePos == mousePos) { return; } lastMousePos = mousePos; if (panelDragging) { Point p = panelMainView.ScrollPosition; p.Y = p.Y - (e.Y - leftMouseDownPos.Y); p.X = p.X - (e.X - leftMouseDownPos.X); panelMainView.ScrollPosition = p; // Debug.WriteLine(string.Format("({0}, {1})", e.X - lastMousePos.X, e.Y - lastMousePos.Y)); } else { long cycle = coordinateSystem.CycleAtX(e.X) - coordinateSystem.CycleFrom; ulong id = coordinateSystem.InsnIdAtY(e.Y) - coordinateSystem.IdFrom; if (!IsVisibleInsnId(id)) { toolTip.SetToolTip(panelMainView, ""); return; } // マウスオーバー位置のInsnのステージを表示する string stageName = ""; string stageComment = ""; Insn insn = GetInsn(id); if (insn != null) { for (int segmentID = 0; segmentID < insn.StageSegments.Count; segmentID++) { List <Insn.Stage> stages = insn.StageSegments[segmentID]; for (int i = 0; i < stages.Count; i++) { Insn.Stage stage = stages[i]; long beginCycle = insn.StartCycle + stage.BeginRelCycle - coordinateSystem.CycleFrom; long length = (int)stage.Length; if ((beginCycle <= cycle && cycle < beginCycle + length) || (beginCycle == cycle && length == 0)) { if (stageName.Length != 0) { stageName += ", "; } stageName += loginfo.StageNames[segmentID][stage.Id] + "[" + length + "]"; if (stage.Comment != null) { stageComment += stage.Comment; } } } } string tipStr = string.Format("(+{0},+{1}) {2}\n{3}", cycle, id, stageName, stageComment); toolTip.SetToolTip(panelMainView, tipStr); } } }
//命令一つ分の描画 private void DrawInsn(Graphics g, Insn insn) { int bufferWidth = (int)(insn.EndCycle - insn.StartCycle) * (int)coordinateSystem.Grid.Width; int bufferHeight = (int)coordinateSystem.Grid.Height - CellMarginHeight * 2; Rectangle rect = new Rectangle(0, 0, bufferWidth, bufferHeight); bool drawOffscreen = false; if (drawOffscreen) { // Graphics::TranslateTransform() がバグっており,2048命令以上の部分でグラデーションがおかしくなるので, // オフスクリーンに一度描いたあと転送する if (drawStageBMP.Height < bufferHeight + 16 || drawStageBMP.Width < bufferWidth + 16 ) { drawStageBMP = new Bitmap( Math.Max(drawStageBMP.Width, bufferWidth + 16), Math.Max(drawStageBMP.Height, bufferHeight + 16), g ); } } Graphics renderTarget = drawOffscreen ? Graphics.FromImage(drawStageBMP) : g; int baseY = drawOffscreen ? 0 : coordinateSystem.YAtInsnId(insn.Id) + CellMarginHeight; int baseX = drawOffscreen ? 0 : coordinateSystem.XAtCycle(insn.StartCycle); int segmentY = 0; Font stageFont = StageFont; for (int segmentID = 0; segmentID < insn.StageSegments.Count; segmentID++) { var stages = insn.StageSegments[segmentID]; var nameMap = loginfo.StageNames[segmentID]; int y = baseY; if (segmentID != 0 && config.DrawInSeparateLane[segmentID]) { segmentY += (int)coordinateSystem.Cell.Height; y += segmentY; } foreach (var stage in stages) { int x = stage.BeginRelCycle * (int)coordinateSystem.Grid.Width + baseX; int length = (int)stage.Length; string stageName = nameMap[stage.Id]; DrawStage(renderTarget, stage.Id, segmentID, x, y, length, stageName, insn.Flushed); } } if (drawOffscreen) { int dstY = coordinateSystem.YAtInsnId(insn.Id) + CellMarginHeight; int dstX = coordinateSystem.XAtCycle(insn.StartCycle); if (currentViewSetting.DrawOutline) { // DrawRectangle has a bug that draws a rectangle that is 1-pixel larger than specified size. rect.Inflate(1, 1); } g.DrawImage(drawStageBMP, dstX, dstY, rect, GraphicsUnit.Pixel); renderTarget.Dispose(); } }