зеркало из https://github.com/AvaloniaUI/angle.git
Enable frame capture on Android
This CL gets capture/replay working on Android again. * Updates where Android frame captures are written * Uses debug system properties to prime Android environment variables * Adds a configurable target Context to the capture_replay sample * Updates capture/replay documentation for Android Bug: angleproject:4036 Test: Captured TRex on Android, replayed on Linux Change-Id: I94b4f6dc77468cd179b9d884b4dcd4afa56bd28c Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1928056 Reviewed-by: Courtney Goeltzenleuchter <courtneygo@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Cody Northrop <cnorthrop@google.com>
This commit is contained in:
Родитель
d32650bb9e
Коммит
6430e5e003
|
@ -68,3 +68,66 @@ $ ANGLE_CAPTURE_ENABLED=0 out/Debug/capture_replay_sample
|
|||
```
|
||||
|
||||
Note that we specify `ANGLE_CAPTURE_ENABLED=0` to prevent re-capturing when running the replay.
|
||||
|
||||
## Capturing an Android application
|
||||
|
||||
In order to capture on Android, the following additional steps must be taken. These steps
|
||||
presume you've built and installed the ANGLE APK with capture enabled, and selected ANGLE
|
||||
as the GLES driver for your application.
|
||||
|
||||
1. Create the output directory
|
||||
|
||||
Determine your package name:
|
||||
```
|
||||
export PACKAGE_NAME com.android.gl2jni
|
||||
```
|
||||
Then create an output directory that it can write to:
|
||||
```
|
||||
$ adb shell mkdir -p /sdcard/Android/data/$PACKAGE_NAME/angle_capture
|
||||
```
|
||||
|
||||
2. Set properties to use for environment variable
|
||||
|
||||
On Android, it is difficult to set an environment variable before starting native code.
|
||||
To work around this, ANGLE will read debug system properties before starting the capture
|
||||
and use them to prime environment variables used by the capture code.
|
||||
|
||||
Note: Mid-execution capture doesn't work for Android just yet, so frame_start must be
|
||||
zero, which is the default. This it is sufficient to only set the end frame.
|
||||
```
|
||||
$ adb shell setprop debug.angle.capture.frame_end 200
|
||||
```
|
||||
|
||||
There are other properties that can be set that match 1:1 with the env vars, but
|
||||
they are not required for capture:
|
||||
```
|
||||
# Optional
|
||||
$ adb shell setprop debug.angle.capture.enabled 0
|
||||
$ adb shell setprop debug.angle.capture.out_dir foo
|
||||
$ adb shell setprop debug.angle.capture.frame_start 0
|
||||
```
|
||||
|
||||
3. Run the application, then pull the files to the capture_replay directory
|
||||
```
|
||||
$ cd samples/capture_replay
|
||||
$ adb pull /sdcard/Android/data/$PACKAGE_NAME/angle_capture replay_files
|
||||
$ cp replay_files/* .
|
||||
```
|
||||
|
||||
4. Update your GN args to specifiy which context will be replayed.
|
||||
|
||||
By default Context ID 1 will be replayed. On Android, Context ID 2 is more typical, some apps
|
||||
we've run go as high as ID 6.
|
||||
Note: this solution is temporary until EGL capture is in place.
|
||||
```
|
||||
angle_capture_replay_sample_context_id = 2
|
||||
```
|
||||
|
||||
5. Replay the capture on desktop
|
||||
|
||||
Until we have samples building for Android, the replay sample must be run on desktop.
|
||||
We will also be plumbing replay files into perf and correctness tests which will run on Android.
|
||||
```
|
||||
$ autoninja -C out/Release capture_replay_sample
|
||||
$ out/Release/capture_replay_sample
|
||||
```
|
|
@ -7,6 +7,9 @@ import("../gni/angle.gni")
|
|||
declare_args() {
|
||||
# Determines if we build the capture_replay sample. Off by default.
|
||||
angle_build_capture_replay_sample = false
|
||||
|
||||
# Decide which context to replay, starting with desktop default
|
||||
angle_capture_replay_sample_context_id = 1
|
||||
}
|
||||
|
||||
angle_executable("shader_translator") {
|
||||
|
@ -228,17 +231,26 @@ if (angle_build_capture_replay_sample) {
|
|||
# To use the capture replay sample first move your capture sources into
|
||||
# the capture_replay folder and enable the gn arg above.
|
||||
angle_sample("capture_replay_sample") {
|
||||
_contextid = angle_capture_replay_sample_context_id
|
||||
sources =
|
||||
rebase_path(read_file("capture_replay/angle_capture_context1_files.txt",
|
||||
"list lines"), ".", "capture_replay") +
|
||||
rebase_path(
|
||||
read_file(
|
||||
"capture_replay/angle_capture_context${_contextid}_files.txt",
|
||||
"list lines"),
|
||||
".",
|
||||
"capture_replay") +
|
||||
[
|
||||
"capture_replay/CaptureReplay.cpp",
|
||||
"capture_replay/angle_capture_context1.cpp",
|
||||
"capture_replay/angle_capture_context1.h",
|
||||
"capture_replay/angle_capture_context${_contextid}.cpp",
|
||||
"capture_replay/angle_capture_context${_contextid}.h",
|
||||
]
|
||||
|
||||
_data_path = rebase_path("capture_replay", root_out_dir)
|
||||
defines = [ "ANGLE_CAPTURE_REPLAY_SAMPLE_DATA_DIR=\"${_data_path}\"" ]
|
||||
defines = [
|
||||
"ANGLE_CAPTURE_REPLAY_SAMPLE_DATA_DIR=\"${_data_path}\"",
|
||||
"ANGLE_CAPTURE_REPLAY_SAMPLE_CONTEXT_ID=${_contextid}",
|
||||
"ANGLE_CAPTURE_REPLAY_SAMPLE_HEADER=angle_capture_context${_contextid}.h",
|
||||
]
|
||||
suppressed_configs = [ "$angle_root:constructor_and_destructor_warnings" ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,24 @@
|
|||
|
||||
#include "SampleApplication.h"
|
||||
|
||||
#include "angle_capture_context1.h"
|
||||
#include <functional>
|
||||
|
||||
#define ANGLE_MACRO_STRINGIZE_AUX(a) #a
|
||||
#define ANGLE_MACRO_STRINGIZE(a) ANGLE_MACRO_STRINGIZE_AUX(a)
|
||||
#define ANGLE_MACRO_CONCAT_AUX(a, b) a##b
|
||||
#define ANGLE_MACRO_CONCAT(a, b) ANGLE_MACRO_CONCAT_AUX(a, b)
|
||||
|
||||
// Build the right context header based on replay ID
|
||||
// This will expand to "angle_capture_context<#>.h"
|
||||
#include ANGLE_MACRO_STRINGIZE(ANGLE_CAPTURE_REPLAY_SAMPLE_HEADER)
|
||||
|
||||
// Assign the context numbered functions based on GN arg selecting replay ID
|
||||
std::function<void()> SetupContextReplay = reinterpret_cast<void (*)()>(
|
||||
ANGLE_MACRO_CONCAT(SetupContext,
|
||||
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_SAMPLE_CONTEXT_ID, Replay)));
|
||||
std::function<void(int)> ReplayContextFrame = reinterpret_cast<void (*)(int)>(
|
||||
ANGLE_MACRO_CONCAT(ReplayContext,
|
||||
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_SAMPLE_CONTEXT_ID, Frame)));
|
||||
|
||||
class CaptureReplaySample : public SampleApplication
|
||||
{
|
||||
|
@ -23,7 +40,7 @@ class CaptureReplaySample : public SampleApplication
|
|||
if (!angle::SetCWD(exeDir.c_str()))
|
||||
return false;
|
||||
SetBinaryDataDir(ANGLE_CAPTURE_REPLAY_SAMPLE_DATA_DIR);
|
||||
SetupContext1Replay();
|
||||
SetupContextReplay();
|
||||
|
||||
eglSwapInterval(getDisplay(), 1);
|
||||
return true;
|
||||
|
@ -36,7 +53,7 @@ class CaptureReplaySample : public SampleApplication
|
|||
// Compute the current frame, looping from kReplayFrameStart to kReplayFrameEnd.
|
||||
uint32_t frame =
|
||||
kReplayFrameStart + (mCurrentFrame % (kReplayFrameEnd - kReplayFrameStart));
|
||||
ReplayContext1Frame(frame);
|
||||
ReplayContextFrame(frame);
|
||||
mCurrentFrame++;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "sys/stat.h"
|
||||
|
||||
#include "common/system_utils.h"
|
||||
#include "libANGLE/Context.h"
|
||||
#include "libANGLE/Framebuffer.h"
|
||||
|
@ -33,6 +35,76 @@ namespace angle
|
|||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
|
||||
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
|
||||
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
|
||||
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
|
||||
|
||||
#if defined(ANGLE_PLATFORM_ANDROID)
|
||||
|
||||
constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
|
||||
constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
|
||||
constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
|
||||
constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
|
||||
|
||||
constexpr int kStreamSize = 64;
|
||||
|
||||
constexpr char kAndroidOutputSubdir[] = "/angle_capture/";
|
||||
|
||||
// Call out to 'getprop' on a shell and return a string if the value was set
|
||||
std::string AndroidGetEnvFromProp(const char *key)
|
||||
{
|
||||
std::string command("getprop ");
|
||||
command += key;
|
||||
|
||||
// Run the command and open a I/O stream to read results
|
||||
char stream[kStreamSize] = {};
|
||||
FILE *pipe = popen(command.c_str(), "r");
|
||||
if (pipe != nullptr)
|
||||
{
|
||||
fgets(stream, kStreamSize, pipe);
|
||||
pclose(pipe);
|
||||
}
|
||||
|
||||
// Right strip white space
|
||||
std::string result(stream);
|
||||
result.erase(result.find_last_not_of(" \n\r\t") + 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void PrimeAndroidEnvironmentVariables()
|
||||
{
|
||||
std::string enabled = AndroidGetEnvFromProp(kAndroidCaptureEnabled);
|
||||
if (!enabled.empty())
|
||||
{
|
||||
INFO() << "Frame capture read " << enabled << " from " << kAndroidCaptureEnabled;
|
||||
setenv(kEnabledVarName, enabled.c_str(), 1);
|
||||
}
|
||||
|
||||
std::string outDir = AndroidGetEnvFromProp(kAndroidOutDir);
|
||||
if (!outDir.empty())
|
||||
{
|
||||
INFO() << "Frame capture read " << outDir << " from " << kAndroidOutDir;
|
||||
setenv(kOutDirectoryVarName, outDir.c_str(), 1);
|
||||
}
|
||||
|
||||
std::string frameStart = AndroidGetEnvFromProp(kAndroidFrameStart);
|
||||
if (!frameStart.empty())
|
||||
{
|
||||
INFO() << "Frame capture read " << frameStart << " from " << kAndroidFrameStart;
|
||||
setenv(kFrameStartVarName, frameStart.c_str(), 1);
|
||||
}
|
||||
|
||||
std::string frameEnd = AndroidGetEnvFromProp(kAndroidFrameEnd);
|
||||
if (!frameEnd.empty())
|
||||
{
|
||||
INFO() << "Frame capture read " << frameEnd << " from " << kAndroidFrameEnd;
|
||||
setenv(kFrameEndVarName, frameEnd.c_str(), 1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string GetDefaultOutDirectory()
|
||||
{
|
||||
#if defined(ANGLE_PLATFORM_ANDROID)
|
||||
|
@ -57,18 +129,23 @@ std::string GetDefaultOutDirectory()
|
|||
{
|
||||
ERR() << "not able to lookup application id";
|
||||
}
|
||||
path += std::string(applicationId) + "/";
|
||||
|
||||
path += std::string(applicationId) + kAndroidOutputSubdir;
|
||||
|
||||
// Check for existance of output path
|
||||
struct stat dir_stat;
|
||||
if (stat(path.c_str(), &dir_stat) == -1)
|
||||
{
|
||||
ERR() << "Output directory '" << path
|
||||
<< "' does not exist. Create it over adb using mkdir.";
|
||||
}
|
||||
|
||||
return path;
|
||||
#else
|
||||
return std::string("./");
|
||||
#endif // defined(ANGLE_PLATFORM_ANDROID)
|
||||
}
|
||||
|
||||
constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
|
||||
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
|
||||
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
|
||||
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
|
||||
|
||||
struct FmtCapturePrefix
|
||||
{
|
||||
FmtCapturePrefix(int contextIdIn) : contextId(contextIdIn) {}
|
||||
|
@ -1751,6 +1828,10 @@ FrameCapture::FrameCapture()
|
|||
{
|
||||
reset();
|
||||
|
||||
#if defined(ANGLE_PLATFORM_ANDROID)
|
||||
PrimeAndroidEnvironmentVariables();
|
||||
#endif
|
||||
|
||||
std::string enabledFromEnv = angle::GetEnvironmentVar(kEnabledVarName);
|
||||
if (enabledFromEnv == "0")
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче