зеркало из https://github.com/AvaloniaUI/angle.git
Capture/Replay: Allow starting capture at an unknown frame
This CL adds a new way to set the start frame of a capture. It adds a new environment variable called ANGLE_CAPTURE_TRIGGER that, when set, will be used instead of frame start and end. By setting ANGLE_CAPTURE_TRIGGER to a non-zero value, ANGLE will capture that many frames when the value changes. For example, on Android, we can set it with: adb shell setprop debug.angle.capture.trigger 20 When we reach the target content, set the value back to zero: adb shell setprop debug.angle.capture.trigger 0 and ANGLE will start capturing 20 frames. Currently only hooked up for Android, but should be possible to support on other platforms. Test: Capture application frames using trigger Bug: angleproject:4949 Change-Id: I469ef5c48feb78c85b8cda2fefd5df59e495bbe2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2347858 Commit-Queue: Cody Northrop <cnorthrop@google.com> Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Manh Nguyen <nguyenmh@google.com>
This commit is contained in:
Родитель
48d951e22d
Коммит
a7cbb3f06f
|
@ -167,6 +167,25 @@ as the GLES driver for your application.
|
||||||
$ out/Release/capture_replay_sample
|
$ out/Release/capture_replay_sample
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Starting capture at an arbitrary frame
|
||||||
|
In some scenarios, you don't know which frame you want to start on. You'll only know when target
|
||||||
|
content is being rendered. For that we've added a trigger that can allow starting the capture at
|
||||||
|
any time.
|
||||||
|
|
||||||
|
To use it, set the following environment variable, in addition to all the setup steps above. Set
|
||||||
|
the trigger value equal to the number of frames you'd like to capture.
|
||||||
|
```
|
||||||
|
adb shell setprop debug.angle.capture.trigger 20
|
||||||
|
```
|
||||||
|
When this value is set, `ANGLE_CAPTURE_FRAME_START` and `ANGLE_CAPTURE_FRAME_END` will be ignored.
|
||||||
|
|
||||||
|
While your content is rendering, wait until you arrive at the scene you'd like to capture. Then
|
||||||
|
set the value back to zero:
|
||||||
|
```
|
||||||
|
adb shell setprop debug.angle.capture.trigger 0
|
||||||
|
```
|
||||||
|
ANGLE will detect this change and start recording the requested number of frames.
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
### Regression Testing Architecture
|
### Regression Testing Architecture
|
||||||
|
|
|
@ -51,6 +51,7 @@ constexpr char kEnabledVarName[] = "ANGLE_CAPTURE_ENABLED";
|
||||||
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
|
constexpr char kOutDirectoryVarName[] = "ANGLE_CAPTURE_OUT_DIR";
|
||||||
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
|
constexpr char kFrameStartVarName[] = "ANGLE_CAPTURE_FRAME_START";
|
||||||
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
|
constexpr char kFrameEndVarName[] = "ANGLE_CAPTURE_FRAME_END";
|
||||||
|
constexpr char kCaptureTriggerVarName[] = "ANGLE_CAPTURE_TRIGGER";
|
||||||
constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
|
constexpr char kCaptureLabel[] = "ANGLE_CAPTURE_LABEL";
|
||||||
constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
|
constexpr char kCompression[] = "ANGLE_CAPTURE_COMPRESSION";
|
||||||
constexpr char kSerializeStateEnabledVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
|
constexpr char kSerializeStateEnabledVarName[] = "ANGLE_CAPTURE_SERIALIZE_STATE";
|
||||||
|
@ -67,6 +68,7 @@ constexpr char kAndroidCaptureEnabled[] = "debug.angle.capture.enabled";
|
||||||
constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
|
constexpr char kAndroidOutDir[] = "debug.angle.capture.out_dir";
|
||||||
constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
|
constexpr char kAndroidFrameStart[] = "debug.angle.capture.frame_start";
|
||||||
constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
|
constexpr char kAndroidFrameEnd[] = "debug.angle.capture.frame_end";
|
||||||
|
constexpr char kAndroidCaptureTrigger[] = "debug.angle.capture.trigger";
|
||||||
constexpr char kAndroidCaptureLabel[] = "debug.angle.capture.label";
|
constexpr char kAndroidCaptureLabel[] = "debug.angle.capture.label";
|
||||||
constexpr char kAndroidCompression[] = "debug.angle.capture.compression";
|
constexpr char kAndroidCompression[] = "debug.angle.capture.compression";
|
||||||
|
|
||||||
|
@ -125,6 +127,13 @@ void PrimeAndroidEnvironmentVariables()
|
||||||
setenv(kFrameEndVarName, frameEnd.c_str(), 1);
|
setenv(kFrameEndVarName, frameEnd.c_str(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string captureTrigger = AndroidGetEnvFromProp(kAndroidCaptureTrigger);
|
||||||
|
if (!captureTrigger.empty())
|
||||||
|
{
|
||||||
|
INFO() << "Capture trigger read " << captureTrigger << " from " << kAndroidCaptureTrigger;
|
||||||
|
setenv(kCaptureTriggerVarName, captureTrigger.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
std::string captureLabel = AndroidGetEnvFromProp(kAndroidCaptureLabel);
|
std::string captureLabel = AndroidGetEnvFromProp(kAndroidCaptureLabel);
|
||||||
if (!captureLabel.empty())
|
if (!captureLabel.empty())
|
||||||
{
|
{
|
||||||
|
@ -182,6 +191,15 @@ std::string GetDefaultOutDirectory()
|
||||||
#endif // defined(ANGLE_PLATFORM_ANDROID)
|
#endif // defined(ANGLE_PLATFORM_ANDROID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetCaptureTrigger()
|
||||||
|
{
|
||||||
|
#if defined(ANGLE_PLATFORM_ANDROID)
|
||||||
|
return AndroidGetEnvFromProp(kAndroidCaptureTrigger);
|
||||||
|
#else
|
||||||
|
return std::string();
|
||||||
|
#endif // defined(ANGLE_PLATFORM_ANDROID)
|
||||||
|
}
|
||||||
|
|
||||||
struct FmtCapturePrefix
|
struct FmtCapturePrefix
|
||||||
{
|
{
|
||||||
FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
|
FmtCapturePrefix(gl::ContextID contextIdIn, const std::string &captureLabelIn)
|
||||||
|
@ -3356,7 +3374,8 @@ FrameCapture::FrameCapture()
|
||||||
mFrameEnd(10),
|
mFrameEnd(10),
|
||||||
mClientArraySizes{},
|
mClientArraySizes{},
|
||||||
mReadBufferSize(0),
|
mReadBufferSize(0),
|
||||||
mHasResourceType{}
|
mHasResourceType{},
|
||||||
|
mCaptureTrigger(0)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
@ -3398,6 +3417,19 @@ FrameCapture::FrameCapture()
|
||||||
mFrameEnd = atoi(endFromEnv.c_str());
|
mFrameEnd = atoi(endFromEnv.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string captureTriggerFromEnv = angle::GetEnvironmentVar(kCaptureTriggerVarName);
|
||||||
|
if (!captureTriggerFromEnv.empty())
|
||||||
|
{
|
||||||
|
mCaptureTrigger = atoi(captureTriggerFromEnv.c_str());
|
||||||
|
|
||||||
|
// If the trigger has been populated, ignore the other frame range variables by setting them
|
||||||
|
// to unreasonable values. This isn't perfect, but it is effective.
|
||||||
|
// TODO (anglebug.com/4949): Improve this, possibly by moving away from default start frame.
|
||||||
|
mFrameStart = mFrameEnd = std::numeric_limits<uint32_t>::max();
|
||||||
|
INFO() << "Capture trigger detected, overriding mFrameStart and mFrameEnd to "
|
||||||
|
<< mFrameStart;
|
||||||
|
}
|
||||||
|
|
||||||
std::string labelFromEnv = angle::GetEnvironmentVar(kCaptureLabel);
|
std::string labelFromEnv = angle::GetEnvironmentVar(kCaptureLabel);
|
||||||
if (!labelFromEnv.empty())
|
if (!labelFromEnv.empty())
|
||||||
{
|
{
|
||||||
|
@ -4065,8 +4097,43 @@ void FrameCapture::captureMappedBufferSnapshot(const gl::Context *context, const
|
||||||
(void)buffer->unmap(context, &dontCare);
|
(void)buffer->unmap(context, &dontCare);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FrameCapture::checkForCaptureTrigger()
|
||||||
|
{
|
||||||
|
// If the capture trigger has not been set, move on
|
||||||
|
if (mCaptureTrigger == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Otherwise, poll the value for a change
|
||||||
|
std::string captureTriggerStr = GetCaptureTrigger();
|
||||||
|
if (captureTriggerStr.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the value has changed, use the original value as the frame count
|
||||||
|
// TODO (anglebug.com/4949): Improve capture at unknown frame time. It is good to
|
||||||
|
// avoid polling if the feature is not enabled, but not entirely intuitive to set
|
||||||
|
// a value to zero when you want to trigger it.
|
||||||
|
uint32_t captureTrigger = atoi(captureTriggerStr.c_str());
|
||||||
|
if (captureTrigger != mCaptureTrigger)
|
||||||
|
{
|
||||||
|
// Start mid-execution capture for the next frame
|
||||||
|
mFrameStart = mFrameIndex + 1;
|
||||||
|
|
||||||
|
// Use the original trigger value as the frame count
|
||||||
|
mFrameEnd = mFrameStart + (mCaptureTrigger - 1);
|
||||||
|
|
||||||
|
INFO() << "Capture triggered at frame " << mFrameStart << " for " << mCaptureTrigger
|
||||||
|
<< " frames";
|
||||||
|
|
||||||
|
// Stop polling
|
||||||
|
mCaptureTrigger = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FrameCapture::onEndFrame(const gl::Context *context)
|
void FrameCapture::onEndFrame(const gl::Context *context)
|
||||||
{
|
{
|
||||||
|
// On Android, we can trigger a capture during the run
|
||||||
|
checkForCaptureTrigger();
|
||||||
|
|
||||||
// Note that we currently capture before the start frame to collect shader and program sources.
|
// Note that we currently capture before the start frame to collect shader and program sources.
|
||||||
if (!mFrameCalls.empty() && mFrameIndex >= mFrameStart)
|
if (!mFrameCalls.empty() && mFrameIndex >= mFrameStart)
|
||||||
{
|
{
|
||||||
|
|
|
@ -302,6 +302,7 @@ class FrameCapture final : angle::NonCopyable
|
||||||
~FrameCapture();
|
~FrameCapture();
|
||||||
|
|
||||||
void captureCall(const gl::Context *context, CallCapture &&call);
|
void captureCall(const gl::Context *context, CallCapture &&call);
|
||||||
|
void checkForCaptureTrigger();
|
||||||
void onEndFrame(const gl::Context *context);
|
void onEndFrame(const gl::Context *context);
|
||||||
void onDestroyContext(const gl::Context *context);
|
void onDestroyContext(const gl::Context *context);
|
||||||
void onMakeCurrent(const egl::Surface *drawSurface);
|
void onMakeCurrent(const egl::Surface *drawSurface);
|
||||||
|
@ -368,6 +369,11 @@ class FrameCapture final : angle::NonCopyable
|
||||||
// Cache a shadow copy of texture level data
|
// Cache a shadow copy of texture level data
|
||||||
TextureLevels mCachedTextureLevels;
|
TextureLevels mCachedTextureLevels;
|
||||||
TextureLevelDataMap mCachedTextureLevelData;
|
TextureLevelDataMap mCachedTextureLevelData;
|
||||||
|
|
||||||
|
// If you don't know which frame you want to start capturing at, use the capture trigger.
|
||||||
|
// Initialize it to the number of frames you want to capture, and then clear the value to 0 when
|
||||||
|
// you reach the content you want to capture. Currently only available on Android.
|
||||||
|
uint32_t mCaptureTrigger;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CaptureFuncT, typename... ArgsT>
|
template <typename CaptureFuncT, typename... ArgsT>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче