mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-08 08:40:55 +00:00
Add an abstracted interface around android-specific handling
* This makes it easier to use the same kind of interface to manage other kinds of devices.
This commit is contained in:
@@ -31,4 +31,5 @@ In order to help with this, the examples are organised such that most code is wr
|
||||
fetch_counters
|
||||
save_texture
|
||||
decode_mesh
|
||||
display_window
|
||||
display_window
|
||||
remote_capture
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
import renderdoc as rd
|
||||
import threading
|
||||
import time
|
||||
|
||||
# This sample is intended as an example of how to do remote capture and replay
|
||||
# as well as using device protocols to automatically enumerate remote targets.
|
||||
#
|
||||
# It is not complete since it requires filling in with custom logic to select
|
||||
# the executable and trigger the capture at the desired time
|
||||
raise RuntimeError("This sample should not be run directly, read the source")
|
||||
|
||||
protocols = rd.GetSupportedDeviceProtocols()
|
||||
|
||||
print(f"Supported device protocols: {protocols}")
|
||||
|
||||
# Protocols are optional - they allow automatic detection and management of
|
||||
# devices.
|
||||
if protocol_to_use is not None:
|
||||
# the protocol must be supported
|
||||
if protocol_to_use not in protocols:
|
||||
raise RuntimeError(f"{protocol_to_use} protocol not supported")
|
||||
|
||||
protocol = rd.GetDeviceProtocolController(protocol_to_use)
|
||||
|
||||
devices = protocol.GetDevices()
|
||||
|
||||
if len(devices) == 0:
|
||||
raise RuntimeError(f"no {protocol_to_use} devices connected")
|
||||
|
||||
# Choose the first device
|
||||
dev = devices[0]
|
||||
name = protocol.GetFriendlyName(dev)
|
||||
|
||||
print(f"Running test on {dev} - named {name}")
|
||||
|
||||
URL = protocol.GetProtocolName() + "://" + dev
|
||||
|
||||
# Protocols can enumerate devices which are not supported. Capture/replay
|
||||
# is not guaranteed to work on these devices
|
||||
if not protocol.IsSupported(URL):
|
||||
raise RuntimeError(f"{dev} doesn't support capture/replay - too old?")
|
||||
|
||||
# Protocol devices may be single-use and not support multiple captured programs
|
||||
# If so, trying to execute a program for capture is an error
|
||||
if not protocol.SupportsMultiplePrograms(URL):
|
||||
# check to see if anything is running. Just use the URL
|
||||
ident = rd.EnumerateRemoteTargets(URL, 0)
|
||||
|
||||
if ident != 0:
|
||||
raise RuntimeError(f"{name} already has a program running on {ident}")
|
||||
else:
|
||||
# If you're not using a protocol then the URL can simply be a hostname.
|
||||
# The remote server must be running already - how that is done is up
|
||||
# to you. Everything else will work the same over a normal TCP connection
|
||||
protocol = None
|
||||
URL = hostname
|
||||
|
||||
# Let's try to connect
|
||||
status,remote = rd.CreateRemoteServerConnection(URL)
|
||||
|
||||
if status == rd.ReplayStatus.NetworkIOFailed and protocol is not None:
|
||||
# If there's just no I/O, most likely the server is not running. If we have
|
||||
# a protocol, we can try to start the remote server
|
||||
print("Couldn't connect to remote server, trying to start it")
|
||||
|
||||
status = protocol.StartRemoteServer(URL)
|
||||
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
raise RuntimeError(f"Couldn't launch remote server, got error {str(status)}")
|
||||
|
||||
# Try to connect again!
|
||||
status,remote = rd.CreateRemoteServerConnection(URL)
|
||||
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
raise RuntimeError(f"Couldn't connect to remote server, got error {str(status)}")
|
||||
|
||||
# We now have a remote connection. This works regardless of whether it's a device
|
||||
# with a protocol or not. In fact we are done with the protocol at this point
|
||||
protocol = None
|
||||
|
||||
print("Got connection to remote server")
|
||||
|
||||
# GetHomeFolder() gives you a good default path to start with.
|
||||
# ListFolder() lists the contents of a folder and can recursively
|
||||
# browse the remote filesystem.
|
||||
home = remote.GetHomeFolder()
|
||||
paths = remote.ListFolder(home)
|
||||
|
||||
print(f"Executables in home folder '{home}':")
|
||||
|
||||
for p in paths:
|
||||
print(" - " + p.filename)
|
||||
|
||||
# Select your executable, perhaps hardcoded or browsing using the above
|
||||
# functions
|
||||
exe,workingDir,cmdLine,env,opts = select_executable()
|
||||
|
||||
print(f"Running {exe}")
|
||||
|
||||
result = remote.ExecuteAndInject(exe, workingDir, cmdLine, env, opts)
|
||||
|
||||
if result.status != rd.ReplayStatus.Succeeded:
|
||||
remote.ShutdownServerAndConnection()
|
||||
raise RuntimeError(f"Couldn't launch {exe}, got error {str(result.status)}")
|
||||
|
||||
# Spin up a thread to keep the remote server connection alive while we make a capture,
|
||||
# as it will time out after 5 seconds of inactivity
|
||||
def ping_remote(remote, kill):
|
||||
success = True
|
||||
while success and not kill.is_set():
|
||||
success = remote.Ping()
|
||||
time.sleep(1)
|
||||
|
||||
kill = threading.Event()
|
||||
ping_thread = threading.Thread(target=ping_remote, args=(remote,kill))
|
||||
ping_thread.start()
|
||||
|
||||
# Create target control connection
|
||||
target = rd.CreateTargetControl(URL, result.ident, 'remote_capture.py', True)
|
||||
|
||||
if target is None:
|
||||
kill.set()
|
||||
ping_thread.join()
|
||||
remote.ShutdownServerAndConnection()
|
||||
raise RuntimeError(f"Couldn't connect to target control for {exe}")
|
||||
|
||||
print("Connected - waiting for desired capture")
|
||||
|
||||
# Wait for the capture condition we want
|
||||
capture_condition()
|
||||
|
||||
print("Triggering capture")
|
||||
|
||||
target.TriggerCapture(1)
|
||||
|
||||
# Pump messages, keep waiting until we get a capture message. Time out after 30 seconds
|
||||
msg = None
|
||||
start = time.clock()
|
||||
while msg is None or msg.type != rd.TargetControlMessageType.NewCapture:
|
||||
msg = target.ReceiveMessage(None)
|
||||
|
||||
if time.clock() - start > 30:
|
||||
break
|
||||
|
||||
# Close the target connection, we're done either way
|
||||
target.Shutdown()
|
||||
target = None
|
||||
|
||||
# Stop the background ping thread
|
||||
kill.set()
|
||||
ping_thread.join()
|
||||
|
||||
# If we didn't get a capture, error now
|
||||
if msg.type != rd.TargetControlMessageType.NewCapture:
|
||||
remote.ShutdownServerAndConnection()
|
||||
raise RuntimeError("Didn't get new capture notification after triggering capture")
|
||||
|
||||
cap_path = msg.newCapture.path
|
||||
cap_id = msg.newCapture.captureId
|
||||
|
||||
print(f"Got new capture at {cap_path} which is frame {msg.newCapture.frameNumber} with {msg.newCapture.api}")
|
||||
|
||||
# We could save the capture locally
|
||||
# remote.CopyCaptureFromRemote(cap_path, local_path, None)
|
||||
|
||||
|
||||
# Open a replay. It's recommended to set no proxy preference, but you could
|
||||
# call remote.LocalProxies and choose an index.
|
||||
#
|
||||
# The path must be remote - if the capture isn't freshly created then you need
|
||||
# to copy it with remote.CopyCaptureToRemote()
|
||||
status,controller = remote.OpenCapture(rd.RemoteServer.NoPreference, cap_path, None)
|
||||
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
remote.ShutdownServerAndConnection()
|
||||
raise RuntimeError(f"Couldn't open {cap_path}, got error {str(result.status)}")
|
||||
|
||||
# We can now use replay as normal.
|
||||
#
|
||||
# The replay is tunnelled over the remote connection, so you don't have to keep
|
||||
# pinging the remote connection while using the controller. Use of the remote
|
||||
# connection and controller can be interleaved though you should only access
|
||||
# them from one thread at once. If they are both unused for 5 seconds though,
|
||||
# the timeout will happen, so if the controller is idle it's advisable to ping
|
||||
# the remote connection
|
||||
|
||||
sampleCode(controller)
|
||||
|
||||
print("Shutting down")
|
||||
|
||||
controller.Shutdown()
|
||||
|
||||
# We can still use remote here - e.g. capture again, replay something else,
|
||||
# save the capture, etc
|
||||
|
||||
remote.ShutdownServerAndConnection()
|
||||
@@ -0,0 +1,118 @@
|
||||
Remote Capture and Replay
|
||||
=========================
|
||||
|
||||
This example is a bit different since it's not ready-to-run. It provides a template for how you can capture and replay on a remote machine, instead of the local machine. It also shows how to use device protocols to automatically manage devices.
|
||||
|
||||
First we can enumerate which device protocols are currently supported.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
protocols = rd.GetSupportedDeviceProtocols()
|
||||
|
||||
Each string in the list corresponds to a protocol that can be used for managing devices. If we're using one we can call :py:func:`~renderdoc.GetDeviceProtocolController` passing the protocol name and retrieve the controller.
|
||||
|
||||
The controller provides a few methods for managing devices. First we can call :py:meth:`~renderdoc.DeviceProtocolController.GetDevices` to return a list of device IDs. The format of these device IDs is protocol-dependent but will be equivalent to a normal hostname. Devices may have human-readable names obtainable via :py:meth:`~renderdoc.DeviceProtocolController.GetFriendlyName`.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
protocol = rd.GetDeviceProtocolController(protocol_to_use)
|
||||
|
||||
devices = protocol.GetDevices()
|
||||
|
||||
if len(devices) == 0:
|
||||
raise RuntimeError(f"no {protocol_to_use} devices connected")
|
||||
|
||||
# Choose the first device
|
||||
dev = devices[0]
|
||||
name = protocol.GetFriendlyName(dev)
|
||||
|
||||
print(f"Running test on {dev} - named {name}")
|
||||
|
||||
URL = protocol.GetProtocolName() + "://" + dev
|
||||
|
||||
The URL will be used the same as we would use a hostname, when connecting for target control or remote servers.
|
||||
|
||||
Note that protocols may have additional restrictions - be sure to check :py:meth:`~renderdoc.DeviceProtocolController.IsSupported` to check if the device is expected to function at all, and :py:meth:`~renderdoc.DeviceProtocolController.SupportsMultiplePrograms` to see if it supports launching multiple programs. If multiple programs are not supported, you should ensure all running capturable programs are closed before launching a new one.
|
||||
|
||||
To begin with we create a remote server connection using :py:func:`~renderdoc.CreateRemoteServerConnection`. The URL is as constructed above for protocol-based connections, or a simple hostname/IP if we're connecting directly to remote machine.
|
||||
|
||||
If the connection fails, normally we must fail but if we have a device protocol available we can attempt to launch the remote server automatically using :py:meth:`~renderdoc.DeviceProtocolController.StartRemoteServer`.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
if status == rd.ReplayStatus.NetworkIOFailed and protocol is not None:
|
||||
# If there's just no I/O, most likely the server is not running. If we have
|
||||
# a protocol, we can try to start the remote server
|
||||
print("Couldn't connect to remote server, trying to start it")
|
||||
|
||||
status = protocol.StartRemoteServer(URL)
|
||||
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
raise RuntimeError(f"Couldn't launch remote server, got error {str(status)}")
|
||||
|
||||
# Try to connect again!
|
||||
status,remote = rd.CreateRemoteServerConnection(URL)
|
||||
|
||||
.. note::
|
||||
|
||||
The remote server connection has a default timeout of 5 seconds. If the connection is unused for 5 seconds, the other side will disconnect and subsequent use of the interface will fail.
|
||||
|
||||
Once we have a remote server connection, we can browse the remote filesystem for the executable we want to launch using :py:meth:`~renderdoc.RemoteServer.GetHomeFolder` and :py:meth:`~renderdoc.RemoteServer.ListFolder`.
|
||||
|
||||
Then once we've selected the executable, we can launch the remote program for capturing with :py:meth:`~renderdoc.RemoteServer.ExecuteAndInject`. This function is almost identical to the local :py:func:`~renderdoc.ExecuteAndInject` except that it is not possible to wait for the program to exit.
|
||||
|
||||
In our sample, we now place the remote server connection on a background thread that will ping it each second to keep the connection alive while we use a target control connection to trigger a capture in the application.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
def ping_remote(remote, kill):
|
||||
success = True
|
||||
while success and not kill.is_set():
|
||||
success = remote.Ping()
|
||||
time.sleep(1)
|
||||
|
||||
kill = threading.Event()
|
||||
ping_thread = threading.Thread(target=ping_remote, args=(remote,kill))
|
||||
ping_thread.start()
|
||||
|
||||
To connect to and control an application we use :py:func:`~renderdoc.CreateTargetControl` with the URL as before and the ident returned from :py:meth:`~renderdoc.RemoteServer.ExecuteAndInject`.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
target = rd.CreateTargetControl(URL, result.ident, 'remote_capture.py', True)
|
||||
|
||||
# Here we wait for whichever condition you want
|
||||
target.TriggerCapture(1)
|
||||
|
||||
There are a couple of ways to trigger a capture, both :py:meth:`~renderdoc.TargetControl.TriggerCapture` and :py:meth:`~renderdoc.TargetControl.QueueCapture` depending on whether you want a time-based or frame-based trigger. The application itself can also use the in-application API to trigger a capture.
|
||||
|
||||
The target control connection can be intermittently polled for messages using :py:meth:`~renderdoc.TargetControl.ReceiveMessage`, which keeps the connection alive and will return any new information such as the data for a new capture that has been created. A message of type :py:data:`~renderdoc.TargetControlMessageType.NewCapture` indicates a new capture has been created, and :py:data:`~renderdoc.TargetControlMessage.newCapture` contains the information including the path.
|
||||
|
||||
.. highlight:: python
|
||||
.. code:: python
|
||||
|
||||
msg = target.ReceiveMessage(None)
|
||||
|
||||
# Once msg.type == rd.TargetControlMessageType.NewCapture has been retrieved
|
||||
|
||||
cap_path = msg.newCapture.path
|
||||
cap_id = msg.newCapture.captureId
|
||||
|
||||
Once the capture has been found we are finished with the target control connection so we can shut it down and stop the background thread that was keeping the remote server connection alive. Using the remote server connection we can copy the capture back to the local machine with :py:meth:`~renderdoc.RemoteServer.CopyCaptureFromRemote`. Similarly if we wanted to load a previously made capture that wasn't on the remote machine :py:meth:`~renderdoc.RemoteServer.CopyCaptureToRemote` would be useful to copy it ready to be opened.
|
||||
|
||||
Finally to open the capture we use, and that returns a :py:class:`~renderdoc.ReplayController` which can be used as normal and will tunnel over the remote server connection. It can be useful to intermittently ping the remote server connection to check that it's still valid, and remote server and controller calls can be interleaved as long as they don't overlap on multiple threads.
|
||||
|
||||
Example Source
|
||||
--------------
|
||||
|
||||
.. only:: html and not htmlhelp
|
||||
|
||||
:download:`Download the example script <remote_capture.py>`.
|
||||
|
||||
.. literalinclude:: remote_capture.py
|
||||
|
||||
@@ -5,4 +5,4 @@ Enums and Data Structures
|
||||
:members:
|
||||
:undoc-members:
|
||||
:imported-members:
|
||||
:exclude-members: free_functions__, enum_constants__, name_match__startswith__D3D11, name_match__startswith__D3D12, name_match__startswith__VK, name_match__startswith__GL, name_match__startswith__rdcarray_of, rdcstr, bytebuf, ReplayController, ReplayOutput, TargetControl, RemoteServer, CaptureFile, Viewport, Scissor, BlendEquation, ColorBlend, StencilFace, BoundResource, BoundResourceArray, BoundVBuffer, BoundCBuffer, VertexInputAttribute, PipeState
|
||||
:exclude-members: free_functions__, enum_constants__, name_match__startswith__D3D11, name_match__startswith__D3D12, name_match__startswith__VK, name_match__startswith__GL, name_match__startswith__rdcarray_of, rdcstr, bytebuf, ReplayController, ReplayOutput, TargetControl, RemoteServer, DeviceProtocolController, CaptureFile, Viewport, Scissor, BlendEquation, ColorBlend, StencilFace, BoundResource, BoundResourceArray, BoundVBuffer, BoundCBuffer, VertexInputAttribute, PipeState
|
||||
|
||||
@@ -20,9 +20,14 @@ Remote Servers
|
||||
--------------
|
||||
|
||||
.. autofunction:: renderdoc.CreateRemoteServerConnection
|
||||
.. autofunction:: renderdoc.GetDefaultRemoteServerPort
|
||||
.. autofunction:: renderdoc.BecomeRemoteServer
|
||||
|
||||
Device Protocols
|
||||
----------------
|
||||
|
||||
.. autofunction:: renderdoc.GetSupportedDeviceProtocols
|
||||
.. autofunction:: renderdoc.GetDeviceProtocolController
|
||||
|
||||
Local Execution & Injection
|
||||
---------------------------
|
||||
|
||||
|
||||
@@ -33,6 +33,13 @@ RemoteServer
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
DeviceProtocolController
|
||||
------------------------
|
||||
|
||||
.. autoclass:: renderdoc.DeviceProtocolController
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
CaptureFile
|
||||
-----------
|
||||
|
||||
|
||||
@@ -259,15 +259,8 @@ void PersistantConfig::RemoveRemoteHost(RemoteHost host)
|
||||
}
|
||||
}
|
||||
|
||||
void PersistantConfig::AddAndroidHosts()
|
||||
void PersistantConfig::UpdateEnumeratedProtocolDevices()
|
||||
{
|
||||
QMutexLocker autolock(&RemoteHostLock);
|
||||
|
||||
QMap<rdcstr, RemoteHost> oldHosts;
|
||||
for(int i = RemoteHostList.count() - 1; i >= 0; i--)
|
||||
if(RemoteHostList[i].IsADB())
|
||||
oldHosts[RemoteHostList[i].Hostname()] = RemoteHostList.takeAt(i);
|
||||
|
||||
QString androidSDKPath = (!Android_SDKPath.isEmpty() && QFile::exists(Android_SDKPath))
|
||||
? QString(Android_SDKPath)
|
||||
: QString();
|
||||
@@ -282,19 +275,39 @@ void PersistantConfig::AddAndroidHosts()
|
||||
|
||||
SetConfigSetting("MaxConnectTimeout", QString::number(Android_MaxConnectTimeout));
|
||||
|
||||
rdcstr androidHosts;
|
||||
RENDERDOC_EnumerateAndroidDevices(androidHosts);
|
||||
for(const QString &hostName :
|
||||
QString(androidHosts).split(QLatin1Char(','), QString::SkipEmptyParts))
|
||||
rdcarray<RemoteHost> enumeratedDevices;
|
||||
|
||||
rdcarray<rdcstr> protocols;
|
||||
RENDERDOC_GetSupportedDeviceProtocols(&protocols);
|
||||
|
||||
for(const rdcstr &p : protocols)
|
||||
{
|
||||
RemoteHost host((rdcstr)hostName);
|
||||
IDeviceProtocolController *protocol = RENDERDOC_GetDeviceProtocolController(p);
|
||||
|
||||
if(oldHosts.contains(hostName))
|
||||
host = oldHosts.take(hostName);
|
||||
rdcarray<rdcstr> devices = protocol->GetDevices();
|
||||
|
||||
rdcstr friendly;
|
||||
RENDERDOC_GetAndroidFriendlyName(hostName.toUtf8().data(), friendly);
|
||||
host.SetFriendlyName(friendly);
|
||||
for(const rdcstr &d : devices)
|
||||
{
|
||||
RemoteHost newhost(protocol->GetProtocolName() + "://" + d);
|
||||
enumeratedDevices.push_back(newhost);
|
||||
}
|
||||
}
|
||||
|
||||
QMutexLocker autolock(&RemoteHostLock);
|
||||
|
||||
QMap<rdcstr, RemoteHost> oldHosts;
|
||||
|
||||
for(int i = RemoteHostList.count() - 1; i >= 0; i--)
|
||||
if(RemoteHostList[i].Protocol())
|
||||
oldHosts[RemoteHostList[i].Hostname()] = RemoteHostList.takeAt(i);
|
||||
|
||||
for(RemoteHost host : enumeratedDevices)
|
||||
{
|
||||
// if we already had this host, use that one.
|
||||
if(oldHosts.contains(host.Hostname()))
|
||||
host = oldHosts.take(host.Hostname());
|
||||
|
||||
host.SetFriendlyName(host.Protocol()->GetFriendlyName(host.Hostname()));
|
||||
// Just a command to display in the GUI and allow Launch() to be called.
|
||||
host.SetRunCommand("Automatically handled");
|
||||
RemoteHostList.push_back(host);
|
||||
@@ -363,6 +376,10 @@ bool PersistantConfig::Load(const rdcstr &filename)
|
||||
if(!host.IsValid())
|
||||
continue;
|
||||
|
||||
// backwards compatibility - skip old adb hosts that were adb:
|
||||
if(host.Hostname().find("adb:") > 0 && host.Protocol() == NULL)
|
||||
continue;
|
||||
|
||||
RemoteHostList.push_back(host);
|
||||
|
||||
if(host.IsLocalhost())
|
||||
|
||||
@@ -791,8 +791,8 @@ R)");
|
||||
:param RemoteHost host: The remote host to remove.
|
||||
R)");
|
||||
void RemoveRemoteHost(RemoteHost host);
|
||||
DOCUMENT("If configured, queries ``adb`` to add android hosts to :data:`RemoteHosts`.");
|
||||
void AddAndroidHosts();
|
||||
DOCUMENT("If configured, queries available device protocols to update auto-configured hosts.");
|
||||
void UpdateEnumeratedProtocolDevices();
|
||||
|
||||
DOCUMENT("");
|
||||
CONFIG_SETTINGS()
|
||||
|
||||
@@ -60,6 +60,8 @@ RemoteHost::RemoteHost(const QVariant &var)
|
||||
m_data->m_runCommand = map[lit("runCommand")].toString();
|
||||
if(map.contains(lit("lastCapturePath")))
|
||||
m_data->m_lastCapturePath = map[lit("lastCapturePath")].toString();
|
||||
|
||||
m_protocol = RENDERDOC_GetDeviceProtocolController(m_hostname);
|
||||
}
|
||||
|
||||
RemoteHost::RemoteHost()
|
||||
@@ -72,6 +74,8 @@ RemoteHost::RemoteHost(const rdcstr &host)
|
||||
// create a new host
|
||||
m_hostname = host;
|
||||
m_data = new RemoteHostData();
|
||||
|
||||
m_protocol = RENDERDOC_GetDeviceProtocolController(m_hostname);
|
||||
}
|
||||
|
||||
RemoteHost::RemoteHost(const RemoteHost &o)
|
||||
@@ -82,6 +86,7 @@ RemoteHost::RemoteHost(const RemoteHost &o)
|
||||
RemoteHost &RemoteHost::operator=(const RemoteHost &o)
|
||||
{
|
||||
m_hostname = o.m_hostname;
|
||||
m_protocol = o.m_protocol;
|
||||
|
||||
// deref old data
|
||||
if(m_data)
|
||||
@@ -123,7 +128,7 @@ void RemoteHost::CheckStatus()
|
||||
// to avoid doing complex work while holding the remote host lock, we check the status here then
|
||||
// call into the internal function that will propagate that data to the proper storage if needed.
|
||||
IRemoteServer *rend = NULL;
|
||||
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(m_hostname.c_str(), 0, &rend);
|
||||
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(m_hostname.c_str(), &rend);
|
||||
|
||||
if(rend)
|
||||
rend->ShutdownConnection();
|
||||
@@ -187,12 +192,10 @@ ReplayStatus RemoteHost::Launch()
|
||||
{
|
||||
ReplayStatus status = ReplayStatus::Succeeded;
|
||||
|
||||
int WAIT_TIME = 2000;
|
||||
|
||||
if(IsADB())
|
||||
if(m_protocol)
|
||||
{
|
||||
status = RENDERDOC_StartAndroidRemoteServer(m_hostname.c_str());
|
||||
QThread::msleep(WAIT_TIME);
|
||||
// this is blocking
|
||||
status = m_protocol->StartRemoteServer(m_hostname);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -205,7 +208,7 @@ ReplayStatus RemoteHost::Launch()
|
||||
|
||||
RDProcess process;
|
||||
process.start(run);
|
||||
process.waitForFinished(WAIT_TIME);
|
||||
process.waitForFinished(2000);
|
||||
process.detach();
|
||||
|
||||
return status;
|
||||
|
||||
@@ -93,6 +93,9 @@ public:
|
||||
)");
|
||||
void SetLastCapturePath(const rdcstr &path);
|
||||
|
||||
DOCUMENT(
|
||||
"The :class:`DeviceProtocolController` for this host, or ``None`` if no protocol is in use");
|
||||
IDeviceProtocolController *Protocol() const { return m_protocol; }
|
||||
DOCUMENT(R"(
|
||||
Returns the name to display for this host in the UI, either :meth:`FriendlyName` if it is valid, or
|
||||
:meth:`Hostname` if not.
|
||||
@@ -102,12 +105,6 @@ Returns the name to display for this host in the UI, either :meth:`FriendlyName`
|
||||
rdcstr friendlyName = FriendlyName();
|
||||
return !friendlyName.isEmpty() ? friendlyName : m_hostname;
|
||||
}
|
||||
DOCUMENT("Returns ``True`` if this host represents a connected ADB (Android) device.");
|
||||
bool IsADB() const
|
||||
{
|
||||
return m_hostname.count() > 4 && m_hostname[0] == 'a' && m_hostname[1] == 'd' &&
|
||||
m_hostname[2] == 'b' && m_hostname[3] == ':';
|
||||
}
|
||||
DOCUMENT("Returns ``True`` if this host represents the special localhost device.");
|
||||
bool IsLocalhost() const { return m_hostname == "localhost"; }
|
||||
DOCUMENT("Returns ``True`` if this host represents a valid remote host.");
|
||||
@@ -117,6 +114,8 @@ private:
|
||||
// are created with it
|
||||
rdcstr m_hostname;
|
||||
|
||||
IDeviceProtocolController *m_protocol = NULL;
|
||||
|
||||
// self-deleting shared and locked data store
|
||||
RemoteHostData *m_data = NULL;
|
||||
|
||||
|
||||
@@ -307,9 +307,9 @@ void ReplayManager::CloseThread()
|
||||
|
||||
ReplayStatus ReplayManager::ConnectToRemoteServer(RemoteHost host)
|
||||
{
|
||||
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), 0, &m_Remote);
|
||||
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), &m_Remote);
|
||||
|
||||
if(host.IsADB())
|
||||
if(host.Protocol() && host.Protocol()->GetProtocolName() == "adb")
|
||||
{
|
||||
ANALYTIC_SET(UIFeatures.AndroidRemoteReplay, true);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ void PersistantConfig::RemoveRemoteHost(RemoteHost host)
|
||||
{
|
||||
}
|
||||
|
||||
void PersistantConfig::AddAndroidHosts()
|
||||
void PersistantConfig::UpdateEnumeratedProtocolDevices()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,29 @@
|
||||
$result = SWIG_NewPointerObj($1, $descriptor(struct CaptureOptions*), SWIG_POINTER_OWN);
|
||||
}
|
||||
|
||||
// same for RENDERDOC_GetSupportedDeviceProtocols
|
||||
%typemap(in, numinputs=0) rdcarray<rdcstr> *supportedProtocols { $1 = new rdcarray<rdcstr>; }
|
||||
%typemap(argout) rdcarray<rdcstr> *supportedProtocols {
|
||||
$result = ConvertToPy(*$1);
|
||||
delete $1;
|
||||
}
|
||||
%typemap(freearg) rdcarray<rdcstr> *supportedProtocols { }
|
||||
|
||||
// same for RENDERDOC_CreateRemoteServerConnection
|
||||
%typemap(in, numinputs=0) IRemoteServer **rend (IRemoteServer *outRenderer) {
|
||||
outRenderer = NULL;
|
||||
$1 = &outRenderer;
|
||||
}
|
||||
%typemap(argout) IRemoteServer **rend {
|
||||
PyObject *retVal = $result;
|
||||
$result = PyTuple_New(2);
|
||||
if($result)
|
||||
{
|
||||
PyTuple_SetItem($result, 0, retVal);
|
||||
PyTuple_SetItem($result, 1, SWIG_NewPointerObj(SWIG_as_voidptr(outRenderer$argnum), SWIGTYPE_p_IRemoteServer, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// ignore some operators SWIG doesn't have to worry about
|
||||
%ignore SDType::operator=;
|
||||
%ignore StructuredObjectList::swap;
|
||||
|
||||
@@ -474,8 +474,6 @@ int main(int argc, char *argv[])
|
||||
config.Save();
|
||||
}
|
||||
|
||||
RENDERDOC_AndroidShutdown();
|
||||
|
||||
PythonContext::GlobalShutdown();
|
||||
|
||||
Formatter::shutdown();
|
||||
|
||||
@@ -678,7 +678,8 @@ void CaptureDialog::on_exePathBrowse_clicked()
|
||||
{
|
||||
SetExecutableFilename(filename);
|
||||
|
||||
if(m_Ctx.Replay().CurrentRemote().IsADB())
|
||||
if(m_Ctx.Replay().CurrentRemote().Protocol() &&
|
||||
m_Ctx.Replay().CurrentRemote().Protocol()->GetProtocolName() == "adb")
|
||||
{
|
||||
CheckAndroidSetup(filename);
|
||||
}
|
||||
@@ -1122,7 +1123,8 @@ void CaptureDialog::UpdateGlobalHook()
|
||||
|
||||
void CaptureDialog::UpdateRemoteHost()
|
||||
{
|
||||
if(m_Ctx.Replay().CurrentRemote().IsADB())
|
||||
if(m_Ctx.Replay().CurrentRemote().Protocol() &&
|
||||
m_Ctx.Replay().CurrentRemote().Protocol()->GetProtocolName() == "adb")
|
||||
ui->cmdLineLabel->setText(tr("Intent Arguments"));
|
||||
else
|
||||
ui->cmdLineLabel->setText(tr("Command-line Arguments"));
|
||||
|
||||
@@ -105,8 +105,6 @@ RemoteManager::RemoteManager(ICaptureContext &ctx, MainWindow *main)
|
||||
vertical->addWidget(lookupsProgressFlow);
|
||||
vertical->addWidget(ui->bottomLayout->parentWidget());
|
||||
|
||||
m_Ctx.Config().AddAndroidHosts();
|
||||
|
||||
for(RemoteHost h : m_Ctx.Config().GetRemoteHosts())
|
||||
addHost(h);
|
||||
|
||||
@@ -446,9 +444,9 @@ void RemoteManager::on_hosts_itemSelectionChanged()
|
||||
|
||||
ui->addUpdateHost->setText(tr("Update"));
|
||||
|
||||
if(host.IsLocalhost() || host.IsADB())
|
||||
if(host.IsLocalhost() || host.Protocol())
|
||||
{
|
||||
// localhost and android hosts cannot be updated or have their run command changed
|
||||
// localhost and protocol-configured hosts cannot be updated or have their run command changed
|
||||
ui->addUpdateHost->setEnabled(false);
|
||||
ui->runCommand->setEnabled(false);
|
||||
}
|
||||
@@ -601,7 +599,7 @@ void RemoteManager::on_connect_clicked()
|
||||
{
|
||||
IRemoteServer *server = NULL;
|
||||
ReplayStatus status =
|
||||
RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), 0, &server);
|
||||
RENDERDOC_CreateRemoteServerConnection(host.Hostname().c_str(), &server);
|
||||
if(server)
|
||||
server->ShutdownServerAndConnection();
|
||||
setRemoteServerLive(node, false, false);
|
||||
|
||||
@@ -160,11 +160,15 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
|
||||
m_RemoteProbeSemaphore.release();
|
||||
m_RemoteProbe = new LambdaThread([this]() {
|
||||
RENDERDOC_AndroidInitialise();
|
||||
// fetch all device protocols to start them processing
|
||||
rdcarray<rdcstr> protocols;
|
||||
RENDERDOC_GetSupportedDeviceProtocols(&protocols);
|
||||
for(const rdcstr &p : protocols)
|
||||
RENDERDOC_GetDeviceProtocolController(p);
|
||||
|
||||
while(m_RemoteProbeSemaphore.available())
|
||||
{
|
||||
// do a remoteProbe immediately to populate the android hosts list on startup.
|
||||
// do a remoteProbe immediately to populate the device list on startup.
|
||||
remoteProbe();
|
||||
|
||||
// do several small sleeps so we can respond quicker when we need to shut down
|
||||
@@ -510,7 +514,7 @@ void MainWindow::OnCaptureTrigger(const QString &exe, const QString &workingDir,
|
||||
|
||||
LambdaThread *th = new LambdaThread([this, exe, workingDir, cmdLine, env, opts, callback]() {
|
||||
|
||||
if(isCapturableAppRunningOnAndroid())
|
||||
if(isUnshareableDeviceInUse())
|
||||
{
|
||||
RDDialog::warning(this, tr("RenderDoc is already capturing an app on this device"),
|
||||
tr("A running app on this device is already being captured with RenderDoc. "
|
||||
@@ -1583,25 +1587,10 @@ void MainWindow::remoteProbe()
|
||||
{
|
||||
if(!m_Ctx.IsCaptureLoaded() && !m_Ctx.IsCaptureLoading())
|
||||
{
|
||||
GUIInvoke::call(this, [this] {
|
||||
m_Ctx.Config().AddAndroidHosts();
|
||||
|
||||
// update the latest list by copy. Note this lock only protects m_ProbeRemoteHosts, not the
|
||||
// actual RemoteHosts list itself - that is only accessed on the UI thread so is not locked.
|
||||
{
|
||||
QMutexLocker lock(&m_ProbeRemoteHostsLock);
|
||||
m_ProbeRemoteHosts.clear();
|
||||
for(RemoteHost host : m_Ctx.Config().GetRemoteHosts())
|
||||
m_ProbeRemoteHosts.push_back(host);
|
||||
}
|
||||
});
|
||||
m_Ctx.Config().UpdateEnumeratedProtocolDevices();
|
||||
|
||||
// fetch the latest list
|
||||
rdcarray<RemoteHost> hosts;
|
||||
{
|
||||
QMutexLocker lock(&m_ProbeRemoteHostsLock);
|
||||
hosts = m_ProbeRemoteHosts;
|
||||
}
|
||||
rdcarray<RemoteHost> hosts = m_Ctx.Config().GetRemoteHosts();
|
||||
|
||||
for(RemoteHost &host : hosts)
|
||||
{
|
||||
@@ -1832,23 +1821,64 @@ void MainWindow::setRemoteHost(int hostIdx)
|
||||
RemoteHost host = h;
|
||||
host.CheckStatus();
|
||||
|
||||
if(host.IsADB() && !RENDERDOC_IsAndroidSupported(host.Hostname().c_str()))
|
||||
if(host.Protocol() && !host.Protocol()->IsSupported(host.Hostname()))
|
||||
{
|
||||
// check to see if we should warn the user about this unsupported android version.
|
||||
GUIInvoke::call(this, [this]() {
|
||||
GUIInvoke::call(this, [this, host]() {
|
||||
QDateTime today = QDateTime::currentDateTimeUtc();
|
||||
QDateTime compare = today.addDays(-21);
|
||||
|
||||
if(compare > m_Ctx.Config().UnsupportedAndroid_LastUpdate)
|
||||
if(host.Protocol()->GetProtocolName() == "adb")
|
||||
{
|
||||
if(compare > m_Ctx.Config().UnsupportedAndroid_LastUpdate)
|
||||
{
|
||||
RDDialog::critical(
|
||||
this, tr("Unsupported Device Android Version"),
|
||||
tr("This device is older than Android 6.0, the minimum required version for "
|
||||
"RenderDoc.\n\nThis may break or cause unknown problems - use at your own "
|
||||
"risk."));
|
||||
}
|
||||
|
||||
m_Ctx.Config().UnsupportedAndroid_LastUpdate = today;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDDialog::critical(
|
||||
this, tr("Unsupported Device Android Version"),
|
||||
tr("This device is older than Android 6.0, the minimum required version for "
|
||||
"RenderDoc.\n\nThis may break or cause unknown problems - use at your own "
|
||||
"risk."));
|
||||
this, tr("Unsupported Device"),
|
||||
tr("This device is not able to support RenderDoc. Please consult the documentation "
|
||||
"for this type of device to see what the problem may be."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
m_Ctx.Config().UnsupportedAndroid_LastUpdate = today;
|
||||
if(host.Protocol() && host.IsVersionMismatch())
|
||||
{
|
||||
GUIInvoke::blockcall(this, [this, &host]() {
|
||||
|
||||
QMessageBox::StandardButton res =
|
||||
RDDialog::question(this, tr("Unsupported version"),
|
||||
tr("Remote server on %1 has an incompatible version.\n"
|
||||
"Would you like to try to reinstall the version %2?")
|
||||
.arg(host.Name())
|
||||
.arg(lit(FULL_VERSION_STRING)),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if(res == QMessageBox::Yes)
|
||||
{
|
||||
LambdaThread *launchthread = new LambdaThread([this, &host]() {
|
||||
// since we have a protocol, try to force-launch which should attempt to reinstall.
|
||||
host.Launch();
|
||||
|
||||
// update status
|
||||
host.CheckStatus();
|
||||
});
|
||||
launchthread->start();
|
||||
|
||||
ShowProgressDialog(this, tr("Attempting to update remote server, please wait..."),
|
||||
[launchthread]() { return !launchthread->isRunning(); });
|
||||
|
||||
launchthread->deleteLater();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2539,11 +2569,25 @@ void MainWindow::on_action_Manage_Extensions_triggered()
|
||||
|
||||
void MainWindow::on_action_Manage_Remote_Servers_triggered()
|
||||
{
|
||||
RemoteManager *rm = new RemoteManager(m_Ctx, this);
|
||||
RDDialog::show(rm);
|
||||
// now that we're done with it, the manager deletes itself when all lookups terminate (or
|
||||
// immediately if there are no lookups ongoing).
|
||||
rm->closeWhenFinished();
|
||||
LambdaThread *th = new LambdaThread([this]() {
|
||||
m_Ctx.Config().UpdateEnumeratedProtocolDevices();
|
||||
|
||||
GUIInvoke::call(this, [this]() {
|
||||
RemoteManager *rm = new RemoteManager(m_Ctx, this);
|
||||
RDDialog::show(rm);
|
||||
// now that we're done with it, the manager deletes itself when all lookups terminate (or
|
||||
// immediately if there are no lookups ongoing).
|
||||
rm->closeWhenFinished();
|
||||
});
|
||||
});
|
||||
th->start();
|
||||
th->wait(500);
|
||||
if(th->isRunning())
|
||||
{
|
||||
ShowProgressDialog(this, tr("Updating available devices, please wait..."),
|
||||
[th]() { return !th->isRunning(); });
|
||||
}
|
||||
th->deleteLater();
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Settings_triggered()
|
||||
@@ -2895,12 +2939,16 @@ void MainWindow::showLaunchError(ReplayStatus status)
|
||||
});
|
||||
}
|
||||
|
||||
bool MainWindow::isCapturableAppRunningOnAndroid()
|
||||
bool MainWindow::isUnshareableDeviceInUse()
|
||||
{
|
||||
if(!m_Ctx.Replay().CurrentRemote().IsADB())
|
||||
if(!m_Ctx.Replay().CurrentRemote().Protocol())
|
||||
return false;
|
||||
|
||||
rdcstr host = m_Ctx.Replay().CurrentRemote().Hostname();
|
||||
|
||||
if(m_Ctx.Replay().CurrentRemote().Protocol()->SupportsMultiplePrograms(host))
|
||||
return false;
|
||||
|
||||
uint32_t ident = RENDERDOC_EnumerateRemoteTargets(host.c_str(), 0);
|
||||
return ident != 0;
|
||||
}
|
||||
|
||||
@@ -256,5 +256,5 @@ private:
|
||||
|
||||
void showLaunchError(ReplayStatus status);
|
||||
|
||||
bool isCapturableAppRunningOnAndroid();
|
||||
bool isUnshareableDeviceInUse();
|
||||
};
|
||||
|
||||
@@ -110,6 +110,7 @@ set(sources
|
||||
core/crash_handler.h
|
||||
core/target_control.cpp
|
||||
core/remote_server.cpp
|
||||
core/remote_server.h
|
||||
core/replay_proxy.cpp
|
||||
core/replay_proxy.h
|
||||
core/intervals.h
|
||||
|
||||
+685
-272
File diff suppressed because it is too large
Load Diff
@@ -513,12 +513,12 @@ bool IsDebuggable(const std::string &deviceID, const std::string &packageName)
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(
|
||||
const char *hostname, const char *packageAndActivity, AndroidFlags *flags)
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_CheckAndroidPackage(const char *URL, const char *packageAndActivity, AndroidFlags *flags)
|
||||
{
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::ExtractDeviceIDAndIndex(hostname, index, deviceID);
|
||||
IDeviceProtocolHandler *adb = RenderDoc::Inst().GetDeviceProtocol("adb");
|
||||
|
||||
rdcstr deviceID = adb->GetDeviceID(URL);
|
||||
|
||||
// Reset the flags each time we check
|
||||
*flags = AndroidFlags::NoFlags;
|
||||
@@ -542,15 +542,15 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePackage(
|
||||
const char *hostname, const char *packageAndActivity, RENDERDOC_ProgressCallback progress)
|
||||
const char *URL, const char *packageAndActivity, RENDERDOC_ProgressCallback progress)
|
||||
{
|
||||
std::string package = Android::GetPackageName(packageAndActivity);
|
||||
|
||||
Process::ProcessResult result = {};
|
||||
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::ExtractDeviceIDAndIndex(hostname, index, deviceID);
|
||||
IDeviceProtocolHandler *adb = RenderDoc::Inst().GetDeviceProtocol("adb");
|
||||
|
||||
rdcstr deviceID = adb->GetDeviceID(URL);
|
||||
|
||||
// make sure progress is valid so we don't have to check it everywhere
|
||||
if(!progress)
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "core/core.h"
|
||||
#include "strings/string_utils.h"
|
||||
|
||||
static std::map<std::string, std::string> friendlyNameCache;
|
||||
|
||||
namespace Android
|
||||
{
|
||||
bool IsHostADB(const char *hostname)
|
||||
@@ -185,12 +183,8 @@ bool IsSupported(std::string deviceID)
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GetFriendlyName(std::string deviceID)
|
||||
rdcstr GetFriendlyName(const rdcstr &deviceID)
|
||||
{
|
||||
auto it = friendlyNameCache.find(deviceID);
|
||||
if(it != friendlyNameCache.end())
|
||||
return it->second;
|
||||
|
||||
// run adb root now, so we hit any disconnection that we're going to before trying to connect.
|
||||
// If we can't be root, this is cheap, if we're already root, this is cheap, if we can be root
|
||||
// and this changes us it will block only the first time - and we expect this function to be
|
||||
@@ -205,7 +199,7 @@ std::string GetFriendlyName(std::string deviceID)
|
||||
std::string model =
|
||||
trim(Android::adbExecCommand(deviceID, "shell getprop ro.product.model").strStdout);
|
||||
|
||||
std::string &combined = friendlyNameCache[deviceID];
|
||||
std::string combined;
|
||||
|
||||
if(manuf.empty() && model.empty())
|
||||
combined = "";
|
||||
|
||||
@@ -50,7 +50,7 @@ bool toolExists(const std::string &path);
|
||||
std::string GetFirstMatchingLine(const std::string &haystack, const std::string &needle);
|
||||
|
||||
bool IsSupported(std::string deviceID);
|
||||
std::string GetFriendlyName(std::string deviceID);
|
||||
rdcstr GetFriendlyName(const rdcstr &deviceID);
|
||||
|
||||
// supported ABIs
|
||||
enum class ABI
|
||||
|
||||
@@ -2054,7 +2054,8 @@ DOCUMENT(R"(Creates a :class:`TargetControl` connection to a given hostname and
|
||||
|
||||
This function will block until the control connection is ready, or an error occurs.
|
||||
|
||||
:param str host: The hostname to connect to. If blank, the local machine is used.
|
||||
:param str URL: The URL to connect to. If blank, the local machine is used. If no protocol is
|
||||
specified then default TCP enumeration happens.
|
||||
:param int ident: The ident for the particular target to connect to on that machine.
|
||||
:param str clientName: The client name to use when connecting. See
|
||||
:meth:`TargetControl.GetBusyClient`.
|
||||
@@ -2064,7 +2065,7 @@ This function will block until the control connection is ready, or an error occu
|
||||
:rtype: TargetControl
|
||||
)");
|
||||
extern "C" RENDERDOC_API ITargetControl *RENDERDOC_CC RENDERDOC_CreateTargetControl(
|
||||
const char *host, uint32_t ident, const char *clientName, bool forceConnection);
|
||||
const char *URL, uint32_t ident, const char *clientName, bool forceConnection);
|
||||
|
||||
DOCUMENT(R"(Repeatedly query to enumerate which targets are active on a given machine and their
|
||||
idents.
|
||||
@@ -2075,38 +2076,29 @@ more targets.
|
||||
|
||||
This function will block for a variable timeout depending on how many targets are scanned.
|
||||
|
||||
:param str host: The hostname to connect to. If blank, the local machine is used.
|
||||
:param str URL: The URL to connect to. If blank, the local machine is used. If no protocol is
|
||||
specified then default TCP enumeration happens.
|
||||
:param int nextIdent: The next ident to scan.
|
||||
:return: The ident of the next active target, or ``0`` if no other targets exist.
|
||||
:rtype: ``int``
|
||||
)");
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(const char *host,
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(const char *URL,
|
||||
uint32_t nextIdent);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Remote server
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DOCUMENT(R"(Retrieves the default ports where remote servers listen.
|
||||
|
||||
:return: The port where remote servers listen by default.
|
||||
:rtype: ``int``
|
||||
)");
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_GetDefaultRemoteServerPort();
|
||||
|
||||
DOCUMENT(R"(Create a connection to a remote server running on given hostname and port.
|
||||
|
||||
This function will block until the capture is fully loaded and ready.
|
||||
|
||||
:param str host: The hostname to connect to, if blank then localhost is used.
|
||||
:param int port: The port to connect to, or the default port if 0.
|
||||
:param RemoteServer rend: A reference to a :class:`RemoteServer` where the connection handle will be
|
||||
stored.
|
||||
:return: The status of opening the capture, whether success or failure.
|
||||
:rtype: ReplayStatus
|
||||
:param str URL: The hostname to connect to, if blank then localhost is used. If no protocol is
|
||||
specified then default TCP enumeration happens.
|
||||
:return: The status of opening the capture, whether success or failure, and a :class:`RemoteServer`
|
||||
instance if it were successful
|
||||
:rtype: ``pair`` of ReplayStatus and RemoteServer
|
||||
)");
|
||||
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC
|
||||
RENDERDOC_CreateRemoteServerConnection(const char *host, uint32_t port, IRemoteServer **rend);
|
||||
RENDERDOC_CreateRemoteServerConnection(const char *URL, IRemoteServer **rend);
|
||||
|
||||
DOCUMENT(R"(This launches a remote server which will continually run in a loop to server requests
|
||||
from external sources.
|
||||
@@ -2115,15 +2107,14 @@ This function will block until a remote connection tells the server to shut down
|
||||
``killReplay`` callback returns ``True``.
|
||||
|
||||
:param str host: The name of the interface to listen on.
|
||||
:param int port: The port to listen on, or the default port if 0.
|
||||
:param KillCallback killReplay: A callback that returns a ``bool`` indicating if the server should
|
||||
be shut down or not.
|
||||
:param PreviewWindowCallback previewWindow: A callback that returns information for a preview window
|
||||
when the server wants to display some preview of the ongoing replay.
|
||||
)");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
|
||||
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay,
|
||||
RENDERDOC_PreviewWindowCallback previewWindow);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_BecomeRemoteServer(const char *listenhost, RENDERDOC_KillCallback killReplay,
|
||||
RENDERDOC_PreviewWindowCallback previewWindow);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Injection/execution capture functions.
|
||||
@@ -2349,33 +2340,108 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetColors(FloatVector darkC
|
||||
FloatVector lightChecker,
|
||||
bool darkTheme);
|
||||
|
||||
DOCUMENT("Internal function for fetching friendly android names.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_GetAndroidFriendlyName(const rdcstr &device,
|
||||
rdcstr &friendly);
|
||||
|
||||
DOCUMENT("Internal function for enumerating android devices.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_EnumerateAndroidDevices(rdcstr &deviceList);
|
||||
|
||||
DOCUMENT("Internal function for initialising android use.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_AndroidInitialise();
|
||||
|
||||
DOCUMENT("Internal function for shutting down android use.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_AndroidShutdown();
|
||||
|
||||
DOCUMENT("Internal function for checking android support.");
|
||||
extern "C" RENDERDOC_API bool RENDERDOC_CC RENDERDOC_IsAndroidSupported(const char *device);
|
||||
|
||||
DOCUMENT("Internal function for starting an android remote server.");
|
||||
extern "C" RENDERDOC_API ReplayStatus RENDERDOC_CC
|
||||
RENDERDOC_StartAndroidRemoteServer(const char *device);
|
||||
|
||||
DOCUMENT("Internal function for checking remote Android package for requirements");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_CheckAndroidPackage(
|
||||
const char *hostname, const char *packageAndActivity, AndroidFlags *flags);
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_CheckAndroidPackage(const char *URL, const char *packageAndActivity, AndroidFlags *flags);
|
||||
|
||||
DOCUMENT("Internal function that attempts to modify APK contents, adding debuggable flag.");
|
||||
extern "C" RENDERDOC_API AndroidFlags RENDERDOC_CC RENDERDOC_MakeDebuggablePackage(
|
||||
const char *hostname, const char *packageAndActivity, RENDERDOC_ProgressCallback progress);
|
||||
const char *URL, const char *packageAndActivity, RENDERDOC_ProgressCallback progress);
|
||||
|
||||
DOCUMENT("An interface for enumerating and controlling remote devices.");
|
||||
struct IDeviceProtocolController
|
||||
{
|
||||
DOCUMENT(R"(Retrieves the name of this protocol as passed to :func:`GetDeviceProtocolController`.
|
||||
|
||||
:return: A string identifying the protocol.
|
||||
:rtype: ``str``
|
||||
)");
|
||||
virtual rdcstr GetProtocolName() = 0;
|
||||
|
||||
DOCUMENT(R"(Returns a list of devices currently available through the given protocol.
|
||||
|
||||
Until a device is enumerated through this function it may not be available for connection through
|
||||
other methods such as target control or remote server access, even if the device is physically
|
||||
connected, due to initialisation happening only when enumerated.
|
||||
|
||||
The returned string is the hostname of the device, which can be connected via
|
||||
``protocol://hostname`` with interfaces that take a hostname.
|
||||
|
||||
:return: A list of the devices currently available.
|
||||
:rtype: ``list`` of ``str``
|
||||
)");
|
||||
virtual rdcarray<rdcstr> GetDevices() = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieves the user friendly name of the given device. This may be easier for a user to
|
||||
correlate to a device than the hostname which may be only a programmatic identifier.
|
||||
|
||||
:param str URL: The URL of the device in the form ``protocol://host``, with protocol as returned by
|
||||
:func:`GetProtocolName` and host as returned by :func:`GetDevices`.
|
||||
:return: A string identifying the device.
|
||||
:rtype: ``str``
|
||||
)");
|
||||
virtual rdcstr GetFriendlyName(const rdcstr &URL) = 0;
|
||||
|
||||
DOCUMENT(R"(Query if the device supports multiple programs running and being captured. If not, the
|
||||
user can be prompted to close an existing program before a new one is launched.
|
||||
|
||||
:param str URL: The URL of the device in the form ``protocol://host``, with protocol as returned by
|
||||
:func:`GetProtocolName` and host as returned by :func:`GetDevices`.
|
||||
:return: ``True`` if the device supports multiple programs, ``False`` otherwise.
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
virtual bool SupportsMultiplePrograms(const rdcstr &URL) = 0;
|
||||
|
||||
DOCUMENT(R"(Query if the device supports RenderDoc capture and replay.
|
||||
|
||||
:param str URL: The URL of the device in the form ``protocol://host``, with protocol as returned by
|
||||
:func:`GetProtocolName` and host as returned by :func:`GetDevices`.
|
||||
:return: ``True`` if any the device is supported, ``False`` otherwise.
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
virtual bool IsSupported(const rdcstr &URL) = 0;
|
||||
|
||||
DOCUMENT(R"(Start the remote server running on the given device.
|
||||
|
||||
:param str URL: The URL of the device in the form ``protocol://host``, with protocol as returned by
|
||||
:func:`GetProtocolName` and host as returned by :func:`GetDevices`.
|
||||
:return: The status of starting the server, whether success or failure.
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus StartRemoteServer(const rdcstr &URL) = 0;
|
||||
|
||||
protected:
|
||||
IDeviceProtocolController() = default;
|
||||
~IDeviceProtocolController() = default;
|
||||
};
|
||||
|
||||
DOCUMENT(R"(Retrieve the set of device protocols supported (see :func:`GetDeviceProtocolController`).
|
||||
|
||||
:return: The supported device protocols.
|
||||
:rtype: ``list`` of ``str``
|
||||
)");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_GetSupportedDeviceProtocols(rdcarray<rdcstr> *supportedProtocols);
|
||||
|
||||
DOCUMENT(R"(Creates a :class:`DeviceProtocolController` that provides device-specific controls.
|
||||
|
||||
This interface is intended to allow closer integration with remote devices.
|
||||
|
||||
.. note::
|
||||
Note that the use of scripting with Android is explicitly **not supported** due to the inherent
|
||||
fragility and unreliability of the Android platform. This interface is designed primarily for
|
||||
internal use and no support will be provided for Android-specific problems encountered using this.
|
||||
|
||||
This function will not block, however the protocol may still be initialising when it is returned so
|
||||
immediate use of it may block.
|
||||
|
||||
:param str protocol: The protocol to fetch a controller for.
|
||||
:return: A handle to the protocol controller, or ``None`` if something went wrong such as an
|
||||
unsupported protocol being specified.
|
||||
:rtype: DeviceProtocolController
|
||||
)");
|
||||
extern "C" RENDERDOC_API IDeviceProtocolController *RENDERDOC_CC
|
||||
RENDERDOC_GetDeviceProtocolController(const rdcstr &protocol);
|
||||
|
||||
DOCUMENT("Internal function that runs unit tests.");
|
||||
extern "C" RENDERDOC_API int RENDERDOC_CC RENDERDOC_RunUnitTests(const rdcstr &command,
|
||||
|
||||
@@ -136,7 +136,11 @@ enum
|
||||
RenderDoc_FirstTargetControlPort = 38920,
|
||||
RenderDoc_LastTargetControlPort = RenderDoc_FirstTargetControlPort + 7,
|
||||
RenderDoc_RemoteServerPort = 39920,
|
||||
RenderDoc_AndroidPortOffset = 50,
|
||||
|
||||
RenderDoc_ForwardPortBase = 38950,
|
||||
RenderDoc_ForwardTargetControlOffset = 0,
|
||||
RenderDoc_ForwardRemoteServerOffset = 9,
|
||||
RenderDoc_ForwardPortStride = 10,
|
||||
};
|
||||
|
||||
#define RENDERDOC_VULKAN_LAYER_NAME "VK_LAYER_RENDERDOC_Capture"
|
||||
|
||||
@@ -1038,6 +1038,16 @@ void RenderDoc::RegisterCaptureImportExporter(CaptureImporter importer, CaptureE
|
||||
m_Exporters[filetype] = exporter;
|
||||
}
|
||||
|
||||
void RenderDoc::RegisterDeviceProtocol(const rdcstr &protocol, ProtocolHandler handler)
|
||||
{
|
||||
if(m_Protocols[protocol] != NULL)
|
||||
{
|
||||
RDCERR("Duplicate protocol registration: %s", protocol.c_str());
|
||||
return;
|
||||
}
|
||||
m_Protocols[protocol] = handler;
|
||||
}
|
||||
|
||||
StructuredProcessor RenderDoc::GetStructuredProcessor(RDCDriver driver)
|
||||
{
|
||||
auto it = m_StructProcesssors.find(driver);
|
||||
@@ -1074,6 +1084,33 @@ CaptureImporter RenderDoc::GetCaptureImporter(const char *filetype)
|
||||
return it->second;
|
||||
}
|
||||
|
||||
rdcarray<rdcstr> RenderDoc::GetSupportedDeviceProtocols()
|
||||
{
|
||||
rdcarray<rdcstr> ret;
|
||||
|
||||
for(auto it = m_Protocols.begin(); it != m_Protocols.end(); ++it)
|
||||
ret.push_back(it->first);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IDeviceProtocolHandler *RenderDoc::GetDeviceProtocol(const rdcstr &protocol)
|
||||
{
|
||||
rdcstr p = protocol;
|
||||
|
||||
// allow passing in an URL with ://
|
||||
int32_t offs = p.find("://");
|
||||
if(offs >= 0)
|
||||
p.erase(offs, p.size() - offs);
|
||||
|
||||
auto it = m_Protocols.find(p);
|
||||
|
||||
if(it != m_Protocols.end())
|
||||
return it->second();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<CaptureFileFormat> RenderDoc::GetCaptureFileFormats()
|
||||
{
|
||||
std::vector<CaptureFileFormat> ret = m_ImportExportFormats;
|
||||
|
||||
+37
-1
@@ -58,6 +58,24 @@ struct IFrameCapturer
|
||||
virtual bool DiscardFrameCapture(void *dev, void *wnd) = 0;
|
||||
};
|
||||
|
||||
// for protocols, we extend the public interface a bit to add callbacks for remapping connection
|
||||
// ports (typically to some port forwarded on localhost)
|
||||
struct IDeviceProtocolHandler : public IDeviceProtocolController
|
||||
{
|
||||
virtual rdcstr GetDeviceID(const rdcstr &URL)
|
||||
{
|
||||
rdcstr ret = URL;
|
||||
int offs = ret.find("://");
|
||||
if(offs > 0)
|
||||
ret.erase(0, offs + 3);
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual rdcstr RemapHostname(const rdcstr &deviceID) = 0;
|
||||
virtual uint16_t RemapPort(const rdcstr &deviceID, uint16_t srcPort) = 0;
|
||||
virtual IRemoteServer *CreateRemoteServer(Network::Socket *sock, const rdcstr &deviceID) = 0;
|
||||
};
|
||||
|
||||
// In most cases you don't need to check these individually, use the utility functions below
|
||||
// to determine if you're in a capture or replay state. There are utility functions for each
|
||||
// state as well.
|
||||
@@ -155,7 +173,7 @@ enum class SystemChunk : uint32_t
|
||||
|
||||
DECLARE_REFLECTION_ENUM(SystemChunk);
|
||||
|
||||
enum class RDCDriver
|
||||
enum class RDCDriver : uint32_t
|
||||
{
|
||||
Unknown = 0,
|
||||
D3D11 = 1,
|
||||
@@ -328,6 +346,7 @@ typedef ReplayStatus (*CaptureImporter)(const char *filename, StreamReader &read
|
||||
typedef ReplayStatus (*CaptureExporter)(const char *filename, const RDCFile &rdc,
|
||||
const SDFile &structData,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
typedef IDeviceProtocolHandler *(*ProtocolHandler)();
|
||||
|
||||
typedef bool (*VulkanLayerCheck)(VulkanLayerFlags &flags, std::vector<std::string> &myJSONs,
|
||||
std::vector<std::string> &otherJSONs);
|
||||
@@ -406,6 +425,7 @@ public:
|
||||
const GlobalEnvironment GetGlobalEnvironment() { return m_GlobalEnv; }
|
||||
void ProcessGlobalEnvironment(GlobalEnvironment env, const std::vector<std::string> &args);
|
||||
|
||||
int32_t GetForwardedPortSlot() { return Atomic::Inc32(&m_PortSlot); }
|
||||
void RegisterShutdownFunction(ShutdownFunction func) { m_ShutdownFunctions.insert(func); }
|
||||
void SetReplayApp(bool replay) { m_Replay = replay; }
|
||||
bool IsReplayApp() const { return m_Replay; }
|
||||
@@ -465,12 +485,16 @@ public:
|
||||
void RegisterCaptureExporter(CaptureExporter exporter, CaptureFileFormat description);
|
||||
void RegisterCaptureImportExporter(CaptureImporter importer, CaptureExporter exporter,
|
||||
CaptureFileFormat description);
|
||||
void RegisterDeviceProtocol(const rdcstr &protocol, ProtocolHandler handler);
|
||||
|
||||
StructuredProcessor GetStructuredProcessor(RDCDriver driver);
|
||||
|
||||
CaptureExporter GetCaptureExporter(const char *filetype);
|
||||
CaptureImporter GetCaptureImporter(const char *filetype);
|
||||
|
||||
rdcarray<rdcstr> GetSupportedDeviceProtocols();
|
||||
IDeviceProtocolHandler *GetDeviceProtocol(const rdcstr &protocol);
|
||||
|
||||
std::vector<CaptureFileFormat> GetCaptureFileFormats();
|
||||
|
||||
void SetVulkanLayerCheck(VulkanLayerCheck callback) { m_VulkanCheck = callback; }
|
||||
@@ -590,6 +614,8 @@ private:
|
||||
|
||||
GlobalEnvironment m_GlobalEnv;
|
||||
|
||||
int32_t m_PortSlot = 0;
|
||||
|
||||
FrameTimer m_FrameTimer;
|
||||
|
||||
std::string m_LoggingFilename;
|
||||
@@ -628,6 +654,8 @@ private:
|
||||
std::map<std::string, CaptureImporter> m_Importers;
|
||||
std::map<std::string, CaptureExporter> m_Exporters;
|
||||
|
||||
std::map<rdcstr, ProtocolHandler> m_Protocols;
|
||||
|
||||
VulkanLayerCheck m_VulkanCheck;
|
||||
VulkanLayerInstall m_VulkanInstall;
|
||||
|
||||
@@ -725,4 +753,12 @@ struct ConversionRegistration
|
||||
{
|
||||
RenderDoc::Inst().RegisterCaptureExporter(exporter, description);
|
||||
}
|
||||
};
|
||||
|
||||
struct DeviceProtocolRegistration
|
||||
{
|
||||
DeviceProtocolRegistration(const rdcstr &protocol, ProtocolHandler handler)
|
||||
{
|
||||
RenderDoc::Inst().RegisterDeviceProtocol(protocol, handler);
|
||||
}
|
||||
};
|
||||
+782
-1011
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
|
||||
namespace Network
|
||||
{
|
||||
class Socket;
|
||||
};
|
||||
|
||||
enum class RDCDriver : uint32_t;
|
||||
|
||||
class WriteSerialiser;
|
||||
class ReadSerialiser;
|
||||
|
||||
struct RemoteServer : public IRemoteServer
|
||||
{
|
||||
public:
|
||||
RemoteServer(Network::Socket *sock, const rdcstr &deviceID);
|
||||
|
||||
virtual ~RemoteServer();
|
||||
|
||||
virtual void ShutdownConnection();
|
||||
|
||||
virtual void ShutdownServerAndConnection();
|
||||
|
||||
virtual bool Connected();
|
||||
virtual bool Ping();
|
||||
|
||||
virtual rdcarray<rdcstr> LocalProxies();
|
||||
|
||||
virtual rdcarray<rdcstr> RemoteSupportedReplays();
|
||||
|
||||
virtual rdcstr GetHomeFolder();
|
||||
|
||||
virtual rdcarray<PathEntry> ListFolder(const char *path);
|
||||
|
||||
virtual ExecuteResult ExecuteAndInject(const char *a, const char *w, const char *c,
|
||||
const rdcarray<EnvironmentModification> &env,
|
||||
const CaptureOptions &opts);
|
||||
|
||||
virtual void CopyCaptureFromRemote(const char *remotepath, const char *localpath,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
|
||||
virtual rdcstr CopyCaptureToRemote(const char *filename, RENDERDOC_ProgressCallback progress);
|
||||
|
||||
virtual void TakeOwnershipCapture(const char *filename);
|
||||
|
||||
virtual rdcpair<ReplayStatus, IReplayController *> OpenCapture(uint32_t proxyid,
|
||||
const char *filename,
|
||||
RENDERDOC_ProgressCallback progress);
|
||||
|
||||
virtual void CloseCapture(IReplayController *rend);
|
||||
|
||||
virtual rdcstr DriverName();
|
||||
|
||||
virtual int GetSectionCount();
|
||||
|
||||
virtual int FindSectionByName(const char *name);
|
||||
|
||||
virtual int FindSectionByType(SectionType sectionType);
|
||||
|
||||
virtual SectionProperties GetSectionProperties(int index);
|
||||
|
||||
virtual bytebuf GetSectionContents(int index);
|
||||
|
||||
virtual bool WriteSection(const SectionProperties &props, const bytebuf &contents);
|
||||
|
||||
virtual bool HasCallstacks();
|
||||
|
||||
virtual bool InitResolver(RENDERDOC_ProgressCallback progress);
|
||||
|
||||
virtual rdcarray<rdcstr> GetResolve(const rdcarray<uint64_t> &callstack);
|
||||
|
||||
protected:
|
||||
Network::Socket *m_Socket;
|
||||
WriteSerialiser *writer;
|
||||
ReadSerialiser *reader;
|
||||
rdcstr m_deviceID;
|
||||
|
||||
rdcarray<rdcpair<RDCDriver, rdcstr>> m_Proxies;
|
||||
};
|
||||
@@ -861,24 +861,28 @@ private:
|
||||
};
|
||||
|
||||
extern "C" RENDERDOC_API ITargetControl *RENDERDOC_CC RENDERDOC_CreateTargetControl(
|
||||
const char *host, uint32_t ident, const char *clientName, bool forceConnection)
|
||||
const char *URL, uint32_t ident, const char *clientName, bool forceConnection)
|
||||
{
|
||||
std::string s = "localhost";
|
||||
if(host != NULL && host[0] != '\0')
|
||||
s = host;
|
||||
rdcstr host = "localhost";
|
||||
if(URL != NULL && URL[0] != '\0')
|
||||
host = URL;
|
||||
|
||||
bool android = false;
|
||||
rdcstr deviceID = host;
|
||||
uint16_t port = ident & 0xffff;
|
||||
|
||||
if(host != NULL && Android::IsHostADB(host))
|
||||
IDeviceProtocolHandler *protocol = RenderDoc::Inst().GetDeviceProtocol(deviceID);
|
||||
|
||||
if(protocol)
|
||||
{
|
||||
android = true;
|
||||
s = "127.0.0.1";
|
||||
deviceID = protocol->GetDeviceID(deviceID);
|
||||
host = protocol->RemapHostname(deviceID);
|
||||
if(host.empty())
|
||||
return NULL;
|
||||
|
||||
// we don't need the index or device ID here, because the port is already the right one
|
||||
// forwarded to the right device.
|
||||
port = protocol->RemapPort(deviceID, port);
|
||||
}
|
||||
|
||||
Network::Socket *sock = Network::CreateClientSocket(s.c_str(), ident & 0xffff, 750);
|
||||
Network::Socket *sock = Network::CreateClientSocket(host.c_str(), port, 750);
|
||||
|
||||
if(sock == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -188,6 +188,7 @@
|
||||
<ClInclude Include="core\intervals.h" />
|
||||
<ClInclude Include="core\plugins.h" />
|
||||
<ClInclude Include="core\precompiled.h" />
|
||||
<ClInclude Include="core\remote_server.h" />
|
||||
<ClInclude Include="core\replay_proxy.h" />
|
||||
<ClInclude Include="core\resource_manager.h" />
|
||||
<ClInclude Include="data\embedded_files.h" />
|
||||
|
||||
@@ -486,6 +486,9 @@
|
||||
<ClInclude Include="core\bit_flag_iterator.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="core\remote_server.h">
|
||||
<Filter>Core\networking</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="maths\camera.cpp">
|
||||
|
||||
@@ -376,12 +376,14 @@ extern "C" RENDERDOC_API void *RENDERDOC_CC RENDERDOC_AllocArrayMem(uint64_t sz)
|
||||
return malloc((size_t)sz);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(const char *host,
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(const char *URL,
|
||||
uint32_t nextIdent)
|
||||
{
|
||||
std::string s = "localhost";
|
||||
if(host != NULL && host[0] != '\0')
|
||||
s = host;
|
||||
rdcstr host = "localhost";
|
||||
if(URL != NULL && URL[0] != '\0')
|
||||
host = URL;
|
||||
|
||||
rdcstr deviceID = host;
|
||||
|
||||
// initial case is we're called with 0, start with the first port.
|
||||
// otherwise we're called with the last successful ident, so increment
|
||||
@@ -391,32 +393,30 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(
|
||||
else
|
||||
nextIdent++;
|
||||
|
||||
bool isAndroid = false;
|
||||
uint32_t lastIdent = RenderDoc_LastTargetControlPort;
|
||||
if(host != NULL && Android::IsHostADB(host))
|
||||
IDeviceProtocolHandler *protocol = RenderDoc::Inst().GetDeviceProtocol(deviceID);
|
||||
|
||||
if(protocol)
|
||||
{
|
||||
int index = 0;
|
||||
std::string deviceID;
|
||||
Android::ExtractDeviceIDAndIndex(host, index, deviceID);
|
||||
|
||||
isAndroid = true;
|
||||
|
||||
// each subsequent device gets a new range of ports. The deviceID isn't needed since we already
|
||||
// forwarded the ports to the right devices.
|
||||
if(nextIdent == RenderDoc_FirstTargetControlPort)
|
||||
nextIdent += RenderDoc_AndroidPortOffset * (index + 1);
|
||||
lastIdent += RenderDoc_AndroidPortOffset * (index + 1);
|
||||
|
||||
s = "127.0.0.1";
|
||||
deviceID = protocol->GetDeviceID(deviceID);
|
||||
host = protocol->RemapHostname(deviceID);
|
||||
if(host.empty())
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(; nextIdent <= lastIdent; nextIdent++)
|
||||
for(; nextIdent <= RenderDoc_LastTargetControlPort; nextIdent++)
|
||||
{
|
||||
Network::Socket *sock = Network::CreateClientSocket(s.c_str(), (uint16_t)nextIdent, 250);
|
||||
uint16_t port = (uint16_t)nextIdent;
|
||||
if(protocol)
|
||||
port = protocol->RemapPort(deviceID, port);
|
||||
|
||||
if(port == 0)
|
||||
return 0;
|
||||
|
||||
Network::Socket *sock = Network::CreateClientSocket(host.c_str(), port, 250);
|
||||
|
||||
if(sock)
|
||||
{
|
||||
if(isAndroid)
|
||||
if(protocol)
|
||||
{
|
||||
Threading::Sleep(100);
|
||||
(void)sock->IsRecvDataWaiting();
|
||||
@@ -436,14 +436,21 @@ extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_EnumerateRemoteTargets(
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API uint32_t RENDERDOC_CC RENDERDOC_GetDefaultRemoteServerPort()
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_GetSupportedDeviceProtocols(rdcarray<rdcstr> *supportedProtocols)
|
||||
{
|
||||
return RenderDoc_RemoteServerPort;
|
||||
*supportedProtocols = RenderDoc::Inst().GetSupportedDeviceProtocols();
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
|
||||
const char *listenhost, uint32_t port, RENDERDOC_KillCallback killReplay,
|
||||
RENDERDOC_PreviewWindowCallback previewWindow)
|
||||
extern "C" RENDERDOC_API IDeviceProtocolController *RENDERDOC_CC
|
||||
RENDERDOC_GetDeviceProtocolController(const rdcstr &protocol)
|
||||
{
|
||||
return RenderDoc::Inst().GetDeviceProtocol(protocol);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC
|
||||
RENDERDOC_BecomeRemoteServer(const char *listenhost, RENDERDOC_KillCallback killReplay,
|
||||
RENDERDOC_PreviewWindowCallback previewWindow)
|
||||
{
|
||||
if(listenhost == NULL || listenhost[0] == 0)
|
||||
listenhost = "0.0.0.0";
|
||||
@@ -459,10 +466,8 @@ extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_BecomeRemoteServer(
|
||||
return ret;
|
||||
};
|
||||
|
||||
if(port == 0)
|
||||
port = RENDERDOC_GetDefaultRemoteServerPort();
|
||||
|
||||
RenderDoc::Inst().BecomeRemoteServer(listenhost, (uint16_t)port, killReplay, previewWindow);
|
||||
RenderDoc::Inst().BecomeRemoteServer(listenhost, RenderDoc_RemoteServerPort, killReplay,
|
||||
previewWindow);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_StartSelfHostCapture(const char *dllname)
|
||||
|
||||
@@ -461,8 +461,6 @@ struct RemoteServerCommand : public Command
|
||||
parser.add("daemon", 'd', "Go into the background.");
|
||||
parser.add<std::string>(
|
||||
"host", 'h', "The interface to listen on. By default listens on all interfaces", false, "");
|
||||
parser.add<uint32_t>("port", 'p', "The port to listen on.", false,
|
||||
RENDERDOC_GetDefaultRemoteServerPort());
|
||||
parser.add("preview", 'v', "Display a preview window when a replay is active.");
|
||||
}
|
||||
virtual const char *Description()
|
||||
@@ -474,12 +472,11 @@ struct RemoteServerCommand : public Command
|
||||
virtual int Execute(cmdline::parser &parser, const CaptureOptions &)
|
||||
{
|
||||
std::string host = parser.get<std::string>("host");
|
||||
uint32_t port = parser.get<uint32_t>("port");
|
||||
|
||||
RENDERDOC_InitGlobalEnv(m_Env, convertArgs(parser.rest()));
|
||||
|
||||
std::cerr << "Spawning a replay host listening on " << (host.empty() ? "*" : host) << ":"
|
||||
<< port << "..." << std::endl;
|
||||
std::cerr << "Spawning a replay host listening on " << (host.empty() ? "*" : host) << "..."
|
||||
<< std::endl;
|
||||
|
||||
if(parser.exist("daemon"))
|
||||
{
|
||||
@@ -500,8 +497,8 @@ struct RemoteServerCommand : public Command
|
||||
if(DisplayRemoteServerPreview(false, {}).system != WindowingSystem::Unknown)
|
||||
previewWindow = &DisplayRemoteServerPreview;
|
||||
|
||||
RENDERDOC_BecomeRemoteServer(host.empty() ? NULL : host.c_str(), port,
|
||||
[]() { return killSignal; }, previewWindow);
|
||||
RENDERDOC_BecomeRemoteServer(host.empty() ? NULL : host.c_str(), []() { return killSignal; },
|
||||
previewWindow);
|
||||
|
||||
std::cerr << std::endl << "Cleaning up from replay hosting." << std::endl;
|
||||
|
||||
@@ -522,8 +519,6 @@ struct ReplayCommand : public Command
|
||||
parser.add<std::string>("remote-host", 0,
|
||||
"Instead of replaying locally, replay on this host over the network.",
|
||||
false);
|
||||
parser.add<uint32_t>("remote-port", 0, "If --remote-host is set, use this port.", false,
|
||||
RENDERDOC_GetDefaultRemoteServerPort());
|
||||
}
|
||||
virtual const char *Description()
|
||||
{
|
||||
@@ -551,18 +546,16 @@ struct ReplayCommand : public Command
|
||||
if(parser.exist("remote-host"))
|
||||
{
|
||||
std::cout << "Replaying '" << filename << "' on " << parser.get<std::string>("remote-host")
|
||||
<< ":" << parser.get<uint32_t>("remote-port") << "." << std::endl;
|
||||
<< "." << std::endl;
|
||||
|
||||
IRemoteServer *remote = NULL;
|
||||
ReplayStatus status =
|
||||
RENDERDOC_CreateRemoteServerConnection(parser.get<std::string>("remote-host").c_str(),
|
||||
parser.get<uint32_t>("remote-port"), &remote);
|
||||
ReplayStatus status = RENDERDOC_CreateRemoteServerConnection(
|
||||
parser.get<std::string>("remote-host").c_str(), &remote);
|
||||
|
||||
if(remote == NULL || status != ReplayStatus::Succeeded)
|
||||
{
|
||||
std::cerr << "Error: " << ToStr(status) << " - Couldn't connect to "
|
||||
<< parser.get<std::string>("remote-host") << ":"
|
||||
<< parser.get<uint32_t>("remote-port") << "." << std::endl;
|
||||
<< parser.get<std::string>("remote-host") << "." << std::endl;
|
||||
std::cerr << " Have you run renderdoccmd remoteserver on '"
|
||||
<< parser.get<std::string>("remote-host") << "'?" << std::endl;
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user