mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-15 11:06:54 +00:00
Change previous/next/parent IDs in DrawcallDescription to pointers
* This is a legacy holdover from the C# interop not being able to preserve pointers easily.
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import renderdoc as rd
|
||||
|
||||
# Set up a hash for storing draw information by event
|
||||
draws = {}
|
||||
|
||||
# Define a recursive function for iterating over draws
|
||||
def iterDraw(d, indent = ''):
|
||||
global draws
|
||||
@@ -10,16 +7,11 @@ def iterDraw(d, indent = ''):
|
||||
# Print this drawcall
|
||||
print('%s%d: %s' % (indent, d.eventId, d.name))
|
||||
|
||||
# Save the draw by eventId for use later
|
||||
draws[d.eventId] = d
|
||||
|
||||
# Iterate over the draw's children
|
||||
for d in d.children:
|
||||
iterDraw(d, indent + ' ')
|
||||
|
||||
def sampleCode(controller):
|
||||
global draws
|
||||
|
||||
# Iterate over all of the root drawcalls
|
||||
for d in controller.GetDrawcalls():
|
||||
iterDraw(d)
|
||||
@@ -54,9 +46,9 @@ def sampleCode(controller):
|
||||
inpass = True
|
||||
|
||||
# Advance to the next drawcall
|
||||
if not draw.next in draws:
|
||||
draw = draw.next
|
||||
if draw is None:
|
||||
break
|
||||
draw = draws[draw.next]
|
||||
|
||||
if inpass:
|
||||
print("Pass #%d contained %d draws" % (passnum, passcontents))
|
||||
@@ -82,7 +74,7 @@ def loadCapture(filename):
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
raise RuntimeError("Couldn't initialise replay: " + str(status))
|
||||
|
||||
return controller
|
||||
return cap,controller
|
||||
|
||||
if 'pyrenderdoc' in globals():
|
||||
pyrenderdoc.Replay().BlockInvoke(sampleCode)
|
||||
|
||||
@@ -5,9 +5,9 @@ In this example we will show how to iterate over drawcalls.
|
||||
|
||||
The drawcalls returned from :py:meth:`~renderdoc.ReplayController.GetDrawcalls` are draws or marker regions at the root level - with no parent marker region. There are multiple ways to iterate through the list of draws.
|
||||
|
||||
The first way illustrated in this sample is to walk the tree using :py:attr:`~renderdoc.DrawcallDescription.children`, which contains the list of child draws at any point in the tree. There is also :py:attr:`~renderdoc.DrawcallDescription.parent` which contains the index of the parent drawcall.
|
||||
The first way illustrated in this sample is to walk the tree using :py:attr:`~renderdoc.DrawcallDescription.children`, which contains the list of child draws at any point in the tree. There is also :py:attr:`~renderdoc.DrawcallDescription.parent` which points to the parent drawcall.
|
||||
|
||||
The second is to use :py:attr:`~renderdoc.DrawcallDescription.previous` and :py:attr:`~renderdoc.DrawcallDescription.next`, which contain the indices of the previous and next draw respectively in a linear fashion, regardless of nesting depth.
|
||||
The second is to use :py:attr:`~renderdoc.DrawcallDescription.previous` and :py:attr:`~renderdoc.DrawcallDescription.next`, which point to the previous and next draw respectively in a linear fashion, regardless of nesting depth.
|
||||
|
||||
In the example we use this iteration to determine the number of passes, using the drawcall flags to denote the start of each pass by a starting clear call.
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ CaptureContext::CaptureContext(QString paramFilename, QString remoteHost, uint32
|
||||
m_CurVulkanPipelineState = NULL;
|
||||
m_CurPipelineState = &m_DummyPipelineState;
|
||||
|
||||
m_Drawcalls = &m_EmptyDraws;
|
||||
|
||||
m_StructuredFile = &m_DummySDFile;
|
||||
|
||||
qApp->setApplicationVersion(QString::fromLatin1(RENDERDOC_GetVersionString()));
|
||||
@@ -193,8 +195,8 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const rdcstr &origFi
|
||||
// make sure we're on a consistent event before invoking viewer forms
|
||||
if(m_LastDrawcall)
|
||||
SetEventID(viewers, m_LastDrawcall->eventId, true);
|
||||
else if(!m_Drawcalls.empty())
|
||||
SetEventID(viewers, m_Drawcalls.back().eventId, true);
|
||||
else if(!m_Drawcalls->empty())
|
||||
SetEventID(viewers, m_Drawcalls->back().eventId, true);
|
||||
|
||||
GUIInvoke::blockcall(m_MainWindow, [&viewers]() {
|
||||
// notify all the registers viewers that a capture has been loaded
|
||||
@@ -267,21 +269,22 @@ void CaptureContext::LoadCaptureThreaded(const QString &captureFile, const QStri
|
||||
|
||||
// fetch initial data like drawcalls, textures and buffers
|
||||
m_Renderer.BlockInvoke([this](IReplayController *r) {
|
||||
if(Config().EventBrowser_AddFake)
|
||||
r->AddFakeMarkers();
|
||||
|
||||
m_FrameInfo = r->GetFrameInfo();
|
||||
|
||||
m_APIProps = r->GetAPIProperties();
|
||||
|
||||
m_PostloadProgress = 0.2f;
|
||||
|
||||
m_Drawcalls = r->GetDrawcalls();
|
||||
m_Drawcalls = &r->GetDrawcalls();
|
||||
|
||||
AddFakeProfileMarkers();
|
||||
|
||||
m_FirstDrawcall = &m_Drawcalls[0];
|
||||
m_FirstDrawcall = &m_Drawcalls->at(0);
|
||||
while(!m_FirstDrawcall->children.empty())
|
||||
m_FirstDrawcall = &m_FirstDrawcall->children[0];
|
||||
|
||||
m_LastDrawcall = &m_Drawcalls.back();
|
||||
m_LastDrawcall = &m_Drawcalls->back();
|
||||
while(!m_LastDrawcall->children.empty())
|
||||
m_LastDrawcall = &m_LastDrawcall->children.back();
|
||||
|
||||
@@ -401,220 +404,6 @@ void CaptureContext::CacheResources()
|
||||
m_Resources[res.resourceId] = &res;
|
||||
}
|
||||
|
||||
bool CaptureContext::PassEquivalent(const DrawcallDescription &a, const DrawcallDescription &b)
|
||||
{
|
||||
// executing command lists can have children
|
||||
if(!a.children.empty() || !b.children.empty())
|
||||
return false;
|
||||
|
||||
// don't group draws and compute executes
|
||||
if((a.flags & DrawFlags::Dispatch) != (b.flags & DrawFlags::Dispatch))
|
||||
return false;
|
||||
|
||||
// don't group present with anything
|
||||
if((a.flags & DrawFlags::Present) != (b.flags & DrawFlags::Present))
|
||||
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())
|
||||
numAOuts++;
|
||||
if(b.outputs[i] != ResourceId())
|
||||
numBOuts++;
|
||||
}
|
||||
|
||||
int numSame = 0;
|
||||
|
||||
if(a.depthOut != ResourceId())
|
||||
{
|
||||
numAOuts++;
|
||||
numBOuts++;
|
||||
numSame++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
if(a.outputs[i] != ResourceId())
|
||||
{
|
||||
for(int j = 0; j < 8; j++)
|
||||
{
|
||||
if(a.outputs[i] == b.outputs[j])
|
||||
{
|
||||
numSame++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(b.outputs[i] != ResourceId())
|
||||
{
|
||||
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 > qMax(numAOuts, numBOuts) / 2 && qMax(numAOuts, numBOuts) > 1)
|
||||
return true;
|
||||
|
||||
if(numSame == qMax(numAOuts, numBOuts))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CaptureContext::ContainsMarker(const rdcarray<DrawcallDescription> &draws)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
for(const DrawcallDescription &d : draws)
|
||||
{
|
||||
ret |= (d.flags & DrawFlags::PushMarker) &&
|
||||
!(d.flags & (DrawFlags::CmdList | DrawFlags::MultiDraw)) && !d.children.empty();
|
||||
ret |= ContainsMarker(d.children);
|
||||
|
||||
if(ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CaptureContext::AddFakeProfileMarkers()
|
||||
{
|
||||
rdcarray<DrawcallDescription> &draws = m_Drawcalls;
|
||||
|
||||
if(!Config().EventBrowser_AddFake)
|
||||
return;
|
||||
|
||||
if(ContainsMarker(draws))
|
||||
return;
|
||||
|
||||
QList<DrawcallDescription> ret;
|
||||
|
||||
int depthpassID = 1;
|
||||
int copypassID = 1;
|
||||
int computepassID = 1;
|
||||
int passID = 1;
|
||||
|
||||
int start = 0;
|
||||
int refdraw = 0;
|
||||
|
||||
DrawFlags drawFlags = DrawFlags::Copy | DrawFlags::Resolve | DrawFlags::SetMarker |
|
||||
DrawFlags::APICalls | DrawFlags::CmdList;
|
||||
|
||||
for(int32_t i = 1; i < draws.count(); i++)
|
||||
{
|
||||
if(draws[refdraw].flags & drawFlags)
|
||||
{
|
||||
refdraw = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(draws[i].flags & drawFlags)
|
||||
continue;
|
||||
|
||||
if(PassEquivalent(draws[i], draws[refdraw]))
|
||||
continue;
|
||||
|
||||
int end = i - 1;
|
||||
|
||||
if(end - start < 2 || !draws[i].children.empty() || !draws[refdraw].children.empty())
|
||||
{
|
||||
for(int j = start; j <= end; j++)
|
||||
ret.push_back(draws[j]);
|
||||
|
||||
start = i;
|
||||
refdraw = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
int minOutCount = 100;
|
||||
int maxOutCount = 0;
|
||||
bool copyOnly = true;
|
||||
|
||||
for(int j = start; j <= end; j++)
|
||||
{
|
||||
int outCount = 0;
|
||||
|
||||
if(!(draws[j].flags & (DrawFlags::Copy | DrawFlags::Resolve | DrawFlags::Clear)))
|
||||
copyOnly = false;
|
||||
|
||||
for(ResourceId o : draws[j].outputs)
|
||||
if(o != ResourceId())
|
||||
outCount++;
|
||||
minOutCount = qMin(minOutCount, outCount);
|
||||
maxOutCount = qMax(maxOutCount, outCount);
|
||||
}
|
||||
|
||||
DrawcallDescription mark;
|
||||
|
||||
mark.eventId = draws[start].eventId;
|
||||
mark.drawcallId = draws[start].drawcallId;
|
||||
|
||||
mark.flags = DrawFlags::PushMarker;
|
||||
memcpy(mark.outputs, draws[end].outputs, sizeof(mark.outputs));
|
||||
mark.depthOut = draws[end].depthOut;
|
||||
|
||||
mark.name = "Guessed Pass";
|
||||
|
||||
minOutCount = qMax(1, minOutCount);
|
||||
|
||||
QString targets = draws[end].depthOut == ResourceId() ? tr("Targets") : tr("Targets + Depth");
|
||||
|
||||
if(copyOnly)
|
||||
mark.name = tr("Copy/Clear Pass #%1").arg(copypassID++).toUtf8().data();
|
||||
else if(draws[refdraw].flags & DrawFlags::Dispatch)
|
||||
mark.name = tr("Compute Pass #%1").arg(computepassID++).toUtf8().data();
|
||||
else if(maxOutCount == 0)
|
||||
mark.name = tr("Depth-only Pass #%1").arg(depthpassID++).toUtf8().data();
|
||||
else if(minOutCount == maxOutCount)
|
||||
mark.name =
|
||||
tr("Colour Pass #%1 (%2 %3)").arg(passID++).arg(minOutCount).arg(targets).toUtf8().data();
|
||||
else
|
||||
mark.name = tr("Colour Pass #%1 (%2-%3 %4)")
|
||||
.arg(passID++)
|
||||
.arg(minOutCount)
|
||||
.arg(maxOutCount)
|
||||
.arg(targets)
|
||||
.toUtf8()
|
||||
.data();
|
||||
|
||||
mark.children.resize(end - start + 1);
|
||||
|
||||
for(int j = start; j <= end; j++)
|
||||
{
|
||||
mark.children[j - start] = draws[j];
|
||||
draws[j].parent = mark.eventId;
|
||||
}
|
||||
|
||||
ret.push_back(mark);
|
||||
|
||||
start = i;
|
||||
refdraw = i;
|
||||
}
|
||||
|
||||
if(start < draws.count())
|
||||
{
|
||||
for(int j = start; j < draws.count(); j++)
|
||||
ret.push_back(draws[j]);
|
||||
}
|
||||
|
||||
m_Drawcalls = ret;
|
||||
}
|
||||
|
||||
void CaptureContext::RecompressCapture()
|
||||
{
|
||||
QString destFilename = GetCaptureFilename();
|
||||
@@ -857,7 +646,7 @@ void CaptureContext::CloseCapture()
|
||||
m_Bookmarks.clear();
|
||||
m_Notes.clear();
|
||||
|
||||
m_Drawcalls.clear();
|
||||
m_Drawcalls = &m_EmptyDraws;
|
||||
m_FirstDrawcall = m_LastDrawcall = NULL;
|
||||
|
||||
m_CurD3D11PipelineState = NULL;
|
||||
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
const DrawcallDescription *GetLastDrawcall() override { return m_LastDrawcall; };
|
||||
bool OpenRGPProfile(const rdcstr &filename) override;
|
||||
IRGPInterop *GetRGPInterop() override { return m_RGP; }
|
||||
const rdcarray<DrawcallDescription> &CurDrawcalls() override { return m_Drawcalls; }
|
||||
const rdcarray<DrawcallDescription> &CurDrawcalls() override { return *m_Drawcalls; }
|
||||
ResourceDescription *GetResource(ResourceId id) override { return m_Resources[id]; }
|
||||
const rdcarray<ResourceDescription> &GetResources() override { return m_ResourceList; }
|
||||
rdcstr GetResourceName(ResourceId id) override;
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
const rdcarray<BufferDescription> &GetBuffers() override { return m_BufferList; }
|
||||
const DrawcallDescription *GetDrawcall(uint32_t eventId) override
|
||||
{
|
||||
return GetDrawcall(m_Drawcalls, eventId);
|
||||
return GetDrawcall(*m_Drawcalls, eventId);
|
||||
}
|
||||
const SDFile &GetStructuredFile() override { return *m_StructuredFile; }
|
||||
WindowingSystem CurWindowingSystem() override { return m_CurWinSystem; }
|
||||
@@ -246,10 +246,6 @@ private:
|
||||
rdcarray<DebugMessage> m_DebugMessages;
|
||||
int m_UnreadMessageCount = 0;
|
||||
|
||||
bool PassEquivalent(const DrawcallDescription &a, const DrawcallDescription &b);
|
||||
bool ContainsMarker(const rdcarray<DrawcallDescription> &m_Drawcalls);
|
||||
void AddFakeProfileMarkers();
|
||||
|
||||
void SaveChanges();
|
||||
|
||||
bool SaveRenames();
|
||||
@@ -293,12 +289,13 @@ private:
|
||||
}
|
||||
|
||||
void setupDockWindow(QWidget *shad);
|
||||
rdcarray<DrawcallDescription> m_Drawcalls;
|
||||
const rdcarray<DrawcallDescription> *m_Drawcalls;
|
||||
rdcarray<DrawcallDescription> m_EmptyDraws;
|
||||
|
||||
APIProperties m_APIProps;
|
||||
FrameDescription m_FrameInfo;
|
||||
DrawcallDescription *m_FirstDrawcall = NULL;
|
||||
DrawcallDescription *m_LastDrawcall = NULL;
|
||||
const DrawcallDescription *m_FirstDrawcall = NULL;
|
||||
const DrawcallDescription *m_LastDrawcall = NULL;
|
||||
|
||||
IRGPInterop *m_RGP = NULL;
|
||||
|
||||
|
||||
@@ -627,13 +627,13 @@ void CombineUsageEvents(ICaptureContext &ctx, const rdcarray<EventUsage> &usage,
|
||||
// last event was where we were - otherwise it's a new
|
||||
// distinct set of drawcalls and should have a separate
|
||||
// entry in the context menu
|
||||
const DrawcallDescription *prev = ctx.GetDrawcall(draw->previous);
|
||||
const DrawcallDescription *prev = draw->previous;
|
||||
|
||||
while(prev != NULL && prev->eventId > end)
|
||||
{
|
||||
if(!(prev->flags & (DrawFlags::Dispatch | DrawFlags::Drawcall | DrawFlags::CmdList)))
|
||||
{
|
||||
prev = ctx.GetDrawcall(prev->previous);
|
||||
prev = prev->previous;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -573,8 +573,8 @@ void EventBrowser::on_stepNext_clicked()
|
||||
|
||||
const DrawcallDescription *draw = m_Ctx.CurDrawcall();
|
||||
|
||||
if(draw && draw->next > 0)
|
||||
SelectEvent(draw->next);
|
||||
if(draw && draw->next)
|
||||
SelectEvent(draw->next->eventId);
|
||||
|
||||
// special case for the first 'virtual' draw at EID 0
|
||||
if(m_Ctx.CurEvent() == 0)
|
||||
@@ -588,8 +588,8 @@ void EventBrowser::on_stepPrev_clicked()
|
||||
|
||||
const DrawcallDescription *draw = m_Ctx.CurDrawcall();
|
||||
|
||||
if(draw && draw->previous > 0)
|
||||
SelectEvent(draw->previous);
|
||||
if(draw && draw->previous)
|
||||
SelectEvent(draw->previous->eventId);
|
||||
|
||||
// special case for the first 'virtual' draw at EID 0
|
||||
if(m_Ctx.CurEvent() == m_Ctx.GetFirstDrawcall()->eventId)
|
||||
|
||||
@@ -291,11 +291,11 @@ div.stage table tr td { border-right: 1px solid #AAAAAA; background-color: #EEEE
|
||||
const DrawcallDescription *draw = m_Ctx.CurDrawcall();
|
||||
|
||||
QList<const DrawcallDescription *> drawstack;
|
||||
const DrawcallDescription *parent = m_Ctx.GetDrawcall(draw->parent);
|
||||
const DrawcallDescription *parent = draw->parent;
|
||||
while(parent)
|
||||
{
|
||||
drawstack.push_front(parent);
|
||||
parent = m_Ctx.GetDrawcall(parent->parent);
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
for(const DrawcallDescription *d : drawstack)
|
||||
|
||||
@@ -199,11 +199,11 @@ public:
|
||||
|
||||
QString ret;
|
||||
QList<const DrawcallDescription *> drawstack;
|
||||
const DrawcallDescription *parent = m_Ctx.GetDrawcall(drawcall->parent);
|
||||
const DrawcallDescription *parent = drawcall->parent;
|
||||
while(parent)
|
||||
{
|
||||
drawstack.push_back(parent);
|
||||
parent = m_Ctx.GetDrawcall(parent->parent);
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
if(!drawstack.isEmpty())
|
||||
|
||||
@@ -963,9 +963,7 @@ struct DrawcallDescription
|
||||
copySource = ResourceId();
|
||||
copyDestination = ResourceId();
|
||||
|
||||
parent = 0;
|
||||
previous = 0;
|
||||
next = 0;
|
||||
parent = previous = next = NULL;
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
outputs[i] = ResourceId();
|
||||
@@ -1044,19 +1042,17 @@ operation.
|
||||
)");
|
||||
ResourceId copyDestination;
|
||||
|
||||
DOCUMENT(R"(The :data:`eventId <APIEvent.eventId>` of the parent of this drawcall, or ``0`` if there
|
||||
is no parent for this drawcall.
|
||||
DOCUMENT(R"(The parent of this drawcall, or ``None`` if there is no parent for this drawcall.
|
||||
)");
|
||||
int64_t parent;
|
||||
const DrawcallDescription *parent;
|
||||
|
||||
DOCUMENT(R"(The :data:`eventId <APIEvent.eventId>` of the previous drawcall in the frame, or ``0`` if
|
||||
this is the first drawcall in the frame.
|
||||
DOCUMENT(R"(The previous drawcall in the frame, or ``None`` if this is the first drawcall in the
|
||||
frame.
|
||||
)");
|
||||
int64_t previous;
|
||||
DOCUMENT(R"(The :data:`eventId <APIEvent.eventId>` of the next drawcall in the frame, or ``0`` if this
|
||||
is the last drawcall in the frame.
|
||||
)");
|
||||
int64_t next;
|
||||
const DrawcallDescription *previous;
|
||||
DOCUMENT(
|
||||
"The next drawcall in the frame, or ``None`` if this is the last drawcall in the frame.");
|
||||
const DrawcallDescription *next;
|
||||
|
||||
DOCUMENT(R"(A simple list of the :class:`ResourceId` ids for the color outputs, which can be used
|
||||
for very coarse bucketing of drawcalls into similar passes by their outputs.
|
||||
|
||||
@@ -939,7 +939,14 @@ See :meth:`BuildTargetShader`.
|
||||
:return: The list of root-level drawcalls in the capture.
|
||||
:rtype: ``list`` of :class:`DrawcallDescription`
|
||||
)");
|
||||
virtual rdcarray<DrawcallDescription> GetDrawcalls() = 0;
|
||||
virtual void AddFakeMarkers() = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieve the list of root-level drawcalls in the capture.
|
||||
|
||||
:return: The list of root-level drawcalls in the capture.
|
||||
:rtype: ``list`` of :class:`DrawcallDescription`
|
||||
)");
|
||||
virtual const rdcarray<DrawcallDescription> &GetDrawcalls() = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieve the values of a specified set of counters.
|
||||
|
||||
|
||||
@@ -381,6 +381,13 @@ FrameRecord ReplayProxy::Proxied_GetFrameRecord(ParamSerialiser ¶mser, Retur
|
||||
|
||||
SERIALISE_RETURN(ret);
|
||||
|
||||
if(paramser.IsWriting())
|
||||
{
|
||||
// re-configure the drawcall pointers, since they will be invalid
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(m_Drawcalls, ret.drawcallList, NULL, previous);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -649,6 +649,8 @@ private:
|
||||
FrameRecord m_FrameRecord;
|
||||
APIProperties m_APIProps;
|
||||
|
||||
std::vector<DrawcallDescription *> m_Drawcalls;
|
||||
|
||||
SDFile m_StructuredFile;
|
||||
|
||||
std::vector<ResourceDescription> m_Resources;
|
||||
|
||||
@@ -1083,7 +1083,7 @@ ReplayStatus WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool store
|
||||
if(!IsStructuredExporting(m_State))
|
||||
{
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
SetupDrawcallPointers(m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
}
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
|
||||
@@ -1456,10 +1456,9 @@ vector<uint32_t> D3D11Replay::GetPassEvents(uint32_t eventId)
|
||||
const DrawcallDescription *draw = m_pDevice->GetDrawcall(eventId);
|
||||
|
||||
const DrawcallDescription *start = draw;
|
||||
while(start && start->previous != 0 &&
|
||||
!(m_pDevice->GetDrawcall((uint32_t)start->previous)->flags & DrawFlags::Clear))
|
||||
while(start && start->previous && !(start->previous->flags & DrawFlags::Clear))
|
||||
{
|
||||
const DrawcallDescription *prev = m_pDevice->GetDrawcall((uint32_t)start->previous);
|
||||
const DrawcallDescription *prev = start->previous;
|
||||
|
||||
if(memcmp(start->outputs, prev->outputs, sizeof(start->outputs)) ||
|
||||
start->depthOut != prev->depthOut)
|
||||
@@ -1476,7 +1475,7 @@ vector<uint32_t> D3D11Replay::GetPassEvents(uint32_t eventId)
|
||||
if(start->flags & DrawFlags::Drawcall)
|
||||
passEvents.push_back(start->eventId);
|
||||
|
||||
start = m_pDevice->GetDrawcall((uint32_t)start->next);
|
||||
start = start->next;
|
||||
}
|
||||
|
||||
return passEvents;
|
||||
|
||||
@@ -2721,7 +2721,7 @@ ReplayStatus WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool store
|
||||
m_Queue->GetParentDrawcall().children.clear();
|
||||
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
SetupDrawcallPointers(m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
|
||||
D3D12CommandData &cmd = *m_Queue->GetCommandData();
|
||||
|
||||
|
||||
@@ -2528,7 +2528,7 @@ vector<uint32_t> D3D12Replay::GetPassEvents(uint32_t eventId)
|
||||
return passEvents;
|
||||
|
||||
// step back
|
||||
const DrawcallDescription *prev = m_pDevice->GetDrawcall((uint32_t)start->previous);
|
||||
const DrawcallDescription *prev = start->previous;
|
||||
|
||||
// something went wrong, start->previous was non-zero but we didn't
|
||||
// get a draw. Abort
|
||||
@@ -2556,7 +2556,7 @@ vector<uint32_t> D3D12Replay::GetPassEvents(uint32_t eventId)
|
||||
if(start->flags & (DrawFlags::Drawcall | DrawFlags::PassBoundary))
|
||||
passEvents.push_back(start->eventId);
|
||||
|
||||
start = m_pDevice->GetDrawcall((uint32_t)start->next);
|
||||
start = start->next;
|
||||
}
|
||||
|
||||
return passEvents;
|
||||
|
||||
@@ -4374,7 +4374,7 @@ ReplayStatus WrappedOpenGL::ContextReplayLog(CaptureState readType, uint32_t sta
|
||||
GetFrameRecord().frameInfo.debugMessages = GetDebugMessages();
|
||||
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
SetupDrawcallPointers(m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
|
||||
// it's easier to remove duplicate usages here than check it as we go.
|
||||
// this means if textures are bound in multiple places in the same draw
|
||||
|
||||
@@ -98,10 +98,9 @@ vector<uint32_t> GLReplay::GetPassEvents(uint32_t eventId)
|
||||
const DrawcallDescription *draw = m_pDriver->GetDrawcall(eventId);
|
||||
|
||||
const DrawcallDescription *start = draw;
|
||||
while(start && start->previous != 0 &&
|
||||
!(m_pDriver->GetDrawcall((uint32_t)start->previous)->flags & DrawFlags::Clear))
|
||||
while(start && start->previous && !(start->previous->flags & DrawFlags::Clear))
|
||||
{
|
||||
const DrawcallDescription *prev = m_pDriver->GetDrawcall((uint32_t)start->previous);
|
||||
const DrawcallDescription *prev = start->previous;
|
||||
|
||||
if(memcmp(start->outputs, prev->outputs, sizeof(start->outputs)) ||
|
||||
start->depthOut != prev->depthOut)
|
||||
@@ -118,7 +117,7 @@ vector<uint32_t> GLReplay::GetPassEvents(uint32_t eventId)
|
||||
if(start->flags & DrawFlags::Drawcall)
|
||||
passEvents.push_back(start->eventId);
|
||||
|
||||
start = m_pDriver->GetDrawcall((uint32_t)start->next);
|
||||
start = start->next;
|
||||
}
|
||||
|
||||
return passEvents;
|
||||
|
||||
@@ -1985,7 +1985,7 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta
|
||||
GetFrameRecord().drawcallList = m_ParentDrawcall.Bake();
|
||||
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
SetupDrawcallPointers(m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous);
|
||||
|
||||
struct SortEID
|
||||
{
|
||||
|
||||
@@ -130,11 +130,11 @@ vector<uint32_t> VulkanReplay::GetPassEvents(uint32_t eventId)
|
||||
|
||||
// if we've come to the start of the log we were outside of a render pass
|
||||
// to start with
|
||||
if(start->previous == 0)
|
||||
if(start->previous == NULL)
|
||||
return passEvents;
|
||||
|
||||
// step back
|
||||
start = m_pDriver->GetDrawcall((uint32_t)start->previous);
|
||||
start = start->previous;
|
||||
|
||||
// something went wrong, start->previous was non-zero but we didn't
|
||||
// get a draw. Abort
|
||||
@@ -155,7 +155,7 @@ vector<uint32_t> VulkanReplay::GetPassEvents(uint32_t eventId)
|
||||
if(start->flags & (DrawFlags::Drawcall | DrawFlags::PassBoundary))
|
||||
passEvents.push_back(start->eventId);
|
||||
|
||||
start = m_pDriver->GetDrawcall((uint32_t)start->next);
|
||||
start = start->next;
|
||||
}
|
||||
|
||||
return passEvents;
|
||||
|
||||
@@ -491,9 +491,8 @@ void DoSerialise(SerialiserType &ser, DrawcallDescription &el)
|
||||
SERIALISE_MEMBER(copySource);
|
||||
SERIALISE_MEMBER(copyDestination);
|
||||
|
||||
SERIALISE_MEMBER(parent);
|
||||
SERIALISE_MEMBER(previous);
|
||||
SERIALISE_MEMBER(next);
|
||||
if(ser.IsReading())
|
||||
el.parent = el.previous = el.next = NULL;
|
||||
|
||||
SERIALISE_MEMBER(outputs);
|
||||
SERIALISE_MEMBER(depthOut);
|
||||
|
||||
@@ -290,11 +290,218 @@ DrawcallDescription *ReplayController::GetDrawcallByEID(uint32_t eventId)
|
||||
return m_Drawcalls[eventId];
|
||||
}
|
||||
|
||||
rdcarray<DrawcallDescription> ReplayController::GetDrawcalls()
|
||||
const rdcarray<DrawcallDescription> &ReplayController::GetDrawcalls()
|
||||
{
|
||||
return m_FrameRecord.drawcallList;
|
||||
}
|
||||
|
||||
bool ReplayController::ContainsMarker(const rdcarray<DrawcallDescription> &draws)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
for(const DrawcallDescription &d : draws)
|
||||
{
|
||||
ret |= (d.flags & DrawFlags::PushMarker) &&
|
||||
!(d.flags & (DrawFlags::CmdList | DrawFlags::MultiDraw)) && !d.children.empty();
|
||||
ret |= ContainsMarker(d.children);
|
||||
|
||||
if(ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ReplayController::PassEquivalent(const DrawcallDescription &a, const DrawcallDescription &b)
|
||||
{
|
||||
// executing command lists can have children
|
||||
if(!a.children.empty() || !b.children.empty())
|
||||
return false;
|
||||
|
||||
// don't group draws and compute executes
|
||||
if((a.flags & DrawFlags::Dispatch) != (b.flags & DrawFlags::Dispatch))
|
||||
return false;
|
||||
|
||||
// don't group present with anything
|
||||
if((a.flags & DrawFlags::Present) != (b.flags & DrawFlags::Present))
|
||||
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())
|
||||
numAOuts++;
|
||||
if(b.outputs[i] != ResourceId())
|
||||
numBOuts++;
|
||||
}
|
||||
|
||||
int numSame = 0;
|
||||
|
||||
if(a.depthOut != ResourceId())
|
||||
{
|
||||
numAOuts++;
|
||||
numBOuts++;
|
||||
numSame++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++)
|
||||
{
|
||||
if(a.outputs[i] != ResourceId())
|
||||
{
|
||||
for(int j = 0; j < 8; j++)
|
||||
{
|
||||
if(a.outputs[i] == b.outputs[j])
|
||||
{
|
||||
numSame++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(b.outputs[i] != ResourceId())
|
||||
{
|
||||
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 > RDCMAX(numAOuts, numBOuts) / 2 && RDCMAX(numAOuts, numBOuts) > 1)
|
||||
return true;
|
||||
|
||||
if(numSame == RDCMAX(numAOuts, numBOuts))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReplayController::AddFakeMarkers()
|
||||
{
|
||||
rdcarray<DrawcallDescription> &draws = m_FrameRecord.drawcallList;
|
||||
|
||||
if(ContainsMarker(draws))
|
||||
return;
|
||||
|
||||
std::vector<DrawcallDescription> ret;
|
||||
|
||||
int depthpassID = 1;
|
||||
int copypassID = 1;
|
||||
int computepassID = 1;
|
||||
int passID = 1;
|
||||
|
||||
int start = 0;
|
||||
int refdraw = 0;
|
||||
|
||||
DrawFlags drawFlags = DrawFlags::Copy | DrawFlags::Resolve | DrawFlags::SetMarker |
|
||||
DrawFlags::APICalls | DrawFlags::CmdList;
|
||||
|
||||
for(int32_t i = 1; i < draws.count(); i++)
|
||||
{
|
||||
if(draws[refdraw].flags & drawFlags)
|
||||
{
|
||||
refdraw = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(draws[i].flags & drawFlags)
|
||||
continue;
|
||||
|
||||
if(PassEquivalent(draws[i], draws[refdraw]))
|
||||
continue;
|
||||
|
||||
int end = i - 1;
|
||||
|
||||
if(end - start < 2 || !draws[i].children.empty() || !draws[refdraw].children.empty())
|
||||
{
|
||||
for(int j = start; j <= end; j++)
|
||||
ret.push_back(draws[j]);
|
||||
|
||||
start = i;
|
||||
refdraw = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
int minOutCount = 100;
|
||||
int maxOutCount = 0;
|
||||
bool copyOnly = true;
|
||||
|
||||
for(int j = start; j <= end; j++)
|
||||
{
|
||||
int outCount = 0;
|
||||
|
||||
if(!(draws[j].flags & (DrawFlags::Copy | DrawFlags::Resolve | DrawFlags::Clear)))
|
||||
copyOnly = false;
|
||||
|
||||
for(ResourceId o : draws[j].outputs)
|
||||
if(o != ResourceId())
|
||||
outCount++;
|
||||
minOutCount = RDCMIN(minOutCount, outCount);
|
||||
maxOutCount = RDCMAX(maxOutCount, outCount);
|
||||
}
|
||||
|
||||
DrawcallDescription mark;
|
||||
|
||||
mark.eventId = draws[start].eventId;
|
||||
mark.drawcallId = draws[start].drawcallId;
|
||||
|
||||
mark.flags = DrawFlags::PushMarker;
|
||||
memcpy(mark.outputs, draws[end].outputs, sizeof(mark.outputs));
|
||||
mark.depthOut = draws[end].depthOut;
|
||||
|
||||
mark.name = "Guessed Pass";
|
||||
|
||||
minOutCount = RDCMAX(1, minOutCount);
|
||||
|
||||
const char *targets = draws[end].depthOut == ResourceId() ? "Targets" : "Targets + Depth";
|
||||
|
||||
if(copyOnly)
|
||||
mark.name = StringFormat::Fmt("Copy/Clear Pass #%d", copypassID++);
|
||||
else if(draws[refdraw].flags & DrawFlags::Dispatch)
|
||||
mark.name = StringFormat::Fmt("Compute Pass #%d", computepassID++);
|
||||
else if(maxOutCount == 0)
|
||||
mark.name = StringFormat::Fmt("Depth-only Pass #%d", depthpassID++);
|
||||
else if(minOutCount == maxOutCount)
|
||||
mark.name = StringFormat::Fmt("Colour Pass #%d (%d %s)", passID++, minOutCount, targets);
|
||||
else
|
||||
mark.name = StringFormat::Fmt("Colour Pass #%d (%d-%d %s)", passID++, minOutCount,
|
||||
maxOutCount, targets);
|
||||
|
||||
mark.children.resize(end - start + 1);
|
||||
|
||||
for(int j = start; j <= end; j++)
|
||||
mark.children[j - start] = draws[j];
|
||||
|
||||
ret.push_back(mark);
|
||||
|
||||
start = i;
|
||||
refdraw = i;
|
||||
}
|
||||
|
||||
if(start < draws.count())
|
||||
{
|
||||
for(int j = start; j < draws.count(); j++)
|
||||
ret.push_back(draws[j]);
|
||||
}
|
||||
|
||||
m_FrameRecord.drawcallList = ret;
|
||||
|
||||
// re-configure the previous/next pointeres
|
||||
DrawcallDescription *previous = NULL;
|
||||
m_Drawcalls.clear();
|
||||
SetupDrawcallPointers(m_Drawcalls, m_FrameRecord.drawcallList, NULL, previous);
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> ReplayController::FetchCounters(const rdcarray<GPUCounter> &counters)
|
||||
{
|
||||
std::vector<GPUCounter> counterArray(counters.begin(), counters.end());
|
||||
@@ -1718,7 +1925,8 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
|
||||
return ReplayStatus::APIReplayFailed;
|
||||
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, m_FrameRecord.drawcallList, NULL, previous);
|
||||
m_Drawcalls.clear();
|
||||
SetupDrawcallPointers(m_Drawcalls, m_FrameRecord.drawcallList, NULL, previous);
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
@@ -159,7 +159,8 @@ public:
|
||||
|
||||
FrameDescription GetFrameInfo();
|
||||
const SDFile &GetStructuredFile();
|
||||
rdcarray<DrawcallDescription> GetDrawcalls();
|
||||
const rdcarray<DrawcallDescription> &GetDrawcalls();
|
||||
void AddFakeMarkers();
|
||||
rdcarray<CounterResult> FetchCounters(const rdcarray<GPUCounter> &counters);
|
||||
rdcarray<GPUCounter> EnumerateCounters();
|
||||
CounterDescription DescribeCounter(GPUCounter counterID);
|
||||
@@ -208,6 +209,8 @@ private:
|
||||
ReplayStatus PostCreateInit(IReplayDriver *device, RDCFile *rdc);
|
||||
|
||||
DrawcallDescription *GetDrawcallByEID(uint32_t eventId);
|
||||
bool ContainsMarker(const rdcarray<DrawcallDescription> &draws);
|
||||
bool PassEquivalent(const DrawcallDescription &a, const DrawcallDescription &b);
|
||||
|
||||
IReplayDriver *GetDevice() { return m_pDevice; }
|
||||
FrameRecord m_FrameRecord;
|
||||
|
||||
@@ -53,7 +53,7 @@ void DoSerialise(SerialiserType &ser, GetTextureDataParams &el)
|
||||
|
||||
INSTANTIATE_SERIALISE_TYPE(GetTextureDataParams);
|
||||
|
||||
DrawcallDescription *SetupDrawcallPointers(vector<DrawcallDescription *> *drawcallTable,
|
||||
DrawcallDescription *SetupDrawcallPointers(vector<DrawcallDescription *> &drawcallTable,
|
||||
rdcarray<DrawcallDescription> &draws,
|
||||
DrawcallDescription *parent,
|
||||
DrawcallDescription *&previous)
|
||||
@@ -64,15 +64,14 @@ DrawcallDescription *SetupDrawcallPointers(vector<DrawcallDescription *> *drawca
|
||||
{
|
||||
DrawcallDescription *draw = &draws[i];
|
||||
|
||||
draw->parent = parent ? parent->eventId : 0;
|
||||
draw->parent = parent;
|
||||
|
||||
if(!draw->children.empty())
|
||||
{
|
||||
if(drawcallTable)
|
||||
{
|
||||
RDCASSERT(drawcallTable->empty() || draw->eventId > drawcallTable->back()->eventId);
|
||||
drawcallTable->resize(RDCMAX(drawcallTable->size(), size_t(draw->eventId + 1)));
|
||||
(*drawcallTable)[draw->eventId] = draw;
|
||||
RDCASSERT(drawcallTable.empty() || draw->eventId > drawcallTable.back()->eventId);
|
||||
drawcallTable.resize(RDCMAX(drawcallTable.size(), size_t(draw->eventId + 1)));
|
||||
drawcallTable[draw->eventId] = draw;
|
||||
}
|
||||
|
||||
ret = SetupDrawcallPointers(drawcallTable, draw->children, draw, previous);
|
||||
@@ -82,24 +81,25 @@ DrawcallDescription *SetupDrawcallPointers(vector<DrawcallDescription *> *drawca
|
||||
// don't want to set up previous/next links for markers, but still add them to the table
|
||||
// Some markers like Present or API Calls should have previous/next and are not markers
|
||||
|
||||
if(drawcallTable)
|
||||
{
|
||||
RDCASSERT(drawcallTable->empty() || draw->eventId > drawcallTable->back()->eventId);
|
||||
drawcallTable->resize(RDCMAX(drawcallTable->size(), size_t(draw->eventId + 1)));
|
||||
(*drawcallTable)[draw->eventId] = draw;
|
||||
RDCASSERT(drawcallTable.empty() || draw->eventId > drawcallTable.back()->eventId);
|
||||
drawcallTable.resize(RDCMAX(drawcallTable.size(), size_t(draw->eventId + 1)));
|
||||
drawcallTable[draw->eventId] = draw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(previous != NULL)
|
||||
previous->next = draw->eventId;
|
||||
draw->previous = previous ? previous->eventId : 0;
|
||||
if(previous)
|
||||
previous->next = draw;
|
||||
draw->previous = previous;
|
||||
|
||||
if(drawcallTable)
|
||||
{
|
||||
RDCASSERT(drawcallTable->empty() || draw->eventId > drawcallTable->back()->eventId);
|
||||
drawcallTable->resize(RDCMAX(drawcallTable->size(), size_t(draw->eventId + 1)));
|
||||
(*drawcallTable)[draw->eventId] = draw;
|
||||
// we also allow equal EIDs for fake markers that don't have their own EIDs
|
||||
RDCASSERT(drawcallTable.empty() || draw->eventId > drawcallTable.back()->eventId ||
|
||||
(draw->eventId == drawcallTable.back()->eventId &&
|
||||
(drawcallTable.back()->flags & DrawFlags::PushMarker)));
|
||||
drawcallTable.resize(RDCMAX(drawcallTable.size(), size_t(draw->eventId + 1)));
|
||||
drawcallTable[draw->eventId] = draw;
|
||||
}
|
||||
|
||||
ret = previous = draw;
|
||||
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
};
|
||||
|
||||
// utility functions useful in any driver implementation
|
||||
DrawcallDescription *SetupDrawcallPointers(std::vector<DrawcallDescription *> *drawcallTable,
|
||||
DrawcallDescription *SetupDrawcallPointers(std::vector<DrawcallDescription *> &drawcallTable,
|
||||
rdcarray<DrawcallDescription> &draws,
|
||||
DrawcallDescription *parent,
|
||||
DrawcallDescription *&previous);
|
||||
|
||||
Reference in New Issue
Block a user