dcc-mcp-renderdoc 0.3.1__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dcc_mcp_renderdoc-0.3.3/.release-please-manifest.json +2 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/CHANGELOG.md +20 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/PKG-INFO +23 -12
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/README.md +22 -11
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/pyproject.toml +1 -1
- dcc_mcp_renderdoc-0.3.3/src/dcc_mcp_renderdoc/__version__.py +3 -0
- dcc_mcp_renderdoc-0.3.3/src/dcc_mcp_renderdoc/_target_control.py +185 -0
- dcc_mcp_renderdoc-0.3.3/src/dcc_mcp_renderdoc/runtime.py +751 -0
- dcc_mcp_renderdoc-0.3.3/src/dcc_mcp_renderdoc/skills/renderdoc-capture/SKILL.md +40 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-capture/tools.yaml +2 -2
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tests/live_renderdoc_smoke.py +18 -4
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tests/renderdoc_smoke.c +11 -10
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tests/test_package.py +1 -0
- dcc_mcp_renderdoc-0.3.3/tests/test_runtime.py +1686 -0
- dcc_mcp_renderdoc-0.3.1/.release-please-manifest.json +0 -2
- dcc_mcp_renderdoc-0.3.1/src/dcc_mcp_renderdoc/__version__.py +0 -3
- dcc_mcp_renderdoc-0.3.1/src/dcc_mcp_renderdoc/runtime.py +0 -510
- dcc_mcp_renderdoc-0.3.1/src/dcc_mcp_renderdoc/skills/renderdoc-capture/SKILL.md +0 -30
- dcc_mcp_renderdoc-0.3.1/tests/test_runtime.py +0 -267
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/.gitignore +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/LICENSE +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/release-please-config.json +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/__init__.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/server.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/SKILL.md +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/metadata/depends.md +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/scripts/export_thumbnail.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/scripts/export_timeline.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/scripts/inspect_capture.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-analysis/tools.yaml +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-capture/metadata/depends.md +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-capture/scripts/capture_process.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-capture/scripts/capture_program.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/src/dcc_mcp_renderdoc/skills/renderdoc-capture/scripts/get_version.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tests/test_download.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tools/__init__.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tools/download_latest_renderdoc.py +0 -0
- {dcc_mcp_renderdoc-0.3.1 → dcc_mcp_renderdoc-0.3.3}/tools/lint_skills.py +0 -0
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.3](https://github.com/dcc-mcp/dcc-mcp-renderdoc/compare/v0.3.2...v0.3.3) (2026-07-22)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* accept POSIX target ident exit status ([e35d14e](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/e35d14ed7dfdd429f5356ac8a5d5a98411a9dc28))
|
|
9
|
+
* harden target control lifecycle ([1a1eca8](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/1a1eca82fb453ec40b11a33791160d6074e70a6f))
|
|
10
|
+
* isolate target control sidecar ([2e16b2b](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/2e16b2b009c76136a5ad2889c4943c458401923a))
|
|
11
|
+
* normalize target names across platforms ([44602a0](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/44602a0fca3fd2749688f56f169280d18ddcb989))
|
|
12
|
+
* trigger captures through RenderDoc Target Control ([68d93aa](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/68d93aa9c0629b61cac75275ca53a55a65f29729))
|
|
13
|
+
* trigger captures through target control ([f0a11c8](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/f0a11c844a5597c0ae6b022a8ec07c32d7a15806))
|
|
14
|
+
* verify target before capture trigger ([a392e9f](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/a392e9fc974152d5d2dc183c1ed8b60ed15c2195))
|
|
15
|
+
|
|
16
|
+
## [0.3.2](https://github.com/dcc-mcp/dcc-mcp-renderdoc/compare/v0.3.1...v0.3.2) (2026-07-22)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* keep capture controller alive through trigger ([#11](https://github.com/dcc-mcp/dcc-mcp-renderdoc/issues/11)) ([1fb7bed](https://github.com/dcc-mcp/dcc-mcp-renderdoc/commit/1fb7bed40dfb027b148a14cefd01c53028891d56))
|
|
22
|
+
|
|
3
23
|
## [0.3.1](https://github.com/dcc-mcp/dcc-mcp-renderdoc/compare/v0.3.0...v0.3.1) (2026-07-22)
|
|
4
24
|
|
|
5
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dcc-mcp-renderdoc
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: RenderDoc capture and replay automation skills for DCC-MCP
|
|
5
5
|
Project-URL: Homepage, https://github.com/dcc-mcp/dcc-mcp-renderdoc
|
|
6
6
|
Project-URL: Repository, https://github.com/dcc-mcp/dcc-mcp-renderdoc
|
|
@@ -78,8 +78,8 @@ attach a stable session id with `--meta-json`, query `dcc-mcp-cli stats --range
|
|
|
78
78
|
RenderDoc capture and replay automation for the DCC Model Context Protocol ecosystem.
|
|
79
79
|
|
|
80
80
|
The adapter is headless-first: it reuses the official `renderdoccmd` executable for capture and
|
|
81
|
-
conversion
|
|
82
|
-
|
|
81
|
+
conversion. Delayed capture uses RenderDoc's official Target Control API through the sibling
|
|
82
|
+
`qrenderdoc` bundled Python runtime, without foreground focus or synthetic keyboard input.
|
|
83
83
|
|
|
84
84
|
## Install
|
|
85
85
|
|
|
@@ -103,8 +103,8 @@ through the stable gateway at `http://127.0.0.1:9765/mcp`; set
|
|
|
103
103
|
## Agent workflows
|
|
104
104
|
|
|
105
105
|
- Launch a game or test executable under RenderDoc and wait for a typed `.rdc` capture.
|
|
106
|
-
- Trigger
|
|
107
|
-
- Inject into a
|
|
106
|
+
- Trigger a capture through official Target Control after a configurable delay.
|
|
107
|
+
- Inject into a process that had to be launched by a platform client, then trigger and collect a capture.
|
|
108
108
|
- Inspect capture driver, machine identity, chunk version, API-call counts, and representative calls.
|
|
109
109
|
- Export a capture thumbnail for visual review.
|
|
110
110
|
- Export Chrome trace JSON for timeline tooling.
|
|
@@ -112,16 +112,27 @@ through the stable gateway at `http://127.0.0.1:9765/mcp`; set
|
|
|
112
112
|
The capture tool launches only the explicit executable and arguments supplied by the caller. It
|
|
113
113
|
never invokes a shell. Analysis tools are read-only with respect to the `.rdc` input.
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
Pass `trigger_after_secs` to `capture_program` for a Target Control trigger. This requires
|
|
116
|
+
`qrenderdoc` beside `renderdoccmd`. The official RenderDoc runtime supports Windows and Linux;
|
|
117
|
+
macOS is covered only by this project's Python unit tests. Linux Target Control requires an X or
|
|
118
|
+
Wayland display, so headless hosts must run under Xvfb (or explicitly configure a working Qt
|
|
119
|
+
platform). The official Linux archive does not bundle Qt's `offscreen` platform plugin. Each
|
|
120
|
+
sidecar uses an isolated Qt data profile with RenderDoc analytics explicitly opted out, preventing
|
|
121
|
+
the first-run consent dialog without reading or changing the user's qrenderdoc configuration.
|
|
122
|
+
|
|
123
|
+
When a launcher creates the rendered child process, set `hook_children=true` and pass
|
|
124
|
+
`trigger_process_name`. The adapter first checks the launched target itself; if its name does not
|
|
125
|
+
match, it follows only that target's official `NewChild` messages to find a unique named child. A
|
|
126
|
+
child name without child hooking fails before launch. Use `capture_process` only when the target is
|
|
127
|
+
already running; late injection may not capture graphics devices created before RenderDoc was
|
|
128
|
+
attached.
|
|
119
129
|
|
|
120
130
|
## Real CI
|
|
121
131
|
|
|
122
|
-
CI discovers the current stable RenderDoc build from the official downloads page. It
|
|
123
|
-
small OpenGL program,
|
|
124
|
-
|
|
132
|
+
CI discovers the current stable Linux RenderDoc build from the official downloads page. It
|
|
133
|
+
compiles a small OpenGL program, requests a real frame through Target Control under Xvfb using
|
|
134
|
+
Qt's bundled `xcb` platform, asserts the structured trigger mode, calls the MCP analysis tool
|
|
135
|
+
against the resulting `.rdc`, and verifies thumbnail and timeline exports.
|
|
125
136
|
|
|
126
137
|
## Development
|
|
127
138
|
|
|
@@ -50,8 +50,8 @@ attach a stable session id with `--meta-json`, query `dcc-mcp-cli stats --range
|
|
|
50
50
|
RenderDoc capture and replay automation for the DCC Model Context Protocol ecosystem.
|
|
51
51
|
|
|
52
52
|
The adapter is headless-first: it reuses the official `renderdoccmd` executable for capture and
|
|
53
|
-
conversion
|
|
54
|
-
|
|
53
|
+
conversion. Delayed capture uses RenderDoc's official Target Control API through the sibling
|
|
54
|
+
`qrenderdoc` bundled Python runtime, without foreground focus or synthetic keyboard input.
|
|
55
55
|
|
|
56
56
|
## Install
|
|
57
57
|
|
|
@@ -75,8 +75,8 @@ through the stable gateway at `http://127.0.0.1:9765/mcp`; set
|
|
|
75
75
|
## Agent workflows
|
|
76
76
|
|
|
77
77
|
- Launch a game or test executable under RenderDoc and wait for a typed `.rdc` capture.
|
|
78
|
-
- Trigger
|
|
79
|
-
- Inject into a
|
|
78
|
+
- Trigger a capture through official Target Control after a configurable delay.
|
|
79
|
+
- Inject into a process that had to be launched by a platform client, then trigger and collect a capture.
|
|
80
80
|
- Inspect capture driver, machine identity, chunk version, API-call counts, and representative calls.
|
|
81
81
|
- Export a capture thumbnail for visual review.
|
|
82
82
|
- Export Chrome trace JSON for timeline tooling.
|
|
@@ -84,16 +84,27 @@ through the stable gateway at `http://127.0.0.1:9765/mcp`; set
|
|
|
84
84
|
The capture tool launches only the explicit executable and arguments supplied by the caller. It
|
|
85
85
|
never invokes a shell. Analysis tools are read-only with respect to the `.rdc` input.
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
Pass `trigger_after_secs` to `capture_program` for a Target Control trigger. This requires
|
|
88
|
+
`qrenderdoc` beside `renderdoccmd`. The official RenderDoc runtime supports Windows and Linux;
|
|
89
|
+
macOS is covered only by this project's Python unit tests. Linux Target Control requires an X or
|
|
90
|
+
Wayland display, so headless hosts must run under Xvfb (or explicitly configure a working Qt
|
|
91
|
+
platform). The official Linux archive does not bundle Qt's `offscreen` platform plugin. Each
|
|
92
|
+
sidecar uses an isolated Qt data profile with RenderDoc analytics explicitly opted out, preventing
|
|
93
|
+
the first-run consent dialog without reading or changing the user's qrenderdoc configuration.
|
|
94
|
+
|
|
95
|
+
When a launcher creates the rendered child process, set `hook_children=true` and pass
|
|
96
|
+
`trigger_process_name`. The adapter first checks the launched target itself; if its name does not
|
|
97
|
+
match, it follows only that target's official `NewChild` messages to find a unique named child. A
|
|
98
|
+
child name without child hooking fails before launch. Use `capture_process` only when the target is
|
|
99
|
+
already running; late injection may not capture graphics devices created before RenderDoc was
|
|
100
|
+
attached.
|
|
91
101
|
|
|
92
102
|
## Real CI
|
|
93
103
|
|
|
94
|
-
CI discovers the current stable RenderDoc build from the official downloads page. It
|
|
95
|
-
small OpenGL program,
|
|
96
|
-
|
|
104
|
+
CI discovers the current stable Linux RenderDoc build from the official downloads page. It
|
|
105
|
+
compiles a small OpenGL program, requests a real frame through Target Control under Xvfb using
|
|
106
|
+
Qt's bundled `xcb` platform, asserts the structured trigger mode, calls the MCP analysis tool
|
|
107
|
+
against the resulting `.rdc`, and verifies thumbnail and timeline exports.
|
|
97
108
|
|
|
98
109
|
## Development
|
|
99
110
|
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""RenderDoc 1.45 bundled-Python bridge for headless Target Control capture."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _positive_int(name):
|
|
9
|
+
value = int(os.environ[name])
|
|
10
|
+
if value <= 0:
|
|
11
|
+
raise ValueError("{} must be positive".format(name))
|
|
12
|
+
return value
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _nonnegative_float(name):
|
|
16
|
+
value = float(os.environ[name])
|
|
17
|
+
if value < 0:
|
|
18
|
+
raise ValueError("{} must not be negative".format(name))
|
|
19
|
+
return value
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _open_target(rd, ident):
|
|
23
|
+
target = rd.CreateTargetControl("", ident, "dcc-mcp-renderdoc", False)
|
|
24
|
+
if target is None:
|
|
25
|
+
raise RuntimeError("RenderDoc target ident {} is busy or unavailable".format(ident))
|
|
26
|
+
if not target.Connected():
|
|
27
|
+
busy_client = target.GetBusyClient()
|
|
28
|
+
detail = " (busy client: {})".format(busy_client) if busy_client else ""
|
|
29
|
+
target.Shutdown()
|
|
30
|
+
raise RuntimeError("could not connect to RenderDoc target ident {}{}".format(ident, detail))
|
|
31
|
+
return target
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _target_name_matches(actual, expected):
|
|
35
|
+
actual = str(actual).replace("\\", "/").rsplit("/", 1)[-1].casefold()
|
|
36
|
+
expected = str(expected).replace("\\", "/").rsplit("/", 1)[-1].casefold()
|
|
37
|
+
return (
|
|
38
|
+
actual == expected
|
|
39
|
+
or (actual.endswith(".exe") and actual[:-4] == expected)
|
|
40
|
+
or (expected.endswith(".exe") and expected[:-4] == actual)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _wait_for_child_target(rd, parent, target_name, trigger_at, deadline):
|
|
45
|
+
matches = []
|
|
46
|
+
quiet_deadline = None
|
|
47
|
+
try:
|
|
48
|
+
while time.monotonic() < deadline:
|
|
49
|
+
now = time.monotonic()
|
|
50
|
+
if (
|
|
51
|
+
len(matches) == 1
|
|
52
|
+
and quiet_deadline is not None
|
|
53
|
+
and now >= trigger_at
|
|
54
|
+
and now >= quiet_deadline
|
|
55
|
+
):
|
|
56
|
+
return matches.pop()
|
|
57
|
+
message = parent.ReceiveMessage(None)
|
|
58
|
+
if message is not None and message.type == rd.TargetControlMessageType.NewChild:
|
|
59
|
+
child_ident = int(message.newChild.ident)
|
|
60
|
+
child_pid = int(message.newChild.processId)
|
|
61
|
+
child = _open_target(rd, child_ident)
|
|
62
|
+
try:
|
|
63
|
+
if int(child.GetPID()) != child_pid:
|
|
64
|
+
raise RuntimeError(
|
|
65
|
+
"RenderDoc child target PID did not match NewChild message"
|
|
66
|
+
)
|
|
67
|
+
if _target_name_matches(child.GetTarget(), target_name):
|
|
68
|
+
matches.append(child)
|
|
69
|
+
child = None
|
|
70
|
+
finally:
|
|
71
|
+
if child is not None:
|
|
72
|
+
child.Shutdown()
|
|
73
|
+
if matches:
|
|
74
|
+
if len(matches) > 1:
|
|
75
|
+
raise RuntimeError("multiple child targets matched {}".format(target_name))
|
|
76
|
+
quiet_deadline = time.monotonic() + 0.25
|
|
77
|
+
if quiet_deadline > deadline:
|
|
78
|
+
raise RuntimeError("insufficient time to select a unique child target")
|
|
79
|
+
continue
|
|
80
|
+
if message is not None and message.type == rd.TargetControlMessageType.Disconnected:
|
|
81
|
+
if len(matches) == 1:
|
|
82
|
+
return matches.pop()
|
|
83
|
+
raise RuntimeError("RenderDoc parent Target Control disconnected before child")
|
|
84
|
+
for match in matches:
|
|
85
|
+
child_message = match.ReceiveMessage(None)
|
|
86
|
+
if (
|
|
87
|
+
child_message is not None
|
|
88
|
+
and child_message.type == rd.TargetControlMessageType.Disconnected
|
|
89
|
+
):
|
|
90
|
+
raise RuntimeError("RenderDoc child Target Control disconnected before trigger")
|
|
91
|
+
time.sleep(0.05)
|
|
92
|
+
if len(matches) == 1:
|
|
93
|
+
raise RuntimeError("insufficient time to select a unique child target")
|
|
94
|
+
raise RuntimeError("no child target matched {}".format(target_name))
|
|
95
|
+
finally:
|
|
96
|
+
for match in matches:
|
|
97
|
+
match.Shutdown()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _pump_until(rd, target, deadline):
|
|
101
|
+
while time.monotonic() < deadline:
|
|
102
|
+
message = target.ReceiveMessage(None)
|
|
103
|
+
if message is not None and message.type == rd.TargetControlMessageType.Disconnected:
|
|
104
|
+
raise RuntimeError("RenderDoc Target Control disconnected before trigger")
|
|
105
|
+
time.sleep(0.05)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def main():
|
|
109
|
+
status_path = os.environ.get("DCC_MCP_RENDERDOC_TARGET_STATUS")
|
|
110
|
+
status = {
|
|
111
|
+
"schema_version": 1,
|
|
112
|
+
"connected": False,
|
|
113
|
+
"triggered": False,
|
|
114
|
+
"shutdown": False,
|
|
115
|
+
"timed_out": False,
|
|
116
|
+
"target_pid": None,
|
|
117
|
+
"capture_path": None,
|
|
118
|
+
"error": None,
|
|
119
|
+
}
|
|
120
|
+
target = None
|
|
121
|
+
try:
|
|
122
|
+
import renderdoc as rd
|
|
123
|
+
|
|
124
|
+
ident = _positive_int("DCC_MCP_RENDERDOC_TARGET_IDENT")
|
|
125
|
+
capture_wait_secs = _positive_int("DCC_MCP_RENDERDOC_TARGET_TIMEOUT_SECS")
|
|
126
|
+
trigger_after_secs = _nonnegative_float("DCC_MCP_RENDERDOC_TRIGGER_AFTER_SECS")
|
|
127
|
+
target_name = os.environ.get("DCC_MCP_RENDERDOC_TARGET_NAME", "").strip()
|
|
128
|
+
expected_pid_value = os.environ.get("DCC_MCP_RENDERDOC_EXPECTED_PID", "").strip()
|
|
129
|
+
expected_pid = int(expected_pid_value) if expected_pid_value else None
|
|
130
|
+
if expected_pid is not None and expected_pid <= 0:
|
|
131
|
+
raise ValueError("DCC_MCP_RENDERDOC_EXPECTED_PID must be positive")
|
|
132
|
+
trigger_at = time.monotonic() + trigger_after_secs
|
|
133
|
+
capture_deadline = trigger_at + capture_wait_secs
|
|
134
|
+
target = _open_target(rd, ident)
|
|
135
|
+
if target_name and not _target_name_matches(target.GetTarget(), target_name):
|
|
136
|
+
child = _wait_for_child_target(rd, target, target_name, trigger_at, capture_deadline)
|
|
137
|
+
try:
|
|
138
|
+
target.Shutdown()
|
|
139
|
+
except BaseException:
|
|
140
|
+
child.Shutdown()
|
|
141
|
+
raise
|
|
142
|
+
target = child
|
|
143
|
+
status["connected"] = True
|
|
144
|
+
status["target_pid"] = int(target.GetPID())
|
|
145
|
+
if expected_pid is not None and status["target_pid"] != expected_pid:
|
|
146
|
+
raise RuntimeError(
|
|
147
|
+
"RenderDoc target PID {} did not match expected PID {}".format(
|
|
148
|
+
status["target_pid"], expected_pid
|
|
149
|
+
)
|
|
150
|
+
)
|
|
151
|
+
_pump_until(rd, target, trigger_at)
|
|
152
|
+
target.TriggerCapture(1)
|
|
153
|
+
status["triggered"] = True
|
|
154
|
+
while time.monotonic() < capture_deadline:
|
|
155
|
+
message = target.ReceiveMessage(None)
|
|
156
|
+
if message is not None and message.type == rd.TargetControlMessageType.NewCapture:
|
|
157
|
+
status["capture_path"] = str(message.newCapture.path)
|
|
158
|
+
break
|
|
159
|
+
if message is not None and message.type == rd.TargetControlMessageType.Disconnected:
|
|
160
|
+
raise RuntimeError("RenderDoc Target Control disconnected before capture")
|
|
161
|
+
time.sleep(0.05)
|
|
162
|
+
if status["capture_path"] is None:
|
|
163
|
+
status["timed_out"] = True
|
|
164
|
+
raise RuntimeError("timed out waiting for RenderDoc NewCapture")
|
|
165
|
+
except BaseException as exc:
|
|
166
|
+
status["error"] = str(exc)
|
|
167
|
+
finally:
|
|
168
|
+
if target is not None:
|
|
169
|
+
try:
|
|
170
|
+
target.Shutdown()
|
|
171
|
+
status["shutdown"] = True
|
|
172
|
+
target = None
|
|
173
|
+
except BaseException as exc:
|
|
174
|
+
status["error"] = status["error"] or ("Target Control shutdown failed: " + str(exc))
|
|
175
|
+
if status_path:
|
|
176
|
+
with open(status_path, "w") as status_file:
|
|
177
|
+
json.dump(status, status_file)
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
if __name__ == "__main__":
|
|
181
|
+
try:
|
|
182
|
+
main()
|
|
183
|
+
except BaseException:
|
|
184
|
+
pass
|
|
185
|
+
raise SystemExit(0)
|