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:
baldurk
2018-06-18 18:39:06 +01:00
parent f919ea81e2
commit 0dda96a045
25 changed files with 307 additions and 309 deletions
@@ -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.
+11 -222
View File
@@ -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;
+6 -9
View File
@@ -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;
+2 -2
View File
@@ -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
{
+4 -4
View File
@@ -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)
+2 -2
View File
@@ -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())
+9 -13
View File
@@ -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.
+8 -1
View File
@@ -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.
+7
View File
@@ -381,6 +381,13 @@ FrameRecord ReplayProxy::Proxied_GetFrameRecord(ParamSerialiser &paramser, 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;
}
+2
View File
@@ -649,6 +649,8 @@ private:
FrameRecord m_FrameRecord;
APIProperties m_APIProps;
std::vector<DrawcallDescription *> m_Drawcalls;
SDFile m_StructuredFile;
std::vector<ResourceDescription> m_Resources;
+1 -1
View File
@@ -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)
+3 -4
View File
@@ -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;
+1 -1
View File
@@ -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();
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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
+3 -4
View File
@@ -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;
+1 -1
View File
@@ -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
{
+3 -3
View File
@@ -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;
+2 -3
View File
@@ -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);
+210 -2
View File
@@ -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;
}
+4 -1
View File
@@ -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;
+17 -17
View File
@@ -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;
+1 -1
View File
@@ -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);