public void AddDebugMessages(FetchDrawcall[] drawcalls) { foreach (var draw in drawcalls) { if (draw.context != m_Core.FrameInfo[m_Core.CurFrame].immContextId) continue; if(draw.children.Length > 0) AddDebugMessages(draw.children); if (draw.debugMessages != null) { foreach (var msg in draw.debugMessages) { int i = m_Messages.Count; m_VisibleMessages.Add(i); m_Messages.Add(new DebugMessage(i, draw.eventID, msg)); } } } }
// used to determine if two drawcalls can be considered in the same 'pass', // ie. writing to similar targets, same type of call, etc. // // When a log has no markers, this is used to group up drawcalls into fake markers private bool PassEquivalent(FetchDrawcall a, FetchDrawcall b) { // executing command lists can have children if(a.children.Length > 0 || b.children.Length > 0) return false; // don't group draws and compute executes if ((a.flags & DrawcallFlags.Dispatch) != (b.flags & DrawcallFlags.Dispatch)) return false; // don't group present with anything if ((a.flags & DrawcallFlags.Present) != (b.flags & DrawcallFlags.Present)) return false; // don't group things run on different multithreaded contexts if(a.context != b.context) return false; // don't group things with different depth outputs if (a.depthOut != b.depthOut) return false; int numAOuts = 0, numBOuts = 0; for (int i = 0; i < 8; i++) { if (a.outputs[i] != ResourceId.Null) numAOuts++; if (b.outputs[i] != ResourceId.Null) numBOuts++; } int numSame = 0; if (a.depthOut != ResourceId.Null) { numAOuts++; numBOuts++; numSame++; } for (int i = 0; i < 8; i++) { if (a.outputs[i] != ResourceId.Null) { for (int j = 0; j < 8; j++) { if (a.outputs[i] == b.outputs[j]) { numSame++; break; } } } else if (b.outputs[i] != ResourceId.Null) { for (int j = 0; j < 8; j++) { if (a.outputs[j] == b.outputs[i]) { numSame++; break; } } } } // use a kind of heuristic to group together passes where the outputs are similar enough. // could be useful for example if you're rendering to a gbuffer and sometimes you render // without one target, but the draws are still batched up. if (numSame > Math.Max(numAOuts, numBOuts) / 2 && Math.Max(numAOuts, numBOuts) > 1) return true; if (numSame == Math.Max(numAOuts, numBOuts)) return true; return false; }
private TreelistView.Node AddDrawcall(FetchDrawcall drawcall, TreelistView.Node root) { if (m_Core.Config.EventBrowser_HideEmpty) { if ((drawcall.children == null || drawcall.children.Length == 0) && (drawcall.flags & DrawcallFlags.PushMarker) != 0) return null; } UInt32 eventNum = drawcall.eventID; TreelistView.Node drawNode = null; if(drawcall.children.Length > 0) drawNode = MakeNode(eventNum, GetEndEventID(drawcall), drawcall.drawcallID, drawcall.name, 0.0); else drawNode = MakeNode(eventNum, drawcall.drawcallID, drawcall.name, 0.0); if (m_Core.Config.EventBrowser_ApplyColours) { // if alpha isn't 0, assume the colour is valid if ((drawcall.flags & (DrawcallFlags.PushMarker | DrawcallFlags.SetMarker)) > 0 && drawcall.markerColour[3] > 0.0f) { float red = drawcall.markerColour[0]; float green = drawcall.markerColour[1]; float blue = drawcall.markerColour[2]; float alpha = drawcall.markerColour[3]; drawNode.TreeLineColor = drawcall.GetColor(); drawNode.TreeLineWidth = 3.0f; if (m_Core.Config.EventBrowser_ColourEventRow) { drawNode.BackColor = drawcall.GetColor(); if (drawcall.ShouldUseWhiteText()) drawNode.ForeColor = Color.White; } } } DeferredEvent def = new DeferredEvent(); def.eventID = eventNum; def.marker = (drawcall.flags & DrawcallFlags.SetMarker) != 0; if (drawcall.context != m_Core.FrameInfo.immContextId) { def.defCtx = drawcall.context; def.lastDefEv = drawcall.eventID; FetchDrawcall parent = drawcall.parent; while(!parent.name.Contains("ExecuteCommand")) parent = parent.parent; def.eventID = parent.eventID-1; def.firstDefEv = parent.children[0].eventID; if(parent.children[0].events.Length > 0) def.firstDefEv = parent.children[0].events[0].eventID; } drawNode.Tag = def; if (drawcall.children != null && drawcall.children.Length > 0) { for (int i = 0; i < drawcall.children.Length; i++) { AddDrawcall(drawcall.children[i], drawNode); if (i > 0 && drawNode.Nodes.Count >= 2 && (drawcall.children[i - 1].flags & DrawcallFlags.SetMarker) > 0) { drawNode.Nodes[drawNode.Nodes.Count - 2].Tag = drawNode.Nodes.LastNode.Tag; } } bool found = false; for (int i = drawNode.Nodes.Count - 1; i >= 0; i--) { DeferredEvent t = drawNode.Nodes[i].Tag as DeferredEvent; if (t != null && !t.marker) { drawNode.Tag = drawNode.Nodes[i].Tag; found = true; break; } } if (!found && !drawNode.Nodes.IsEmpty()) drawNode.Tag = drawNode.Nodes.LastNode.Tag; } if (drawNode.Nodes.IsEmpty() && (drawcall.flags & DrawcallFlags.PushMarker) != 0 && m_Core.Config.EventBrowser_HideEmpty) return null; root.Nodes.Add(drawNode); return drawNode; }
private void FindDraw(Point p, Section s, ref FetchDrawcall left, ref float dleft, ref bool uleft, ref FetchDrawcall right, ref float dright, ref bool uright) { if (s == null) return; var rect = s.lastRect; rect.Y = 0; rect.Height = 10000; if (s.subsections != null) { foreach (var sub in s.subsections) { FindDraw(p, sub, ref left, ref dleft, ref uleft, ref right, ref dright, ref uright); if(left != null && right != null) return; } } if (rect.Contains(p)) { if (s.draws == null || s.draws.Count == 0) return; for(int i=0; i < s.lastPoss.Count; i++) { if (s.lastVisible[i]) { if (s.lastPoss[i] <= p.X) { if ( // not found left left == null || // this left is closer and as usage-y, or we don't have a usage-y one yet (s.lastPoss[i] > dleft && s.lastUsage[i] == uleft) || // this left is WAY closer (s.lastPoss[i] > dleft + 20.0f) || // this left is more usage-y (s.lastUsage[i] && !uleft) ) { dleft = s.lastPoss[i]; uleft = s.lastUsage[i]; left = s.draws[i]; } } if (s.lastPoss[i] > p.X) { if ( // not found right right == null || // this right is closer and as usage-y, or we don't have a usage-y one yet (s.lastPoss[i] < dright && s.lastUsage[i] == uright) || // this right is WAY closer (s.lastPoss[i] < dright - 20.0f) || // this right is more usage-y (s.lastUsage[i] && !uright) ) { dright = s.lastPoss[i]; uright = s.lastUsage[i]; right = s.draws[i]; } } } } if (left != null && right != null) return; } }
private TreelistView.Node AddDrawcall(FetchDrawcall drawcall, TreelistView.Node root) { if (m_Core.Config.EventBrowser_HideEmpty) { if ((drawcall.children == null || drawcall.children.Length == 0) && (drawcall.flags & DrawcallFlags.PushMarker) != 0) return null; } UInt32 eventNum = drawcall.eventID; TreelistView.Node drawNode = MakeNode(eventNum, drawcall.drawcallID, drawcall.name, 0.0); DeferredEvent def = new DeferredEvent(); def.frameID = m_Core.CurFrame; def.eventID = eventNum; def.marker = (drawcall.flags & DrawcallFlags.SetMarker) != 0; if (drawcall.context != m_Core.FrameInfo[m_Core.CurFrame].immContextId) { def.defCtx = drawcall.context; def.lastDefEv = drawcall.eventID; FetchDrawcall parent = drawcall.parent; while(!parent.name.Contains("ExecuteCommand")) parent = parent.parent; def.eventID = parent.eventID-1; def.firstDefEv = parent.children[0].eventID; if(parent.children[0].events.Length > 0) def.firstDefEv = parent.children[0].events[0].eventID; } drawNode.Tag = def; if (drawcall.children != null && drawcall.children.Length > 0) { for (int i = 0; i < drawcall.children.Length; i++) { AddDrawcall(drawcall.children[i], drawNode); if (i > 0 && drawNode.Nodes.Count >= 2 && (drawcall.children[i - 1].flags & DrawcallFlags.SetMarker) > 0) { drawNode.Nodes[drawNode.Nodes.Count - 2].Tag = drawNode.Nodes.LastNode.Tag; } } bool found = false; for (int i = drawNode.Nodes.Count - 1; i >= 0; i--) { DeferredEvent t = drawNode.Nodes[i].Tag as DeferredEvent; if (t != null && !t.marker) { drawNode.Tag = drawNode.Nodes[i].Tag; found = true; break; } } if (!found && !drawNode.Nodes.IsEmpty()) drawNode.Tag = drawNode.Nodes.LastNode.Tag; } if (drawNode.Nodes.IsEmpty() && (drawcall.flags & DrawcallFlags.PushMarker) != 0 && m_Core.Config.EventBrowser_HideEmpty) return null; root.Nodes.Add(drawNode); return drawNode; }
private string GetExportDrawcallString(int indent, bool firstchild, FetchDrawcall drawcall) { string prefix = new string(' ', indent * 2 - (firstchild ? 1 : 0)); if(firstchild) prefix += '\\'; return String.Format("{0}- {1}", prefix, drawcall.name); }
private double GetDrawTime(FetchDrawcall drawcall) { if (drawcall.children.Length > 0) { double total = 0.0; foreach (FetchDrawcall c in drawcall.children) { double f = GetDrawTime(c); if(f >= 0) total += f; } return total; } else if (m_Times.ContainsKey(drawcall.eventID)) { return m_Times[drawcall.eventID][0].value.d; } return -1.0; }
private TreelistView.Node AddDrawcall(FetchDrawcall drawcall, TreelistView.Node root) { if (m_Core.Config.EventBrowser_HideEmpty) { if ((drawcall.children == null || drawcall.children.Length == 0) && (drawcall.flags & DrawcallFlags.PushMarker) != 0) return null; } UInt32 eventNum = drawcall.eventID; TreelistView.Node drawNode = null; if(drawcall.children.Length > 0) drawNode = MakeNode(eventNum, GetEndEventID(drawcall), drawcall.drawcallID, GetEndDrawID(drawcall), drawcall.name, 0.0); else drawNode = MakeNode(eventNum, drawcall.drawcallID, drawcall.name, 0.0); if (m_Core.Config.EventBrowser_ApplyColours) { // if alpha isn't 0, assume the colour is valid if ((drawcall.flags & (DrawcallFlags.PushMarker | DrawcallFlags.SetMarker)) > 0 && drawcall.markerColour[3] > 0.0f) { float red = drawcall.markerColour[0]; float green = drawcall.markerColour[1]; float blue = drawcall.markerColour[2]; float alpha = drawcall.markerColour[3]; drawNode.TreeLineColor = drawcall.GetColor(); drawNode.TreeLineWidth = 3.0f; if (m_Core.Config.EventBrowser_ColourEventRow) { drawNode.BackColor = drawcall.GetColor(); drawNode.ForeColor = drawcall.GetTextColor(eventView.ForeColor); } } } DeferredEvent def = new DeferredEvent(); def.eventID = eventNum; def.marker = (drawcall.flags & DrawcallFlags.SetMarker) != 0; drawNode.Tag = def; if (drawcall.children != null && drawcall.children.Length > 0) { for (int i = 0; i < drawcall.children.Length; i++) { AddDrawcall(drawcall.children[i], drawNode); if (i > 0 && drawNode.Nodes.Count >= 2 && (drawcall.children[i - 1].flags & DrawcallFlags.SetMarker) > 0) { DeferredEvent markerTag = drawNode.Nodes[drawNode.Nodes.Count - 2].Tag as DeferredEvent; DeferredEvent drawTag = drawNode.Nodes.LastNode.Tag as DeferredEvent; markerTag.eventID = drawTag.eventID; } } bool found = false; for (int i = drawNode.Nodes.Count - 1; i >= 0; i--) { DeferredEvent t = drawNode.Nodes[i].Tag as DeferredEvent; if (t != null && !t.marker) { drawNode.Tag = drawNode.Nodes[i].Tag; found = true; break; } } if (!found && !drawNode.Nodes.IsEmpty()) drawNode.Tag = drawNode.Nodes.LastNode.Tag; } if (drawNode.Nodes.IsEmpty() && (drawcall.flags & DrawcallFlags.PushMarker) != 0 && m_Core.Config.EventBrowser_HideEmpty) return null; root.Nodes.Add(drawNode); return drawNode; }
private void RemoveMarkerColors(FetchDrawcall[] draws) { for (int i = 0; i < draws.Length; i++) { draws[i].markerColour[0] = 0.0f; draws[i].markerColour[1] = 0.0f; draws[i].markerColour[2] = 0.0f; draws[i].markerColour[3] = 0.0f; RemoveMarkerColors(draws[i].children); } }
// because some engines (*cough*unreal*cough*) provide a valid marker colour of // opaque black for every marker, instead of transparent black (i.e. just 0) we // want to check for that case and remove the colors, instead of displaying all // the markers as black which is not what's intended. // // Valid marker colors = has at least one color somewhere that isn't (0.0, 0.0, 0.0, 1.0) // or (0.0, 0.0, 0.0, 0.0) // // This will fail if no marker colors are set anyway, but then removing them is // harmless. private bool HasValidMarkerColors(FetchDrawcall[] draws) { if (draws.Length == 0) return false; foreach (var d in draws) { if (d.markerColour[0] != 0.0f || d.markerColour[1] != 0.0f || d.markerColour[2] != 0.0f || (d.markerColour[3] != 1.0f && d.markerColour[3] != 0.0f)) { return true; } if (HasValidMarkerColors(d.children)) return true; } return false; }
private void AddFrameDrawcalls(TreelistView.Node frame, FetchDrawcall[] drawcalls) { eventView.BeginUpdate(); frame["Duration"] = -1.0; DeferredEvent startEv = new DeferredEvent(); startEv.frameID = m_Core.CurFrame; startEv.eventID = 0; if(frame.Nodes.Count == 0) frame.Nodes.Add(MakeNode(0, 0, "Frame Start", -1.0)).Tag = startEv; for (int i = 0; i < drawcalls.Length; i++) { TreelistView.Node d = frame.Nodes.Count > (i + 1) ? frame.Nodes[i + 1] : null; TreelistView.Node newD = AddDrawcall(d, drawcalls[i], frame); if (newD != null) { d = newD; if ((double)d["Duration"] > 0.0) frame["Duration"] = Math.Max(0.0, (double)frame["Duration"]) + (double)d["Duration"]; } } frame.Tag = frame.Nodes.LastNode.Tag; eventView.EndUpdate(); }
private TreelistView.Node AddDrawcall(TreelistView.Node existing, FetchDrawcall drawcall, TreelistView.Node root) { if (m_Core.Config.EventBrowser_HideEmpty) { if ((drawcall.children == null || drawcall.children.Length == 0) && (drawcall.flags & DrawcallFlags.PushMarker) != 0) return null; } UInt32 eventNum = drawcall.eventID; double duration = drawcall.duration; TreelistView.Node drawNode = MakeNode(eventNum, drawcall.drawcallID, drawcall.name, duration); if (existing != null) { existing.SetData(drawNode.GetData()); drawNode = existing; } else { root.Nodes.Add(drawNode); } DeferredEvent def = new DeferredEvent(); def.frameID = m_Core.CurFrame; def.eventID = eventNum; if (drawcall.context != m_Core.FrameInfo[m_Core.CurFrame].immContextId) { def.defCtx = drawcall.context; def.lastDefEv = drawcall.eventID; FetchDrawcall parent = drawcall.parent; while(!parent.name.Contains("ExecuteCommand")) parent = parent.parent; def.eventID = parent.eventID-1; def.firstDefEv = parent.children[0].eventID; if(parent.children[0].events.Length > 0) def.firstDefEv = parent.children[0].events[0].eventID; } drawNode.Tag = def; if (drawcall.children != null && drawcall.children.Length > 0) { for (int i = 0; i < drawcall.children.Length; i++) { TreelistView.Node d = drawNode.Nodes.Count > i ? drawNode.Nodes[i] : null; AddDrawcall(d, drawcall.children[i], drawNode); if (i > 0 && (drawcall.children[i-1].flags & DrawcallFlags.SetMarker) > 0) { drawNode.Nodes[drawNode.Nodes.Count - 2].Tag = drawNode.Nodes.LastNode.Tag; } if ((double)drawNode.Nodes[i]["Duration"] > 0.0) drawNode["Duration"] = Math.Max(0.0, (double)drawNode["Duration"]) + (double)drawNode.Nodes[i]["Duration"]; } drawNode.Tag = drawNode.Nodes.LastNode.Tag; } return drawNode; }
private void PopulateDraws(ref Dictionary<Int64, FetchDrawcall> map, FetchDrawcall[] draws) { if (draws.Length == 0) return; foreach (var d in draws) { map.Add((Int64)d.eventID, d); PopulateDraws(ref map, d.children); } }
private void FixupDraws(Dictionary<Int64, FetchDrawcall> map, FetchDrawcall[] draws) { if (draws.Length == 0) return; foreach (var d in draws) { if (d.previousDrawcall != 0 && map.ContainsKey(d.previousDrawcall)) d.previous = map[d.previousDrawcall]; if (d.nextDrawcall != 0 && map.ContainsKey(d.nextDrawcall)) d.next = map[d.nextDrawcall]; if (d.parentDrawcall != 0 && map.ContainsKey(d.parentDrawcall)) d.parent = map[d.parentDrawcall]; FixupDraws(map, d.children); } }
private void CountContributingEvents(FetchDrawcall draw, ref uint drawCount, ref uint dispatchCount, ref uint diagnosticCount) { const uint diagnosticMask = (uint)DrawcallFlags.SetMarker | (uint)DrawcallFlags.PushMarker | (uint)DrawcallFlags.PopMarker; uint diagnosticMasked = (uint)draw.flags & diagnosticMask; if (diagnosticMasked != 0) diagnosticCount += 1; if ((draw.flags & DrawcallFlags.Drawcall) != 0) drawCount += 1; if ((draw.flags & DrawcallFlags.Dispatch) != 0) dispatchCount += 1; if (draw.children != null) { foreach (var c in draw.children) CountContributingEvents(c, ref drawCount, ref dispatchCount, ref diagnosticCount); } }
private void CountDrawsDispatches(FetchDrawcall draw, ref int numDraws, ref int numDispatches) { if ((draw.flags & DrawcallFlags.Drawcall) != 0) { numDraws++; } if ((draw.flags & DrawcallFlags.Dispatch) != 0) { numDraws++; numDispatches++; } if(draw.children != null) { foreach (var d in draw.children) CountDrawsDispatches(d, ref numDraws, ref numDispatches); } }
// used for the mesh view, to get the format of the mesh input from whichever stage that // we're looking at private Input GetCurrentMeshInput(FetchDrawcall draw, MeshDataStage type) { if (!MeshView) return null; FormatElement[] f = null; Input ret = new Input(); ret.Drawcall = draw; ret.Topology = m_Core.CurPipelineState.DrawTopology; if (type != MeshDataStage.VSIn) { ShaderReflection details = null; if (type == MeshDataStage.VSOut) details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Vertex); else if (type == MeshDataStage.GSOut) { details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Geometry); if (details == null) details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Domain); } if (details == null) return null; f = new FormatElement[details.OutputSig.Length]; uint offset = 0; for (int i = 0; i < details.OutputSig.Length; i++) { var sig = details.OutputSig[i]; f[i] = new FormatElement(); f[i].buffer = 0; f[i].name = details.OutputSig[i].varName != "" ? details.OutputSig[i].varName : details.OutputSig[i].semanticIdxName; f[i].format.compByteWidth = sizeof(float); f[i].format.compCount = sig.compCount; f[i].format.compType = sig.compType; f[i].format.special = false; f[i].format.rawType = 0; f[i].offset = offset; f[i].perinstance = false; f[i].rowmajor = false; f[i].matrixdim = 1; offset += details.OutputSig[i].compCount * sizeof(float); } ret.BufferFormats = f; ret.Strides = new uint[] { offset }; ret.Offsets = new uint[] { 0 }; ret.Buffers = null; ret.IndexBuffer = ResourceId.Null; return ret; } CommonPipelineState.VBuffer[] vbs = m_Core.CurPipelineState.GetVBuffers(); ResourceId[] bs = new ResourceId[vbs.Length]; uint[] s = new uint[vbs.Length]; uint[] o = new uint[vbs.Length]; for (int i = 0; i < vbs.Length; i++) { bs[i] = vbs[i].Buffer; s[i] = vbs[i].ByteStride; o[i] = vbs[i].ByteOffset; } { var vinputs = m_Core.CurPipelineState.GetVertexInputs(); f = new FormatElement[vinputs.Length]; int i = 0; foreach (var a in vinputs) { f[i] = new FormatElement(a.Name, a.VertexBuffer, a.RelativeByteOffset, a.PerInstance, false, // row major matrix 1, // matrix dimension a.Format); i++; } } ResourceId ibuffer = ResourceId.Null; uint ioffset = 0; ResourceFormat ifmt = null; m_Core.CurPipelineState.GetIBuffer(out ibuffer, out ioffset, out ifmt); if (draw != null && (draw.flags & DrawcallFlags.UseIBuffer) == 0) { ibuffer = ResourceId.Null; ioffset = 0; } ret.BufferFormats = f; ret.Strides = s; ret.Offsets = o; ret.Buffers = bs; ret.IndexFormat = new FormatElement("", 0, 0, false, false, 1, ifmt); ret.IndexBuffer = ibuffer; ret.IndexOffset = ioffset; return ret; }
private void ExportDrawcall(StreamWriter sw, int maxNameLength, int indent, bool firstchild, FetchDrawcall drawcall) { string eidString = drawcall.children.Length > 0 ? "" : drawcall.eventID.ToString(); string nameString = GetExportDrawcallString(indent, firstchild, drawcall); string line = String.Format("{0,-5} | {1,-" + maxNameLength + "} | {2,-6}", eidString, nameString, drawcall.drawcallID); if (m_Times.Count > 0) { if (m_Core.Config.EventBrowser_TimeUnit != m_TimeUnit) UpdateDurationColumn(); double f = GetDrawTime(drawcall); if (f >= 0) { if (m_Core.Config.EventBrowser_TimeUnit == PersistantConfig.TimeUnit.Milliseconds) f *= 1000.0; else if (m_Core.Config.EventBrowser_TimeUnit == PersistantConfig.TimeUnit.Microseconds) f *= 1000000.0; else if (m_Core.Config.EventBrowser_TimeUnit == PersistantConfig.TimeUnit.Nanoseconds) f *= 1000000000.0; line += String.Format(" | {0}", Formatter.Format(f)); } else { line += " |"; } } sw.WriteLine(line); for (int i = 0; i < drawcall.children.Length; i++) ExportDrawcall(sw, maxNameLength, indent + 1, i == 0, drawcall.children[i]); }
// used for the mesh view, to get the format of the mesh input from whichever stage that // we're looking at private Input GetCurrentMeshInput(FetchDrawcall draw, MeshDataStage type) { if (!MeshView) return null; Input ret = new Input(); ret.Drawcall = draw; ret.Topology = draw.topology; ResourceId ibuffer = ResourceId.Null; ulong ioffset = 0; m_Core.CurPipelineState.GetIBuffer(out ibuffer, out ioffset); if (draw != null && (draw.flags & DrawcallFlags.UseIBuffer) == 0) { ibuffer = ResourceId.Null; ioffset = 0; } ret.IndexBuffer = ibuffer; ret.IndexOffset = ioffset; ret.IndexRestart = m_Core.CurPipelineState.IsStripRestartEnabled(); ret.IndexRestartValue = m_Core.CurPipelineState.GetStripRestartIndex(draw != null ? draw.indexByteWidth : 0); if (type != MeshDataStage.VSIn) { ShaderReflection details = null; if (type == MeshDataStage.VSOut) details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Vertex); else if (type == MeshDataStage.GSOut) { details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Geometry); if (details == null) details = m_Core.CurPipelineState.GetShaderReflection(ShaderStageType.Domain); } if (details == null) return null; List<FormatElement> f = new List<FormatElement>(); int posidx = -1; for (int i = 0; i < details.OutputSig.Length; i++) { var sig = details.OutputSig[i]; f.Add(new FormatElement()); f[i].buffer = 0; f[i].name = details.OutputSig[i].varName.Length > 0 ? details.OutputSig[i].varName : details.OutputSig[i].semanticIdxName; f[i].format.compByteWidth = sizeof(float); f[i].format.compCount = sig.compCount; f[i].format.compType = sig.compType; f[i].format.special = false; f[i].format.rawType = 0; f[i].perinstance = false; f[i].instancerate = 1; f[i].rowmajor = false; f[i].matrixdim = 1; f[i].systemValue = sig.systemValue; if(f[i].systemValue == SystemAttribute.Position) posidx = i; } // shift position attribute up to first, keeping order otherwise // the same if (posidx > 0) { FormatElement pos = f[posidx]; f.RemoveAt(posidx); f.Insert(0, pos); } uint offset = 0; for (int i = 0; i < details.OutputSig.Length; i++) { uint numComps = f[i].format.compCount; uint elemSize = f[i].format.compType == FormatComponentType.Double ? 8U : 4U; if (m_Core.CurPipelineState.HasAlignedPostVSData) { if (numComps == 2) offset = offset.AlignUp(2U * elemSize); else if (numComps > 2) offset = offset.AlignUp(4U * elemSize); } f[i].offset = offset; offset += numComps * elemSize; } ret.BufferFormats = f.ToArray(); ret.Strides = new uint[] { offset }; ret.Offsets = new ulong[] { 0 }; ret.Buffers = null; return ret; } BoundVBuffer[] vbs = m_Core.CurPipelineState.GetVBuffers(); ResourceId[] bs = new ResourceId[vbs.Length]; uint[] s = new uint[vbs.Length]; ulong[] o = new ulong[vbs.Length]; for (int i = 0; i < vbs.Length; i++) { bs[i] = vbs[i].Buffer; s[i] = vbs[i].ByteStride; o[i] = vbs[i].ByteOffset; } { FormatElement[] f = null; var vinputs = m_Core.CurPipelineState.GetVertexInputs(); f = new FormatElement[vinputs.Length]; ret.GenericValues = new object[vinputs.Length][]; int numinputs = vinputs.Length; int i = 0; foreach (var a in vinputs) { if (!a.Used) { numinputs--; Array.Resize(ref f, numinputs); Array.Resize(ref ret.GenericValues, numinputs); continue; } f[i] = new FormatElement(a.Name, a.VertexBuffer, a.RelativeByteOffset, a.PerInstance, a.InstanceRate, false, // row major matrix 1, // matrix dimension a.Format, false); ret.GenericValues[i] = a.GenericValue; i++; } ret.BufferFormats = f; ret.Strides = s; ret.Offsets = o; ret.Buffers = bs; } return ret; }
private uint GetEndEventID(FetchDrawcall drawcall) { if (drawcall.children.Length == 0) return drawcall.eventID; return GetEndEventID(drawcall.children.Last()); }
private void ExportDrawcall(StreamWriter sw, int maxNameLength, int indent, bool firstchild, FetchDrawcall drawcall) { string eidString = drawcall.children.Length > 0 ? "" : drawcall.eventID.ToString(); string nameString = GetExportDrawcallString(indent, firstchild, drawcall); sw.WriteLine(String.Format("{0,-5} | {1,-" + maxNameLength + "} | {2,-5}", eidString, nameString, drawcall.drawcallID)); for (int i = 0; i < drawcall.children.Length; i++) ExportDrawcall(sw, maxNameLength, indent + 1, i == 0, drawcall.children[i]); }
private void GetMaxNameLength(ref int maxNameLength, int indent, bool firstchild, FetchDrawcall drawcall) { string nameString = GetExportDrawcallString(indent, firstchild, drawcall); maxNameLength = Math.Max(maxNameLength, nameString.Length); for (int i = 0; i < drawcall.children.Length; i++) GetMaxNameLength(ref maxNameLength, indent + 1, i == 0, drawcall.children[i]); }
private bool ContainsMarker(FetchDrawcall[] draws) { bool ret = false; foreach (var d in draws) { ret |= (d.flags & (DrawcallFlags.PushMarker | DrawcallFlags.SetMarker)) > 0 && (d.flags & DrawcallFlags.CmdList) == 0; ret |= ContainsMarker(d.children); } return ret; }
private void AddFrameDrawcalls(TreelistView.Node frame, FetchDrawcall[] drawcalls) { eventView.BeginUpdate(); frame["Duration"] = -1.0; DeferredEvent startEv = new DeferredEvent(); startEv.frameID = m_Core.CurFrame; startEv.eventID = 0; frame.Nodes.Clear(); frame.Nodes.Add(MakeNode(0, 0, "Frame Start", -1.0)).Tag = startEv; for (int i = 0; i < drawcalls.Length; i++) AddDrawcall(drawcalls[i], frame); frame.Tag = frame.Nodes.LastNode.Tag; eventView.EndUpdate(); }
// if a log doesn't contain any markers specified at all by the user, then we can // fake some up by determining batches of draws that are similar and giving them a // pass number private FetchDrawcall[] FakeProfileMarkers(int frameID, FetchDrawcall[] draws) { if (ContainsMarker(draws)) return draws; var ret = new List<FetchDrawcall>(); int depthpassID = 1; int computepassID = 1; int passID = 1; int start = 0; int counter = 1; for (int i = 1; i < draws.Length; i++) { if (PassEquivalent(draws[i], draws[start])) continue; int end = i-1; if (end - start < 2 || draws[i].children.Length > 0 || draws[start].children.Length > 0 || draws[i].context != m_FrameInfo[frameID].immContextId || draws[start].context != m_FrameInfo[frameID].immContextId) { for (int j = start; j <= end; j++) { ret.Add(draws[j]); counter++; } start = i; continue; } int minOutCount = 100; int maxOutCount = 0; for (int j = start; j <= end; j++) { int outCount = 0; foreach (var o in draws[j].outputs) if (o != ResourceId.Null) outCount++; minOutCount = Math.Min(minOutCount, outCount); maxOutCount = Math.Max(maxOutCount, outCount); } FetchDrawcall mark = new FetchDrawcall(); mark.eventID = draws[end].eventID; mark.drawcallID = draws[end].drawcallID; mark.context = draws[end].context; mark.flags = DrawcallFlags.PushMarker; mark.outputs = draws[end].outputs; mark.depthOut = draws[end].depthOut; mark.name = "Guessed Pass"; if((draws[end].flags & DrawcallFlags.Dispatch) != 0) mark.name = String.Format("Compute Pass #{0}", computepassID++); else if (maxOutCount == 0) mark.name = String.Format("Depth-only Pass #{0}", depthpassID++); else if(minOutCount == maxOutCount) mark.name = String.Format("Colour Pass #{0} ({1} Targets{2})", passID++, minOutCount, draws[end].depthOut == ResourceId.Null ? "" : " + Depth"); else mark.name = String.Format("Colour Pass #{0} ({1}-{2} Targets{3})", passID++, minOutCount, maxOutCount, draws[end].depthOut == ResourceId.Null ? "" : " + Depth"); mark.children = new FetchDrawcall[end - start + 1]; for (int j = start; j <= end; j++) { mark.children[j - start] = draws[j]; draws[j].parent = mark; } ret.Add(mark); start = i; counter++; } if (start < draws.Length) ret.Add(draws[start]); return ret.ToArray(); }
private Section GatherEvents(FetchDrawcall[] draws) { var sections = new List<List<FetchDrawcall>>(); foreach (var d in draws) { if ((d.flags & (DrawcallFlags.SetMarker | DrawcallFlags.Present)) > 0) continue; if (m_Core.Config.EventBrowser_HideEmpty) { if ((d.children == null || d.children.Length == 0) && (d.flags & (DrawcallFlags.PushMarker | DrawcallFlags.MultiDraw)) != 0) continue; } bool newSection = ((d.flags & (DrawcallFlags.PushMarker|DrawcallFlags.MultiDraw)) > 0 || sections.Count == 0); if (!newSection) { var lastSection = sections.Last(); if (lastSection.Count == 1 && (lastSection[0].flags & (DrawcallFlags.PushMarker | DrawcallFlags.MultiDraw)) > 0) newSection = true; } if (newSection) sections.Add(new List<FetchDrawcall>()); sections.Last().Add(d); } Section ret = new Section(); ret.subsections = new List<Section>(); foreach (var s in sections) { Section sec = null; if (s.Count == 1 && (s[0].flags & (DrawcallFlags.PushMarker | DrawcallFlags.MultiDraw)) > 0) { sec = GatherEvents(s[0].children); if (m_Core.Config.EventBrowser_ApplyColours) { sec.color = s[0].GetColor(); sec.textcolor = s[0].GetTextColor(Color.Black); } else { sec.color = Color.Transparent; sec.textcolor = Color.Black; } sec.Name = s[0].name; } else { sec = new Section(); sec.draws = s; for (int i = 0; i < sec.draws.Count; i++) { sec.lastPoss.Add(0.0f); sec.lastUsage.Add(false); sec.lastVisible.Add(false); } } ret.subsections.Add(sec); } return ret; }
private FetchDrawcall GetDrawcall(FetchDrawcall[] draws, UInt32 eventID) { foreach (var d in draws) { if (d.children != null && d.children.Length > 0) { var draw = GetDrawcall(d.children, eventID); if (draw != null) return draw; } if (d.eventID == eventID) return d; } return null; }