4 # Copyright (c) 2019 Collabora Ltd
5 # Copyright © 2020 Valve Corporation.
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the "Software"),
9 # to deal in the Software without restriction, including without limitation
10 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 # and/or sell copies of the Software, and to permit persons to whom the
12 # Software is furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included
15 # in all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 # OTHER DEALINGS IN THE SOFTWARE.
25 # SPDX-License-Identifier: MIT
32 from pathlib
import Path
36 shutil
.rmtree(dirpath
)
39 TMP_DIR
= tempfile
.mkdtemp()
40 atexit
.register(cleanup
, TMP_DIR
)
41 RENDERDOC_DEBUG_FILE
= TMP_DIR
+ "/renderdoc.log"
43 # Needs to be in the environment before importing the module
44 os
.environ
['RENDERDOC_DEBUG_LOG_FILE'] = RENDERDOC_DEBUG_FILE
45 import renderdoc
as rd
# noqa: E402
48 from renderdoc
import ResultCode
50 from renderdoc
import ReplayStatus
as ResultCode
53 def find_draw_with_event_id(controller
, event_id
):
55 for root_action
in controller
.GetRootActions():
56 if root_action
.eventId
== event_id
:
58 except AttributeError:
59 for root_drawcall
in controller
.GetDrawcalls():
60 if root_drawcall
.eventId
== event_id
:
66 def dump_image(controller
, event_id
, output_dir
, tracefile
):
67 draw
= find_draw_with_event_id(controller
, event_id
)
69 raise RuntimeError("Couldn't find draw call with event ID " +
72 controller
.SetFrameEvent(draw
.eventId
, True)
74 texsave
= rd
.TextureSave()
76 # Select the first color output
77 texsave
.resourceId
= draw
.outputs
[0]
79 if texsave
.resourceId
== rd
.ResourceId
.Null():
82 filepath
= Path(output_dir
)
83 filepath
.mkdir(parents
=True, exist_ok
=True)
84 filepath
= filepath
/ (tracefile
+ "-" + str(int(draw
.eventId
)) + ".png")
87 filename
: str = draw
.GetName(controller
.GetStructuredFile())
88 except AttributeError:
89 filename
: str = draw
.name
91 print(f
"Saving image at event ID {draw.eventId}: {filename} to {filepath}")
93 # Most formats can only display a single image per file, so we select the
94 # first mip and first slice
96 texsave
.slice.sliceIndex
= 0
98 # For formats with an alpha channel, preserve it
99 texsave
.alpha
= rd
.AlphaMapping
.Preserve
100 texsave
.destType
= rd
.FileType
.PNG
101 controller
.SaveTexture(texsave
, str(filepath
))
104 def load_capture(filename
):
105 cap
= rd
.OpenCaptureFile()
107 status
= cap
.OpenFile(filename
, '', None)
109 if status
!= ResultCode
.Succeeded
:
110 raise RuntimeError("Couldn't open file: " + str(status
))
111 if not cap
.LocalReplaySupport():
112 raise RuntimeError("Capture cannot be replayed")
114 status
, controller
= cap
.OpenCapture(rd
.ReplayOptions(), None)
116 if status
!= ResultCode
.Succeeded
:
117 if os
.path
.exists(RENDERDOC_DEBUG_FILE
):
118 print(open(RENDERDOC_DEBUG_FILE
, "r").read())
119 raise RuntimeError("Couldn't initialise replay: " + str(status
))
121 if os
.path
.exists(RENDERDOC_DEBUG_FILE
):
122 open(RENDERDOC_DEBUG_FILE
, "w").write("")
124 return (cap
, controller
)
127 def renderdoc_dump_images(filename
, event_ids
, output_dir
):
128 rd
.InitialiseReplay(rd
.GlobalEnvironment(), [])
129 cap
, controller
= load_capture(filename
)
131 tracefile
= Path(filename
).name
135 event_ids
.append(controller
.GetRootActions()[-1].eventId
)
136 except AttributeError:
137 event_ids
.append(controller
.GetDrawcalls()[-1].eventId
)
139 for event_id
in event_ids
:
140 dump_image(controller
, event_id
, output_dir
, tracefile
)
148 parser
= argparse
.ArgumentParser()
150 parser
.add_argument('file_path',
151 help='the path to a trace file.')
152 parser
.add_argument('output_dir',
153 help='the path in which to place the results')
154 parser
.add_argument('draw_id',
156 nargs
=argparse
.REMAINDER
,
157 help=('a draw-id number from the trace to dump. '
158 'If none are provided, by default, '
159 'the last frame will be used.'))
161 args
= parser
.parse_args()
163 renderdoc_dump_images(args
.file_path
, args
.draw_id
, args
.output_dir
)
166 if __name__
== '__main__':