3 # Copyright (c) 2019 Collabora Ltd
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 # OTHER DEALINGS IN THE SOFTWARE.
23 # SPDX-License-Identifier: MIT
30 from pathlib
import Path
33 shutil
.rmtree(dirpath
)
35 dirpath
= tempfile
.mkdtemp()
36 atexit
.register(cleanup
, dirpath
)
37 RENDERDOC_DEBUG_FILE
= dirpath
+ "/renderdoc.log"
39 # Needs to be in the environment before importing the module
40 os
.environ
['RENDERDOC_DEBUG_LOG_FILE'] = RENDERDOC_DEBUG_FILE
41 import renderdoc
as rd
43 def findDrawWithEventId(controller
, eventId
):
44 for d
in controller
.GetDrawcalls():
45 if d
.eventId
== eventId
:
50 def dumpImage(controller
, eventId
, outputDir
, tracefile
):
51 draw
= findDrawWithEventId(controller
, eventId
)
53 raise RuntimeError("Couldn't find draw call with eventId " + str(eventId
))
55 controller
.SetFrameEvent(draw
.eventId
, True)
57 texsave
= rd
.TextureSave()
59 # Select the first color output
60 texsave
.resourceId
= draw
.outputs
[0]
62 if texsave
.resourceId
== rd
.ResourceId
.Null():
65 filepath
= Path(outputDir
)
66 filepath
.mkdir(parents
= True, exist_ok
= True)
67 filepath
= filepath
/ (tracefile
+ "-" + str(int(draw
.eventId
)) + ".png")
69 print("Saving image at eventId %d: %s to %s" % (draw
.eventId
, draw
.name
, filepath
))
71 # Most formats can only display a single image per file, so we select the
72 # first mip and first slice
74 texsave
.slice.sliceIndex
= 0
76 # For formats with an alpha channel, preserve it
77 texsave
.alpha
= rd
.AlphaMapping
.Preserve
78 texsave
.destType
= rd
.FileType
.PNG
79 controller
.SaveTexture(texsave
, str(filepath
))
81 def loadCapture(filename
):
82 cap
= rd
.OpenCaptureFile()
84 status
= cap
.OpenFile(filename
, '', None)
86 if status
!= rd
.ReplayStatus
.Succeeded
:
87 raise RuntimeError("Couldn't open file: " + str(status
))
88 if not cap
.LocalReplaySupport():
89 raise RuntimeError("Capture cannot be replayed")
91 status
, controller
= cap
.OpenCapture(rd
.ReplayOptions(), None)
93 if status
!= rd
.ReplayStatus
.Succeeded
:
94 if os
.path
.exists(RENDERDOC_DEBUG_FILE
):
95 print(open(RENDERDOC_DEBUG_FILE
, "r").read())
96 raise RuntimeError("Couldn't initialise replay: " + str(status
))
98 if os
.path
.exists(RENDERDOC_DEBUG_FILE
):
99 open(RENDERDOC_DEBUG_FILE
, "w").write("")
101 return (cap
, controller
)
103 def renderdoc_dump_images(filename
, eventIds
, outputDir
):
104 rd
.InitialiseReplay(rd
.GlobalEnvironment(), [])
105 cap
, controller
= loadCapture(filename
);
107 tracefile
= Path(filename
).name
109 if len(eventIds
) == 0:
110 eventIds
.append(controller
.GetDrawcalls()[-1].eventId
)
112 for eventId
in eventIds
:
113 dumpImage(controller
, eventId
, outputDir
, tracefile
)
115 controller
.Shutdown()
120 if __name__
== "__main__":
121 if len(sys
.argv
) < 3:
122 raise RuntimeError("Usage: renderdoc_dump_images.py <trace> <outputdir> [<draw-id>...]")
124 eventIds
= [int(e
) for e
in sys
.argv
[3:]]
126 renderdoc_dump_images(sys
.argv
[1], eventIds
, sys
.argv
[2])