Skip to content

Commit

Permalink
Capture/Replay: Implement mid-execution replay.
Browse files Browse the repository at this point in the history
Mid-execution replay starts the replay from a specific start frame
instead of frame 0. Integration tests will then run between the start
and end frames. This lets us make much smaller reproduction cases from
large benchmarks or applications.

We implement mid-execution replay via a cpp "Setup" function. The
replay test will run the setup function before the starting frame. Test
execution proceeds normally after setup.

Currently we do not implement mid-execution capture. We run capture on
all frames. Including frames before the start frame. We do this to
intercept compiled shaders and programs for easier caching. This could
be changed in the future to also start capture mid-execution. Mid-
execution capture might require using ProgramBinary calls to capture
shader and program data.

Many captures are unimplemented. Several comments indicate missing
functionality. There's a lot we can add as we explore replaying more
complex applications and higher GL versions. We will also need some
kind of state reset functionality so we can run the replay in a loop.

Bug: angleproject:3611
Change-Id: I51841fc1a64e3622c34e49c85ed8919a9a7c0b20
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1689329
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Cody Northrop <cnorthrop@google.com>
  • Loading branch information
null77 authored and Commit Bot committed Nov 3, 2019
1 parent b68a279 commit 6c7208f
Show file tree
Hide file tree
Showing 9 changed files with 850 additions and 205 deletions.
41 changes: 25 additions & 16 deletions doc/CaptureAndReplay.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ ANGLE currently supports a limited OpenGL capture and replay framework.

Limitations:

* Many OpenGL ES functions are not yet implemented.
* GLES capture has many unimplemented functions.
* EGL capture and replay is not yet supported.
* Mid-execution is not yet implemented.
* Capture only tested on desktop platforms currently.
* Replays currently are implemented as CPP files.
* Mid-execution capture is supported with the Vulkan back-end.
* Mid-execution capture has many unimplemented features.
* Capture and replay is currently only tested on desktop platforms.
* Binary replay is unimplemented. CPP replay is supported.

## Capturing and replaying an application

Expand All @@ -18,23 +19,28 @@ To build ANGLE with capture and replay enabled update your GN args:
angle_with_capture_by_default = true
```

Once built ANGLE will capture the OpenGL ES calls to a CPP replay. By default the replay will be
Once built ANGLE will capture the OpenGL ES calls to CPP replay files. By default the replay will be
stored in the current working directory. The capture files will be named according to the pattern
`angle_capture_context{id}_frame{n}.cpp`. ANGLE will additionally write out data binary blobs for
Texture or Buffer contexts to `angle_capture_context{id}_frame{n}.angledata`.
`angle_capture_context{id}_frame{n}.cpp`. Each GL Context currently has its own replay sources.
ANGLE will write out data binary blobs for large Texture or Buffer contents to
`angle_capture_context{id}_frame{n}.angledata`. Replay programs must be able to load data from the
corresponding `angledata` files.

## Controlling Frame Capture

Some simple environment variables control frame capture:

* `ANGLE_CAPTURE_ENABLED`:
Can be set to "0" to disable capture entirely.
* Set to `0` to disable capture entirely. Default is `1`.
* `ANGLE_CAPTURE_OUT_DIR=<path>`:
Can specify an alternate replay output directory than the CWD.
Example: `ANGLE_CAPTURE_OUT_DIR=samples/capture_replay`
* Can specify an alternate replay output directory.
* Example: `ANGLE_CAPTURE_OUT_DIR=samples/capture_replay`. Default is the CWD.
* `ANGLE_CAPTURE_FRAME_START=<n>`:
* Uses mid-execution capture to write "Setup" functions that starts a Context at frame `n`.
* Example: `ANGLE_CAPTURE_FRAME_START=2`. Default is `0`.
* `ANGLE_CAPTURE_FRAME_END=<n>`:
By default ANGLE will capture the first ten frames. This variable can override the default.
Example: `ANGLE_CAPTURE_FRAME_END=4`
* By default ANGLE will capture the first ten frames. This variable can override the default.
* Example: `ANGLE_CAPTURE_FRAME_END=4`. Default is `10`.

A good way to test out the capture is to use environment variables in conjunction with the sample
template. For example:
Expand All @@ -47,10 +53,11 @@ $ ANGLE_CAPTURE_FRAME_END=4 ANGLE_CAPTURE_OUT_DIR=samples/capture_replay out/Deb

To run a CPP replay you can use a template located in
[samples/capture_replay](../samples/capture_replay). Update
[samples/BUILD.gn](../samples/BUILD.gn) to enable the `capture_replay` sample to include your replay:
[samples/BUILD.gn](../samples/BUILD.gn) to enable `capture_replay_sample`
sample to include your replay frames:

```
capture_replay("my_sample") {
angle_capture_replay_sample("capture_replay_sample") {
sources = [
"capture_replay/angle_capture_context1_frame000.cpp",
"capture_replay/angle_capture_context1_frame001.cpp",
Expand All @@ -64,6 +71,8 @@ capture_replay("my_sample") {
Then build and run your replay sample:

```
$ autoninja -C out/Debug my_sample
$ ANGLE_CAPTURE_ENABLED=0 out/Debug/my_sample
$ autoninja -C out/Debug capture_replay
$ ANGLE_CAPTURE_ENABLED=0 out/Debug/capture_replay
```

Note that we specify `ANGLE_CAPTURE_ENABLED=0` to prevent re-capturing your replay.
2 changes: 1 addition & 1 deletion samples/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ angle_sample("gles1_draw_texture") {
]
}

template("capture_replay") {
template("angle_capture_replay_sample") {
angle_sample(target_name) {
sources = invoker.sources + [
"capture_replay/CaptureReplay.cpp",
Expand Down
10 changes: 10 additions & 0 deletions src/common/PackedEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ class PackedEnumMap
T *data() noexcept { return mPrivateData.data(); }
const T *data() const noexcept { return mPrivateData.data(); }

bool operator==(const PackedEnumMap &rhs) const { return mPrivateData == rhs.mPrivateData; }
bool operator!=(const PackedEnumMap &rhs) const { return mPrivateData != rhs.mPrivateData; }

private:
Storage mPrivateData;
};
Expand Down Expand Up @@ -500,6 +503,13 @@ typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator!=(const
return lhs.value != rhs.value;
}

template <typename T>
typename std::enable_if<IsResourceIDType<T>::value, bool>::type operator<(const T &lhs,
const T &rhs)
{
return lhs.value < rhs.value;
}

// Used to unbox typed values.
template <typename ResourceIDType>
GLuint GetIDValue(ResourceIDType id);
Expand Down
Loading

0 comments on commit 6c7208f

Please sign in to comment.