Iterate drawcall tree¶
In this example we will show how to iterate over drawcalls.
The drawcalls returned from 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 children
, which contains the list of child draws at any point in the tree. There is also parent
which points to the parent drawcall.
The second is to use previous
and 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.
Example Source¶
import sys
# Import renderdoc if not already imported (e.g. in the UI)
if 'renderdoc' not in sys.modules and '_renderdoc' not in sys.modules:
import renderdoc
# Alias renderdoc for legibility
rd = renderdoc
# Define a recursive function for iterating over draws
def iterDraw(d, indent = ''):
# Print this drawcall
print('%s%d: %s' % (indent, d.eventId, d.name))
# Iterate over the draw's children
for d in d.children:
iterDraw(d, indent + ' ')
def sampleCode(controller):
# Iterate over all of the root drawcalls
for d in controller.GetDrawcalls():
iterDraw(d)
# Start iterating from the first real draw as a child of markers
draw = controller.GetDrawcalls()[0]
while len(draw.children) > 0:
draw = draw.children[0]
# Counter for which pass we're in
passnum = 0
# Counter for how many draws are in the pass
passcontents = 0
# Whether we've started seeing draws in the pass - i.e. we're past any
# starting clear calls that may be batched together
inpass = False
print("Pass #0 starts with %d: %s" % (draw.eventId, draw.name))
while draw != None:
# When we encounter a clear
if draw.flags & rd.DrawFlags.Clear:
if inpass:
print("Pass #%d contained %d draws" % (passnum, passcontents))
passnum += 1
print("Pass #%d starts with %d: %s" % (passnum, draw.eventId, draw.name))
passcontents = 0
inpass = False
else:
passcontents += 1
inpass = True
# Advance to the next drawcall
draw = draw.next
if draw is None:
break
if inpass:
print("Pass #%d contained %d draws" % (passnum, passcontents))
def loadCapture(filename):
# Open a capture file handle
cap = rd.OpenCaptureFile()
# Open a particular file - see also OpenBuffer to load from memory
status = cap.OpenFile(filename, '', None)
# Make sure the file opened successfully
if status != rd.ReplayStatus.Succeeded:
raise RuntimeError("Couldn't open file: " + str(status))
# Make sure we can replay
if not cap.LocalReplaySupport():
raise RuntimeError("Capture cannot be replayed")
# Initialise the replay
status,controller = cap.OpenCapture(rd.ReplayOptions(), None)
if status != rd.ReplayStatus.Succeeded:
raise RuntimeError("Couldn't initialise replay: " + str(status))
return cap,controller
if 'pyrenderdoc' in globals():
pyrenderdoc.Replay().BlockInvoke(sampleCode)
else:
rd.InitialiseReplay(rd.GlobalEnvironment(), [])
if len(sys.argv) <= 1:
print('Usage: python3 {} filename.rdc'.format(sys.argv[0]))
sys.exit(0)
cap,controller = loadCapture(sys.argv[1])
sampleCode(controller)
controller.Shutdown()
cap.Shutdown()
rd.ShutdownReplay()
Sample output:
1: Scene
2: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
3: ClearDepthStencilView(D=1.000000, S=00)
9: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 0.000000)
10: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 0.000000)
11: ClearDepthStencilView(D=1.000000, S=00)
13: GBuffer
28: DrawIndexed(4800)
43: DrawIndexed(36)
56: DrawIndexed(5220)
69: DrawIndexed(5580)
82: DrawIndexed(5580)
95: DrawIndexed(5580)
108: DrawIndexed(5580)
121: DrawIndexed(5580)
134: DrawIndexed(5580)
147: DrawIndexed(5580)
160: DrawIndexed(5580)
173: DrawIndexed(5580)
186: DrawIndexed(5580)
199: DrawIndexed(5220)
212: DrawIndexed(5220)
225: DrawIndexed(5220)
238: DrawIndexed(5220)
251: DrawIndexed(5220)
264: DrawIndexed(5220)
277: DrawIndexed(5220)
290: DrawIndexed(5220)
303: DrawIndexed(5220)
316: DrawIndexed(5220)
319: ClearDepthStencilView(D=1.000000, S=00)
321: Shadowmap
333: DrawIndexed(4800)
345: DrawIndexed(36)
355: DrawIndexed(5220)
365: DrawIndexed(5580)
375: DrawIndexed(5580)
385: DrawIndexed(5580)
395: DrawIndexed(5580)
405: DrawIndexed(5580)
415: DrawIndexed(5580)
425: DrawIndexed(5580)
435: DrawIndexed(5580)
445: DrawIndexed(5580)
455: DrawIndexed(5580)
465: DrawIndexed(5220)
475: DrawIndexed(5220)
485: DrawIndexed(5220)
495: DrawIndexed(5220)
505: DrawIndexed(5220)
515: DrawIndexed(5220)
525: DrawIndexed(5220)
535: DrawIndexed(5220)
545: DrawIndexed(5220)
555: DrawIndexed(5220)
558: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
559: ClearDepthStencilView(D=1.000000, S=00)
561: Lighting
563: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 0.000000)
564: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 0.000000)
580: DrawIndexed(36)
597: DrawIndexed(36)
614: DrawIndexed(36)
617: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
618: ClearDepthStencilView(D=1.000000, S=00)
620: Shading
630: Draw(6)
645: DrawIndexed(960)
652: API Calls
655: End of Frame
Pass #0 starts with 2: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
Pass #0 contained 24 draws
Pass #1 starts with 319: ClearDepthStencilView(D=1.000000, S=00)
Pass #1 contained 24 draws
Pass #2 starts with 558: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
Pass #2 contained 3 draws
Pass #3 starts with 617: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
Pass #3 contained 4 draws