mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 01:20:42 +00:00
Rename 'draw' or 'drawcall' to action
* There's not a good accepted terminology for this kind of event, and for historical reasons 'drawcall' has been the accepted term, even though that can be quite confusing when a dispatch or a copy is a 'drawcall'. * This is particularly highlighted by the event browser filters where $draw() includes draws and dispatches, but $dispatch() only includes dispatches, it's hard to intuitively understand why $draw() matches all of these calls. * As a result we've defined the term 'action' to cover these types of events in the same way that we defined 'event' in the first place to mean a single atomic API call.
This commit is contained in:
@@ -11,13 +11,13 @@ ReplayController
|
||||
|
||||
The primary interface for accessing the low level of RenderDoc's replay analysis is :py:class:`~renderdoc.ReplayController`.
|
||||
|
||||
From this interface, information about the capture can be gathered, using e.g. :py:meth:`~renderdoc.ReplayController.GetDrawcalls` to return the list of root-level drawcalls in the frame, or :py:meth:`~renderdoc.ReplayController.GetResources` to return a list of all resources in the capture.
|
||||
From this interface, information about the capture can be gathered, using e.g. :py:meth:`~renderdoc.ReplayController.GetRootActions` to return the list of root-level actions in the frame, or :py:meth:`~renderdoc.ReplayController.GetResources` to return a list of all resources in the capture.
|
||||
|
||||
Some methods like the two above return information which is global and does not vary across the frame. Most functions however return information relative to the current point in the frame.
|
||||
|
||||
During RenderDoc's replay, you can imagine a cursor that moves back and forth between the start and end of the frame. All requests for information that varies - such as texture and buffer contents, pipeline state, and other information will be relative to the current event.
|
||||
|
||||
Every function call within a frame is assigned an ascending ``eventId``, from ``1`` up to as many events as are in the frame. Within the drawcall list returned by :py:meth:`~renderdoc.ReplayController.GetDrawcalls`, each drawcall contains a list of events in :py:attr:`~renderdoc.DrawcallDescription.events`. These contain all of the ``eventId`` that immediately preceeded the draw. The details of the function call can be found by using :py:attr:`~renderdoc.APIEvent.chunkIndex` as an index into the structured data returned from :py:meth:`~renderdoc.GetStructuredFile`. The structured data contains the function name and the complete set of parameters passed to it, with their values.
|
||||
Every function call within a frame is assigned an ascending ``eventId``, from ``1`` up to as many events as are in the frame. Within the action list returned by :py:meth:`~renderdoc.ReplayController.GetRootActions`, each action contains a list of events in :py:attr:`~renderdoc.ActionDescription.events`. These contain all of the ``eventId`` that immediately preceeded the action. The details of the function call can be found by using :py:attr:`~renderdoc.APIEvent.chunkIndex` as an index into the structured data returned from :py:meth:`~renderdoc.GetStructuredFile`. The structured data contains the function name and the complete set of parameters passed to it, with their values.
|
||||
|
||||
To change the current active event and move the cursor, you can call :py:meth:`~renderdoc.ReplayController.SetFrameEvent`. This will move the replay to represent the current state immediately after the given event has executed.
|
||||
|
||||
@@ -51,4 +51,4 @@ Functions such as :py:meth:`~qrenderdoc.CaptureContext.GetTextureViewer` will re
|
||||
|
||||
You can also create new instances of windows such as buffer or shader viewers using :py:meth:`~qrenderdoc.CaptureContext.ViewBuffer` or :py:meth:`~qrenderdoc.CaptureContext.ViewShader`.
|
||||
|
||||
The :py:class:`~qrenderdoc.CaptureContext` interface also provides useful utility functions such as :py:meth:`~qrenderdoc.CaptureContext.GetTexture` or :py:meth:`~qrenderdoc.CaptureContext.GetDrawcall` to look up objects by id instead of needing your own caching and lookup from the lists returned by the lower level interface.
|
||||
The :py:class:`~qrenderdoc.CaptureContext` interface also provides useful utility functions such as :py:meth:`~qrenderdoc.CaptureContext.GetTexture` or :py:meth:`~qrenderdoc.CaptureContext.GetAction` to look up objects by id instead of needing your own caching and lookup from the lists returned by the lower level interface.
|
||||
|
||||
@@ -45,7 +45,7 @@ To invoke onto the right thread, you can use :py:meth:`~qrenderdoc.ReplayManager
|
||||
.. code:: python
|
||||
|
||||
def myCallback(controller):
|
||||
print("%d top-level drawcalls" % len(controller.GetDrawcalls()))
|
||||
print("%d top-level actions" % len(controller.GetRootActions()))
|
||||
|
||||
pyrenderdoc.Replay().BlockInvoke(myCallback)
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ def getMeshInputs(controller, draw):
|
||||
meshInput.numIndices = draw.numIndices
|
||||
|
||||
# If the draw doesn't use an index buffer, don't use it even if bound
|
||||
if not (draw.flags & rd.DrawFlags.Indexed):
|
||||
if not (draw.flags & rd.ActionFlags.Indexed):
|
||||
meshInput.indexResourceId = rd.ResourceId.Null()
|
||||
|
||||
# The total offset is the attribute offset from the base of the vertex
|
||||
@@ -223,7 +223,7 @@ def printMeshData(controller, meshData):
|
||||
def sampleCode(controller):
|
||||
# Find the biggest drawcall in the whole capture
|
||||
draw = None
|
||||
for d in controller.GetDrawcalls():
|
||||
for d in controller.GetRootActions():
|
||||
draw = biggestDraw(draw, d)
|
||||
|
||||
# Move to that draw
|
||||
|
||||
@@ -36,7 +36,7 @@ In the object we pass both the indices (which does not vary per attribute in our
|
||||
meshInput.numIndices = draw.numIndices
|
||||
|
||||
# If the draw doesn't use an index buffer, don't use it even if bound
|
||||
if not (draw.flags & rd.DrawFlags.Indexed):
|
||||
if not (draw.flags & rd.ActionFlags.Indexed):
|
||||
meshInput.indexResourceId = rd.ResourceId.Null()
|
||||
|
||||
# The total offset is the attribute offset from the base of the vertex
|
||||
|
||||
@@ -68,8 +68,8 @@ out = controller.CreateOutput(windata, rd.ReplayOutputType.Texture)
|
||||
# Fetch the list of textures
|
||||
textures = controller.GetTextures()
|
||||
|
||||
# Fetch the list of drawcalls
|
||||
draws = controller.GetDrawcalls()
|
||||
# Fetch the list of actions
|
||||
actions = controller.GetRootActions()
|
||||
|
||||
# Function to look up the texture descriptor for a given resourceId
|
||||
def getTexture(texid):
|
||||
@@ -85,23 +85,23 @@ def paint():
|
||||
out.Display()
|
||||
window.after(33, paint)
|
||||
|
||||
# Start on the first drawcall
|
||||
curdraw = draws[0]
|
||||
# Start on the first action
|
||||
curact = actions[0]
|
||||
|
||||
loopcount = 0
|
||||
|
||||
# The advance function will be called every 50ms, to move to the next draw
|
||||
# The advance function will be called every 50ms, to move to the next action
|
||||
def advance():
|
||||
global out, window, curdraw, draws, loopcount
|
||||
global out, window, curact, actions, loopcount
|
||||
|
||||
# Move to the current drawcall
|
||||
controller.SetFrameEvent(curdraw.eventId, False)
|
||||
# Move to the current action
|
||||
controller.SetFrameEvent(curact.eventId, False)
|
||||
|
||||
# Initialise a default TextureDisplay object
|
||||
disp = rd.TextureDisplay()
|
||||
|
||||
# Set the first colour output as the texture to display
|
||||
disp.resourceId = curdraw.outputs[0]
|
||||
disp.resourceId = curact.outputs[0]
|
||||
|
||||
if disp.resourceId != rd.ResourceId.Null():
|
||||
# Get the details of this texture
|
||||
@@ -117,13 +117,13 @@ def advance():
|
||||
# Update the texture display
|
||||
out.SetTextureDisplay(disp)
|
||||
|
||||
# Set the next drawcall
|
||||
curdraw = curdraw.next
|
||||
# Set the next action
|
||||
curact = curact.next
|
||||
|
||||
# If we have no next draw, start again from the first
|
||||
if curdraw is None:
|
||||
# If we have no next action, start again from the first
|
||||
if curact is None:
|
||||
loopcount = loopcount + 1
|
||||
curdraw = draws[0]
|
||||
curact = actions[0]
|
||||
|
||||
# after 3 loops, quit
|
||||
if loopcount == 3:
|
||||
|
||||
@@ -43,7 +43,7 @@ Once we have the :py:class:`~renderdoc.WindowingData`, we can create a :py:class
|
||||
# Create a texture output on the window
|
||||
out = controller.CreateOutput(windata, rd.ReplayOutputType.Texture)
|
||||
|
||||
In order to iterate over all drawcalls we need some global state first from :py:meth:`~renderdoc.ReplayController.GetTextures` and :py:meth:`~renderdoc.ReplayController.GetDrawcalls`, and we'll also define a helper function to fetch a particular texture by resourceId, so that we can easily look up the details for a texture.
|
||||
In order to iterate over all actions we need some global state first from :py:meth:`~renderdoc.ReplayController.GetTextures` and :py:meth:`~renderdoc.ReplayController.GetRootActions`, and we'll also define a helper function to fetch a particular texture by resourceId, so that we can easily look up the details for a texture.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
@@ -51,8 +51,8 @@ In order to iterate over all drawcalls we need some global state first from :py:
|
||||
# Fetch the list of textures
|
||||
textures = controller.GetTextures()
|
||||
|
||||
# Fetch the list of drawcalls
|
||||
draws = controller.GetDrawcalls()
|
||||
# Fetch the list of actions
|
||||
actions = controller.GetRootActions()
|
||||
|
||||
# Function to look up the texture descriptor for a given resourceId
|
||||
def getTexture(texid):
|
||||
@@ -62,7 +62,7 @@ In order to iterate over all drawcalls we need some global state first from :py:
|
||||
return tex
|
||||
return None
|
||||
|
||||
We now define two callback functions - ``paint`` and ``advance``. ``paint`` will be called every 33ms, it will display the output with the latest state using :py:meth:`~renderdoc.ReplayOutput.Display`. ``advance`` changes the current state to reflect a new drawcall.
|
||||
We now define two callback functions - ``paint`` and ``advance``. ``paint`` will be called every 33ms, it will display the output with the latest state using :py:meth:`~renderdoc.ReplayOutput.Display`. ``advance`` changes the current state to reflect a new action.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
@@ -73,48 +73,60 @@ We now define two callback functions - ``paint`` and ``advance``. ``paint`` will
|
||||
out.Display()
|
||||
window.after(33, paint)
|
||||
|
||||
Within ``advance`` we do a few things. First we move the current event to the current drawcall's ``eventId``, using :py:meth:`~renderdoc.ReplayController.SetFrameEvent`. Then we set up the texture display configuration with :py:meth:`~renderdoc.ReplayOutput.SetTextureDisplay`, to point to the first colour output at that drawcall.
|
||||
Within ``advance`` we do a few things. First we move the current event to the current action's ``eventId``, using :py:meth:`~renderdoc.ReplayController.SetFrameEvent`. Then we set up the texture display configuration with :py:meth:`~renderdoc.ReplayOutput.SetTextureDisplay`, to point to the first colour output at that action.
|
||||
|
||||
When we update to a new texture, we fetch its details using our earlier ``getTexture`` and calculate a scale that keeps the texture fully visible on screen.
|
||||
|
||||
Finally we move to the next drawcall in the list for the next time ``advance`` is called.
|
||||
Finally we move to the next action in the list for the next time ``advance`` is called.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
# Start on the first drawcall
|
||||
curdraw = 0
|
||||
# Start on the first action
|
||||
curact = actions[0]
|
||||
|
||||
loopcount = 0
|
||||
|
||||
# The advance function will be called every 150ms, to move to the next draw
|
||||
# The advance function will be called every 50ms, to move to the next action
|
||||
def advance():
|
||||
global out, window, curdraw
|
||||
|
||||
# Move to the current drawcall
|
||||
controller.SetFrameEvent(draws[curdraw].eventId, False)
|
||||
|
||||
global out, window, curact, actions, loopcount
|
||||
|
||||
# Move to the current action
|
||||
controller.SetFrameEvent(curact.eventId, False)
|
||||
|
||||
# Initialise a default TextureDisplay object
|
||||
disp = rd.TextureDisplay()
|
||||
|
||||
|
||||
# Set the first colour output as the texture to display
|
||||
disp.resourceId = draws[curdraw].outputs[0]
|
||||
|
||||
# Get the details of this texture
|
||||
texDetails = getTexture(disp.resourceId)
|
||||
|
||||
# Calculate the scale required in width and height
|
||||
widthScale = window.winfo_width() / texDetails.width
|
||||
heightScale = window.winfo_height() / texDetails.height
|
||||
|
||||
# Use the lower scale to fit the texture on the window
|
||||
disp.scale = min(widthScale, heightScale)
|
||||
|
||||
# Update the texture display
|
||||
out.SetTextureDisplay(disp)
|
||||
|
||||
# Set the next drawcall
|
||||
curdraw = (curdraw + 1) % len(draws)
|
||||
|
||||
window.after(150, advance)
|
||||
disp.resourceId = curact.outputs[0]
|
||||
|
||||
if disp.resourceId != rd.ResourceId.Null():
|
||||
# Get the details of this texture
|
||||
texDetails = getTexture(disp.resourceId)
|
||||
|
||||
# Calculate the scale required in width and height
|
||||
widthScale = window.winfo_width() / texDetails.width
|
||||
heightScale = window.winfo_height() / texDetails.height
|
||||
|
||||
# Use the lower scale to fit the texture on the window
|
||||
disp.scale = min(widthScale, heightScale)
|
||||
|
||||
# Update the texture display
|
||||
out.SetTextureDisplay(disp)
|
||||
|
||||
# Set the next action
|
||||
curact = curact.next
|
||||
|
||||
# If we have no next action, start again from the first
|
||||
if curact is None:
|
||||
loopcount = loopcount + 1
|
||||
curact = actions[0]
|
||||
|
||||
# after 3 loops, quit
|
||||
if loopcount == 3:
|
||||
window.quit()
|
||||
else:
|
||||
window.after(50, advance)
|
||||
|
||||
Once we have the callbacks defined, we call them once to initialise the display and set up the repeated callbacks, and start the tkinter main window loop.
|
||||
|
||||
|
||||
@@ -7,23 +7,23 @@ if 'renderdoc' not in sys.modules and '_renderdoc' not in sys.modules:
|
||||
# Alias renderdoc for legibility
|
||||
rd = renderdoc
|
||||
|
||||
draws = {}
|
||||
actions = {}
|
||||
|
||||
# Define a recursive function for iterating over draws
|
||||
# Define a recursive function for iterating over actions
|
||||
def iterDraw(d, indent = ''):
|
||||
global draws
|
||||
global actions
|
||||
|
||||
# save the drawcall by eventId
|
||||
draws[d.eventId] = d
|
||||
# save the action by eventId
|
||||
actions[d.eventId] = d
|
||||
|
||||
# Iterate over the draw's children
|
||||
for d in d.children:
|
||||
iterDraw(d, indent + ' ')
|
||||
|
||||
def sampleCode(controller):
|
||||
# Iterate over all of the root drawcalls, so we have names for each
|
||||
# Iterate over all of the root actions, so we have names for each
|
||||
# eventId
|
||||
for d in controller.GetDrawcalls():
|
||||
for d in controller.GetRootActions():
|
||||
iterDraw(d)
|
||||
|
||||
# Enumerate the available counters
|
||||
@@ -50,10 +50,10 @@ def sampleCode(controller):
|
||||
# Look in the results for any draws with 0 samples written - this is an indication
|
||||
# that if a lot of draws appear then culling could be better.
|
||||
for r in results:
|
||||
draw = draws[r.eventId]
|
||||
draw = actions[r.eventId]
|
||||
|
||||
# Only care about draws, not about clears and other misc events
|
||||
if not (draw.flags & rd.DrawFlags.Drawcall):
|
||||
if not (draw.flags & rd.ActionFlags.Drawcall):
|
||||
continue
|
||||
|
||||
if samplesPassedDesc.resultByteWidth == 4:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Fetch GPU Counter Data
|
||||
======================
|
||||
|
||||
In this example we will gather GPU counter data over a capture and find any drawcalls that completely failed the depth/stencil test.
|
||||
In this example we will gather GPU counter data over a capture and find any actions that completely failed the depth/stencil test.
|
||||
|
||||
The first thing we do is enumerate a list of counters that the implementation supports using :py:meth:`~renderdoc.ReplayController.EnumerateCounters`. A few of these counters values are statically known - see :py:class:`~renderdoc.GPUCounter`. If you know which counter you want ahead of time you can continue straight away by calling :py:meth:`~renderdoc.ReplayController.FetchCounters` with a list of counters to sample from, or :py:meth:`~renderdoc.ReplayController.DescribeCounter` to obtain a :py:class:`~renderdoc.CounterDescription` of the counter itself:
|
||||
|
||||
@@ -34,7 +34,7 @@ However we will also print all available counters. If the implementation support
|
||||
print(" %s" % desc.description)
|
||||
print(" Returns %d byte %s, representing %s" % (desc.resultByteWidth, desc.resultType, desc.unit))
|
||||
|
||||
Once we have the list of :py:class:`~renderdoc.CounterResult` from sampling the specified counters, each result returned is for one counter on one event. Since we only fetched one counter we can simply iterate over the results looking up the drawcall for each. For actual draws (excluding clears and markers etc) we use the counter description to determine the data payload size, and get the value out. Interpreting this can either happen based on the description, or in our case we know that this counter returns a simple value we can check:
|
||||
Once we have the list of :py:class:`~renderdoc.CounterResult` from sampling the specified counters, each result returned is for one counter on one event. Since we only fetched one counter we can simply iterate over the results looking up the action for each. For actual draws (excluding clears and markers etc) we use the counter description to determine the data payload size, and get the value out. Interpreting this can either happen based on the description, or in our case we know that this counter returns a simple value we can check:
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
@@ -42,10 +42,10 @@ Once we have the list of :py:class:`~renderdoc.CounterResult` from sampling the
|
||||
# Look in the results for any draws with 0 samples written - this is an indication
|
||||
# that if a lot of draws appear then culling could be better.
|
||||
for r in results:
|
||||
draw = draws[r.eventId]
|
||||
draw = actions[r.eventId]
|
||||
|
||||
# Only care about draws, not about clears and other misc events
|
||||
if not (draw.flags & rd.DrawFlags.Drawcall):
|
||||
if not (draw.flags & rd.ActionFlags.Drawcall):
|
||||
continue
|
||||
|
||||
if samplesPassedDesc.resultByteWidth == 4:
|
||||
|
||||
@@ -26,7 +26,7 @@ In order to help with this, the examples are organised such that most code is wr
|
||||
cap.Shutdown()
|
||||
|
||||
.. toctree::
|
||||
iter_draws
|
||||
iter_actions
|
||||
fetch_shader
|
||||
fetch_counters
|
||||
save_texture
|
||||
|
||||
+23
-23
@@ -7,56 +7,56 @@ if 'renderdoc' not in sys.modules and '_renderdoc' not in sys.modules:
|
||||
# Alias renderdoc for legibility
|
||||
rd = renderdoc
|
||||
|
||||
# Define a recursive function for iterating over draws
|
||||
def iterDraw(d, indent = ''):
|
||||
# Print this drawcall
|
||||
# Define a recursive function for iterating over actions
|
||||
def iterAction(d, indent = ''):
|
||||
# Print this action
|
||||
print('%s%d: %s' % (indent, d.eventId, d.name))
|
||||
|
||||
# Iterate over the draw's children
|
||||
# Iterate over the action's children
|
||||
for d in d.children:
|
||||
iterDraw(d, indent + ' ')
|
||||
iterAction(d, indent + ' ')
|
||||
|
||||
def sampleCode(controller):
|
||||
# Iterate over all of the root drawcalls
|
||||
for d in controller.GetDrawcalls():
|
||||
iterDraw(d)
|
||||
# Iterate over all of the root actions
|
||||
for d in controller.GetRootActions():
|
||||
iterAction(d)
|
||||
|
||||
# Start iterating from the first real draw as a child of markers
|
||||
draw = controller.GetDrawcalls()[0]
|
||||
# Start iterating from the first real action as a child of markers
|
||||
action = controller.GetRootActions()[0]
|
||||
|
||||
while len(draw.children) > 0:
|
||||
draw = draw.children[0]
|
||||
while len(action.children) > 0:
|
||||
action = action.children[0]
|
||||
|
||||
# Counter for which pass we're in
|
||||
passnum = 0
|
||||
# Counter for how many draws are in the pass
|
||||
# Counter for how many actions are in the pass
|
||||
passcontents = 0
|
||||
# Whether we've started seeing draws in the pass - i.e. we're past any
|
||||
# Whether we've started seeing actions 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))
|
||||
print("Pass #0 starts with %d: %s" % (action.eventId, action.name))
|
||||
|
||||
while draw != None:
|
||||
while action != None:
|
||||
# When we encounter a clear
|
||||
if draw.flags & rd.DrawFlags.Clear:
|
||||
if action.flags & rd.ActionFlags.Clear:
|
||||
if inpass:
|
||||
print("Pass #%d contained %d draws" % (passnum, passcontents))
|
||||
print("Pass #%d contained %d actions" % (passnum, passcontents))
|
||||
passnum += 1
|
||||
print("Pass #%d starts with %d: %s" % (passnum, draw.eventId, draw.name))
|
||||
print("Pass #%d starts with %d: %s" % (passnum, action.eventId, action.name))
|
||||
passcontents = 0
|
||||
inpass = False
|
||||
else:
|
||||
passcontents += 1
|
||||
inpass = True
|
||||
|
||||
# Advance to the next drawcall
|
||||
draw = draw.next
|
||||
if draw is None:
|
||||
# Advance to the next action
|
||||
action = action.next
|
||||
if action is None:
|
||||
break
|
||||
|
||||
if inpass:
|
||||
print("Pass #%d contained %d draws" % (passnum, passcontents))
|
||||
print("Pass #%d contained %d actions" % (passnum, passcontents))
|
||||
|
||||
def loadCapture(filename):
|
||||
# Open a capture file handle
|
||||
+13
-13
@@ -1,24 +1,24 @@
|
||||
Iterate drawcall tree
|
||||
=====================
|
||||
Iterate Action tree
|
||||
===================
|
||||
|
||||
In this example we will show how to iterate over drawcalls.
|
||||
In this example we will show how to iterate over actions.
|
||||
|
||||
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 actions returned from :py:meth:`~renderdoc.ReplayController.GetRootActions` are actions or marker regions at the root level - with no parent marker region. There are multiple ways to iterate through the list of actions.
|
||||
|
||||
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 first way illustrated in this sample is to walk the tree using :py:attr:`~renderdoc.ActionDescription.children`, which contains the list of child actions at any point in the tree. There is also :py:attr:`~renderdoc.ActionDescription.parent` which points to the parent action.
|
||||
|
||||
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.
|
||||
The second is to use :py:attr:`~renderdoc.ActionDescription.previous` and :py:attr:`~renderdoc.ActionDescription.next`, which point to the previous and next action 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.
|
||||
In the example we use this iteration to determine the number of passes, using the action flags to denote the start of each pass by a starting clear call.
|
||||
|
||||
Example Source
|
||||
--------------
|
||||
|
||||
.. only:: html and not htmlhelp
|
||||
|
||||
:download:`Download the example script <iter_draws.py>`.
|
||||
:download:`Download the example script <iter_actions.py>`.
|
||||
|
||||
.. literalinclude:: iter_draws.py
|
||||
.. literalinclude:: iter_actions.py
|
||||
|
||||
Sample output:
|
||||
|
||||
@@ -95,11 +95,11 @@ Sample output:
|
||||
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 #0 contained 24 actions
|
||||
Pass #1 starts with 319: ClearDepthStencilView(D=1.000000, S=00)
|
||||
Pass #1 contained 24 draws
|
||||
Pass #1 contained 24 actions
|
||||
Pass #2 starts with 558: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
|
||||
Pass #2 contained 3 draws
|
||||
Pass #2 contained 3 actions
|
||||
Pass #3 starts with 617: ClearRenderTargetView(0.000000, 0.000000, 0.000000, 1.000000)
|
||||
Pass #3 contained 4 draws
|
||||
Pass #3 contained 4 actions
|
||||
|
||||
@@ -24,7 +24,7 @@ def biggestDraw(prevBiggest, d):
|
||||
def sampleCode(controller):
|
||||
# Find the biggest drawcall in the whole capture
|
||||
draw = None
|
||||
for d in controller.GetDrawcalls():
|
||||
for d in controller.GetRootActions():
|
||||
draw = biggestDraw(draw, d)
|
||||
|
||||
# Move to that draw
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Save a texture to disk
|
||||
======================
|
||||
|
||||
In this example we will find a particular drawcall, and save the color output to disk as an image file.
|
||||
In this example we will find a particular action, and save the color output to disk as an image file.
|
||||
|
||||
To begin with, so that we have an interesting drawcall selected we iterate over the list of draws finding the drawcall with the highest vertex count. For more on how to iterate through a capture's list of drawcalls, see :doc:`iter_draws`.
|
||||
To begin with, so that we have an interesting action selected we iterate over the list of actions finding the draw with the highest vertex count. For more on how to iterate through a capture's list of actions, see :doc:`iter_actions`.
|
||||
|
||||
Once we have set the drawcall we want as the current event, we can configure the texture save operation. To do this we create a :py:class:`~renderdoc.TextureSave` object. The properties of the object determine how the texture will be mapped to an image file to be saved to disk.
|
||||
Once we have set the draw we want as the current event, we can configure the texture save operation. To do this we create a :py:class:`~renderdoc.TextureSave` object. The properties of the object determine how the texture will be mapped to an image file to be saved to disk.
|
||||
|
||||
At minimum you need to select a file format, and we'll try a few - :py:attr:`~renderdoc.FileType.JPG`, :py:attr:`~renderdoc.FileType.HDR`, :py:attr:`~renderdoc.FileType.PNG`, and :py:attr:`~renderdoc.FileType.DDS`.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ if status != rd.ReplayStatus.Succeeded:
|
||||
raise RuntimeError("Couldn't initialise replay: " + str(status))
|
||||
|
||||
# Now we can use the controller!
|
||||
print("%d top-level drawcalls" % len(controller.GetDrawcalls()))
|
||||
print("%d top-level actions" % len(controller.GetRootActions()))
|
||||
|
||||
controller.Shutdown()
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ This function call will open the capture and begin to replay it, and initialise
|
||||
raise RuntimeError("Couldn't initialise replay: " + str(status))
|
||||
|
||||
# Now we can use the controller!
|
||||
print("%d top-level drawcalls" % len(controller.GetDrawcalls()))
|
||||
print("%d top-level actions" % len(controller.GetRootActions()))
|
||||
|
||||
Once we're done with the interfaces, we should call the ``Shutdown`` function on each, this allows the C++ interface to release the resources allocated.
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@ Replay Analysis
|
||||
|
||||
.. currentmodule:: renderdoc
|
||||
|
||||
Frame and Drawcalls
|
||||
-------------------
|
||||
Frame and Actions
|
||||
-----------------
|
||||
|
||||
.. autoclass:: FrameDescription
|
||||
:members:
|
||||
|
||||
.. autoclass:: DrawcallDescription
|
||||
.. autoclass:: ActionDescription
|
||||
:members:
|
||||
|
||||
.. autoclass:: DrawFlags
|
||||
.. autoclass:: ActionFlags
|
||||
:members:
|
||||
|
||||
.. autoclass:: APIEvent
|
||||
|
||||
@@ -56,16 +56,16 @@ class Window(qrd.CaptureViewer):
|
||||
pass
|
||||
|
||||
def OnEventChanged(self, event):
|
||||
draw = self.ctx.GetDrawcall(event)
|
||||
action = self.ctx.GetAction(event)
|
||||
|
||||
breadcrumbs = ''
|
||||
|
||||
if draw is not None:
|
||||
breadcrumbs = '@{}: {}'.format(draw.eventId, draw.name)
|
||||
if action is not None:
|
||||
breadcrumbs = '@{}: {}'.format(action.eventId, action.name)
|
||||
|
||||
while draw.parent is not None:
|
||||
draw = draw.parent
|
||||
breadcrumbs = '@{}: {}'.format(draw.eventId, draw.name) + '\n' + breadcrumbs
|
||||
while action.parent is not None:
|
||||
action = action.parent
|
||||
breadcrumbs = '@{}: {}'.format(action.eventId, action.name) + '\n' + breadcrumbs
|
||||
|
||||
self.mqt.SetWidgetText(self.breadcrumbs, "Breadcrumbs:\n{}".format(breadcrumbs))
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Now we have a new menu item which when clicked produces a popup message dialog!
|
||||
|
||||
Python extension generating a message box
|
||||
|
||||
This is a good proof of concept, but really we want something more directly usable. Instead of showing a message box, let's show a window which reacts to the selected drawcall by showing a series of breadcrumbs for marker labels.
|
||||
This is a good proof of concept, but really we want something more directly usable. Instead of showing a message box, let's show a window which reacts to the selected action by showing a series of breadcrumbs for marker labels.
|
||||
|
||||
Adding a window and capture viewer
|
||||
----------------------------------
|
||||
@@ -110,16 +110,16 @@ And finally we can fill in the event functions to set the breadcrumbs. We use ``
|
||||
pass
|
||||
|
||||
def OnEventChanged(self, event):
|
||||
draw = self.ctx.GetDrawcall(event)
|
||||
action = self.ctx.GetAction(event)
|
||||
|
||||
breadcrumbs = ''
|
||||
|
||||
if draw is not None:
|
||||
breadcrumbs = '@{}: {}'.format(draw.eventId, draw.name)
|
||||
if action is not None:
|
||||
breadcrumbs = '@{}: {}'.format(action.eventId, action.name)
|
||||
|
||||
while draw.parent is not None:
|
||||
draw = draw.parent
|
||||
breadcrumbs = '@{}: {}'.format(draw.eventId, draw.name) + '\n' + breadcrumbs
|
||||
while action.parent is not None:
|
||||
action = action.parent
|
||||
breadcrumbs = '@{}: {}'.format(action.eventId, action.name) + '\n' + breadcrumbs
|
||||
|
||||
self.mqt.SetWidgetText(self.breadcrumbs, "Breadcrumbs:\n{}".format(breadcrumbs))
|
||||
|
||||
@@ -176,12 +176,12 @@ With that we now have a new little breadcrumbs window that docks itself above ou
|
||||
|
||||
.. figure:: ../imgs/python_ext/Step2.png
|
||||
|
||||
Python extension showing the current draw's breadcrumbs
|
||||
Python extension showing the current action's breadcrumbs
|
||||
|
||||
Calling onto replay thread
|
||||
--------------------------
|
||||
|
||||
So far this has worked well, but we're only using information available on the UI thread. A good amount of useful information is cached on the UI thread including the current pipeline state and drawcalls, but for some work we might want to call into the underlying analysis functions. When we do this we must do it on the replay thread to avoid blocking the UI if the analysis work takes a long time.
|
||||
So far this has worked well, but we're only using information available on the UI thread. A good amount of useful information is cached on the UI thread including the current pipeline state and actions, but for some work we might want to call into the underlying analysis functions. When we do this we must do it on the replay thread to avoid blocking the UI if the analysis work takes a long time.
|
||||
|
||||
This can get quite complex so we will do something very simple, in the message box callback that we created earlier instead of displaying the message box immediately we will first figure out the minimum and maximum values for the current depth output or first colour output and display that.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user