mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 12:18:30 +09:00
147 lines
4.9 KiB
Python
147 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Queue an exact RenderDoc frame through an Android TargetControl socket."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
import time
|
|
from typing import Any
|
|
|
|
from rdc.discover import find_renderdoc
|
|
|
|
|
|
MESSAGE_DISCONNECTED = 1
|
|
MESSAGE_NOOP = 3
|
|
MESSAGE_NEW_CAPTURE = 4
|
|
|
|
|
|
def _drain_pending_messages(target: Any) -> None:
|
|
"""Consume asynchronous registration messages before queueing a capture."""
|
|
for _ in range(20):
|
|
message = target.ReceiveMessage(None)
|
|
message_type = int(message.type)
|
|
if message_type == MESSAGE_NOOP:
|
|
return
|
|
if message_type == MESSAGE_DISCONNECTED:
|
|
raise RuntimeError("RenderDoc target disconnected during initial message drain")
|
|
|
|
|
|
def _connect(rd: Any, host: str, ident: int, timeout: float) -> Any:
|
|
deadline = time.monotonic() + timeout
|
|
last_error = "target is not listening"
|
|
while time.monotonic() < deadline:
|
|
target = None
|
|
try:
|
|
target = rd.CreateTargetControl(host, ident, "renderdoc-trace-capture", True)
|
|
if target is not None and target.Connected():
|
|
return target
|
|
last_error = "CreateTargetControl returned a disconnected target"
|
|
except Exception as exc: # noqa: BLE001 - RenderDoc raises SWIG exceptions
|
|
last_error = str(exc)
|
|
if target is not None:
|
|
target.Shutdown()
|
|
time.sleep(0.05)
|
|
raise RuntimeError(
|
|
f"failed to connect to RenderDoc target {host}:{ident} within {timeout:g}s: "
|
|
f"{last_error}"
|
|
)
|
|
|
|
|
|
def queue_capture(
|
|
*,
|
|
host: str,
|
|
ident: int,
|
|
frame: int,
|
|
count: int,
|
|
connect_timeout: float,
|
|
capture_timeout: float,
|
|
) -> dict[str, object]:
|
|
rd = find_renderdoc()
|
|
if rd is None:
|
|
raise RuntimeError("RenderDoc Python module not found; run 'rdc setup-renderdoc'")
|
|
|
|
target = _connect(rd, host, ident, connect_timeout)
|
|
started = time.monotonic()
|
|
try:
|
|
_drain_pending_messages(target)
|
|
target.QueueCapture(frame, count)
|
|
deadline = time.monotonic() + capture_timeout
|
|
while time.monotonic() < deadline:
|
|
if not target.Connected():
|
|
raise RuntimeError("RenderDoc target disconnected before capture completed")
|
|
message = target.ReceiveMessage(None)
|
|
message_type = int(message.type)
|
|
if message_type == MESSAGE_NEW_CAPTURE and message.newCapture is not None:
|
|
capture = message.newCapture
|
|
return {
|
|
"queued": True,
|
|
"host": host,
|
|
"ident": ident,
|
|
"frame": frame,
|
|
"count": count,
|
|
"elapsedSeconds": round(time.monotonic() - started, 3),
|
|
"capture": {
|
|
"captureId": capture.captureId,
|
|
"path": capture.path,
|
|
"frame": capture.frameNumber,
|
|
"byteSize": capture.byteSize,
|
|
"api": capture.api,
|
|
"local": capture.local,
|
|
},
|
|
}
|
|
if message_type == MESSAGE_DISCONNECTED:
|
|
raise RuntimeError("RenderDoc target disconnected before capture completed")
|
|
time.sleep(0.01)
|
|
raise RuntimeError(
|
|
f"timed out after {capture_timeout:g}s waiting for frame {frame} capture"
|
|
)
|
|
finally:
|
|
target.Shutdown()
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description=(
|
|
"Wait for an Android RenderDoc TargetControl socket, queue an exact frame, "
|
|
"and keep the connection alive until the RDC is complete."
|
|
)
|
|
)
|
|
parser.add_argument("--host", default="127.0.0.1")
|
|
parser.add_argument("--ident", type=int, default=38920)
|
|
parser.add_argument("--frame", type=int, required=True)
|
|
parser.add_argument("--count", type=int, default=1)
|
|
parser.add_argument("--connect-timeout", type=float, default=20.0)
|
|
parser.add_argument("--capture-timeout", type=float, default=90.0)
|
|
parser.add_argument("--json", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
result = queue_capture(
|
|
host=args.host,
|
|
ident=args.ident,
|
|
frame=args.frame,
|
|
count=args.count,
|
|
connect_timeout=args.connect_timeout,
|
|
capture_timeout=args.capture_timeout,
|
|
)
|
|
except Exception as exc: # noqa: BLE001 - convert tool failures to stable CLI output
|
|
if args.json:
|
|
print(json.dumps({"success": False, "error": str(exc)}))
|
|
else:
|
|
print(f"error: {exc}", file=sys.stderr)
|
|
return 1
|
|
|
|
if args.json:
|
|
print(json.dumps({"success": True, **result}))
|
|
else:
|
|
capture = result["capture"]
|
|
assert isinstance(capture, dict)
|
|
print(capture["path"])
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|