1*8975f5c5SAndroid Build Coastguard Worker# ANGLE OpenGL Frame Capture and Replay 2*8975f5c5SAndroid Build Coastguard Worker 3*8975f5c5SAndroid Build Coastguard WorkerANGLE currently supports a limited OpenGL capture and replay framework. 4*8975f5c5SAndroid Build Coastguard Worker 5*8975f5c5SAndroid Build Coastguard WorkerLimitations: 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Worker * GLES capture has many unimplemented functions. 8*8975f5c5SAndroid Build Coastguard Worker * EGL capture and replay is not yet supported. 9*8975f5c5SAndroid Build Coastguard Worker * Mid-execution capture is supported with the Vulkan back-end. 10*8975f5c5SAndroid Build Coastguard Worker * Mid-execution capture has many unimplemented features. 11*8975f5c5SAndroid Build Coastguard Worker * Capture and replay is currently only tested on desktop platforms. 12*8975f5c5SAndroid Build Coastguard Worker * Binary replay is unimplemented. CPP replay is supported. 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Worker## Capturing and replaying an application 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard WorkerTo build ANGLE with capture and replay enabled update your GN args: 17*8975f5c5SAndroid Build Coastguard Worker 18*8975f5c5SAndroid Build Coastguard Worker``` 19*8975f5c5SAndroid Build Coastguard Workerangle_with_capture_by_default = true 20*8975f5c5SAndroid Build Coastguard Worker``` 21*8975f5c5SAndroid Build Coastguard Worker 22*8975f5c5SAndroid Build Coastguard WorkerOnce built with capture enabled by default, ANGLE supports capturing OpenGL ES calls to CPP replay 23*8975f5c5SAndroid Build Coastguard Workerfiles. To enable capture, set the `ANGLE_CAPTURE_FRAME_START` and `ANGLE_CAPTURE_FRAME_END` 24*8975f5c5SAndroid Build Coastguard Workerenvironment variables to define a capture frame range, or use the [capture trigger 25*8975f5c5SAndroid Build Coastguard Workerproperty][CaptureTrigger] on Android. By default the replay will be stored in the current working 26*8975f5c5SAndroid Build Coastguard Workerdirectory. The capture files will be named according to the pattern 27*8975f5c5SAndroid Build Coastguard Worker`angle_capture_context{id}_frame{n}.cpp`. Each GL Context currently has its own replay sources. 28*8975f5c5SAndroid Build Coastguard WorkerANGLE will write out data binary blobs for large Texture or Buffer contents to 29*8975f5c5SAndroid Build Coastguard Worker`angle_capture_context{id}_frame{n}.angledata`. Replay programs must be able to load data from the 30*8975f5c5SAndroid Build Coastguard Workercorresponding `angledata` files. 31*8975f5c5SAndroid Build Coastguard Worker 32*8975f5c5SAndroid Build Coastguard Worker## Controlling Frame Capture 33*8975f5c5SAndroid Build Coastguard Worker 34*8975f5c5SAndroid Build Coastguard WorkerSome simple environment variables control frame capture: 35*8975f5c5SAndroid Build Coastguard Worker 36*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_ENABLED`: 37*8975f5c5SAndroid Build Coastguard Worker * Set to `0` to disable capture entirely. Default is `1`. 38*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_COMPRESSION`: 39*8975f5c5SAndroid Build Coastguard Worker * Set to `0` to disable capture compression. Default is `1`. 40*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_OUT_DIR=<path>`: 41*8975f5c5SAndroid Build Coastguard Worker * Can specify an alternate replay output directory. This can either be an 42*8975f5c5SAndroid Build Coastguard Worker absolute path, or relative to CWD. 43*8975f5c5SAndroid Build Coastguard Worker * Example: `ANGLE_CAPTURE_OUT_DIR=samples/capture_replay`. Default is the CWD. 44*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_FRAME_START=<n>`: 45*8975f5c5SAndroid Build Coastguard Worker * Uses mid-execution capture to write "Setup" functions that starts a Context at frame `n`. 46*8975f5c5SAndroid Build Coastguard Worker * Example: `ANGLE_CAPTURE_FRAME_START=2`. Default is `0`. 47*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_FRAME_END=<n>`: 48*8975f5c5SAndroid Build Coastguard Worker * Example: `ANGLE_CAPTURE_FRAME_END=4`. Default is `0` which disables capture. 49*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_LABEL=<label>`: 50*8975f5c5SAndroid Build Coastguard Worker * When specified, files and functions will be labeled uniquely. 51*8975f5c5SAndroid Build Coastguard Worker * Example: `ANGLE_CAPTURE_LABEL=foo` 52*8975f5c5SAndroid Build Coastguard Worker * Results in filenames like this: 53*8975f5c5SAndroid Build Coastguard Worker ``` 54*8975f5c5SAndroid Build Coastguard Worker foo.angledata.gz 55*8975f5c5SAndroid Build Coastguard Worker foo_context1_001.cpp 56*8975f5c5SAndroid Build Coastguard Worker foo_context1_002.cpp 57*8975f5c5SAndroid Build Coastguard Worker foo_context1_003.cpp 58*8975f5c5SAndroid Build Coastguard Worker foo_context1.cpp 59*8975f5c5SAndroid Build Coastguard Worker foo_context1.h 60*8975f5c5SAndroid Build Coastguard Worker foo.json 61*8975f5c5SAndroid Build Coastguard Worker foo_shared.cpp 62*8975f5c5SAndroid Build Coastguard Worker ... 63*8975f5c5SAndroid Build Coastguard Worker ``` 64*8975f5c5SAndroid Build Coastguard Worker * `ANGLE_CAPTURE_SERIALIZE_STATE`: 65*8975f5c5SAndroid Build Coastguard Worker * Set to `1` to enable GL state serialization. Default is `0`. 66*8975f5c5SAndroid Build Coastguard Worker 67*8975f5c5SAndroid Build Coastguard WorkerA good way to test out the capture is to use environment variables in conjunction with the sample 68*8975f5c5SAndroid Build Coastguard Workertemplate. For example: 69*8975f5c5SAndroid Build Coastguard Worker 70*8975f5c5SAndroid Build Coastguard Worker``` 71*8975f5c5SAndroid Build Coastguard Worker$ ANGLE_CAPTURE_FRAME_END=4 ANGLE_CAPTURE_OUT_DIR=samples/capture_replay out/Debug/simple_texture_2d --use-angle=vulkan 72*8975f5c5SAndroid Build Coastguard Worker``` 73*8975f5c5SAndroid Build Coastguard Worker 74*8975f5c5SAndroid Build Coastguard Worker## Running the capture_replay sample (desktop only) 75*8975f5c5SAndroid Build Coastguard Worker 76*8975f5c5SAndroid Build Coastguard WorkerTo run a sample replay you can use a template located in 77*8975f5c5SAndroid Build Coastguard Worker[samples/capture_replay](../samples/capture_replay). First run your sample and ensure all capture 78*8975f5c5SAndroid Build Coastguard Workerfiles are written to `samples/capture_replay`. You can conveniently use `ANGLE_CAPTURE_OUT_DIR`. 79*8975f5c5SAndroid Build Coastguard WorkerMake sure `ANGLE_CAPTURE_LABEL` is left unset during capture to use the default file names. 80*8975f5c5SAndroid Build Coastguard WorkerThen enable the `capture_replay_sample` via `gn args`: 81*8975f5c5SAndroid Build Coastguard Worker 82*8975f5c5SAndroid Build Coastguard Worker``` 83*8975f5c5SAndroid Build Coastguard Workerangle_build_capture_replay_sample = true 84*8975f5c5SAndroid Build Coastguard Worker``` 85*8975f5c5SAndroid Build Coastguard Worker 86*8975f5c5SAndroid Build Coastguard WorkerSee [samples/BUILD.gn](../samples/BUILD.gn) for details. Then build and run your replay sample: 87*8975f5c5SAndroid Build Coastguard Worker 88*8975f5c5SAndroid Build Coastguard Worker``` 89*8975f5c5SAndroid Build Coastguard Worker$ autoninja -C out/Debug capture_replay_sample 90*8975f5c5SAndroid Build Coastguard Worker$ out/Debug/capture_replay_sample 91*8975f5c5SAndroid Build Coastguard Worker``` 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Worker## Running a perf test replay (all platforms, including Android) 94*8975f5c5SAndroid Build Coastguard Worker 95*8975f5c5SAndroid Build Coastguard WorkerTo run your capture on any platform (Windows, Linux, Android, Mac (untested)), you'll need to 96*8975f5c5SAndroid Build Coastguard Workercompile it as part of ANGLE's Trace Replay harness, which is part of `angle_perftests`. 97*8975f5c5SAndroid Build Coastguard Worker 98*8975f5c5SAndroid Build Coastguard WorkerCreate a folder under `src/tests/restricted_traces` that matches the `ANGLE_CAPTURE_LABEL` you 99*8975f5c5SAndroid Build Coastguard Workerused above. 100*8975f5c5SAndroid Build Coastguard Worker 101*8975f5c5SAndroid Build Coastguard WorkerPlace all the trace output files into it. For example, if the label was `desktop_test`: 102*8975f5c5SAndroid Build Coastguard Worker``` 103*8975f5c5SAndroid Build Coastguard Workersrc/tests/restricted_traces$ ls -1 desktop_test/ 104*8975f5c5SAndroid Build Coastguard Workerdesktop_test.angledata.gz 105*8975f5c5SAndroid Build Coastguard Workerdesktop_test_context1_001.cpp 106*8975f5c5SAndroid Build Coastguard Workerdesktop_test_context1_002.cpp 107*8975f5c5SAndroid Build Coastguard Workerdesktop_test_context1_003.cpp 108*8975f5c5SAndroid Build Coastguard Workerdesktop_test_context1.cpp 109*8975f5c5SAndroid Build Coastguard Workerdesktop_test_context1.h 110*8975f5c5SAndroid Build Coastguard Workerdesktop_test.json 111*8975f5c5SAndroid Build Coastguard Workerdesktop_test_shared.cpp 112*8975f5c5SAndroid Build Coastguard Worker``` 113*8975f5c5SAndroid Build Coastguard WorkerThen add the label of your trace to 114*8975f5c5SAndroid Build Coastguard Worker[restricted_traces.json](../src/tests/restricted_traces/restricted_traces.json). 115*8975f5c5SAndroid Build Coastguard WorkerNote it includes a version with the string. Just use the number `1` for local changes. 116*8975f5c5SAndroid Build Coastguard Worker``` 117*8975f5c5SAndroid Build Coastguard Worker "dead_trigger_2 1", 118*8975f5c5SAndroid Build Coastguard Worker+ "desktop_test 1", 119*8975f5c5SAndroid Build Coastguard Worker "disney_tsum_tsum 5", 120*8975f5c5SAndroid Build Coastguard Worker``` 121*8975f5c5SAndroid Build Coastguard WorkerNow you should be able to compile and run the perf test including your trace: 122*8975f5c5SAndroid Build Coastguard Worker``` 123*8975f5c5SAndroid Build Coastguard Workerautoninja -C out/Debug angle_perftests 124*8975f5c5SAndroid Build Coastguard WorkerANGLE_CAPTURE_ENABLED=0 out/Debug/angle_perftests --gtest_filter="*desktop_test*" --verbose 125*8975f5c5SAndroid Build Coastguard Worker``` 126*8975f5c5SAndroid Build Coastguard Worker## Capturing an Android application 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard WorkerIn order to capture on Android, the following additional steps must be taken. These steps 129*8975f5c5SAndroid Build Coastguard Workerpresume you've built and installed the ANGLE APK with capture enabled, and selected ANGLE 130*8975f5c5SAndroid Build Coastguard Workeras the GLES driver for your application. 131*8975f5c5SAndroid Build Coastguard Worker 132*8975f5c5SAndroid Build Coastguard Worker1. Create the output directory 133*8975f5c5SAndroid Build Coastguard Worker 134*8975f5c5SAndroid Build Coastguard Worker Determine your package name: 135*8975f5c5SAndroid Build Coastguard Worker ``` 136*8975f5c5SAndroid Build Coastguard Worker export PACKAGE_NAME com.android.gl2jni 137*8975f5c5SAndroid Build Coastguard Worker ``` 138*8975f5c5SAndroid Build Coastguard Worker Then create an output directory that it can write to: 139*8975f5c5SAndroid Build Coastguard Worker ``` 140*8975f5c5SAndroid Build Coastguard Worker $ adb shell mkdir -p /sdcard/Android/data/$PACKAGE_NAME/angle_capture 141*8975f5c5SAndroid Build Coastguard Worker $ adb shell chmod 777 /sdcard/Android/data/$PACKAGE_NAME/angle_capture 142*8975f5c5SAndroid Build Coastguard Worker ``` 143*8975f5c5SAndroid Build Coastguard Worker 144*8975f5c5SAndroid Build Coastguard Worker2. Set properties to use for environment variable 145*8975f5c5SAndroid Build Coastguard Worker 146*8975f5c5SAndroid Build Coastguard Worker On Android, it is difficult to set an environment variable before starting native code. 147*8975f5c5SAndroid Build Coastguard Worker To work around this, ANGLE will read debug system properties before starting the capture 148*8975f5c5SAndroid Build Coastguard Worker and use them to prime environment variables used by the capture code. 149*8975f5c5SAndroid Build Coastguard Worker 150*8975f5c5SAndroid Build Coastguard Worker Note: Mid-execution capture doesn't work for Android just yet, so frame_start must be 151*8975f5c5SAndroid Build Coastguard Worker zero, which is the default. This it is sufficient to only set the end frame. 152*8975f5c5SAndroid Build Coastguard Worker ``` 153*8975f5c5SAndroid Build Coastguard Worker $ adb shell setprop debug.angle.capture.frame_end 200 154*8975f5c5SAndroid Build Coastguard Worker ``` 155*8975f5c5SAndroid Build Coastguard Worker 156*8975f5c5SAndroid Build Coastguard Worker There are other properties that can be set that match 1:1 with the env vars, but 157*8975f5c5SAndroid Build Coastguard Worker they are not required for capture: 158*8975f5c5SAndroid Build Coastguard Worker ``` 159*8975f5c5SAndroid Build Coastguard Worker # Optional 160*8975f5c5SAndroid Build Coastguard Worker $ adb shell setprop debug.angle.capture.enabled 0 161*8975f5c5SAndroid Build Coastguard Worker $ adb shell setprop debug.angle.capture.out_dir foo 162*8975f5c5SAndroid Build Coastguard Worker $ adb shell setprop debug.angle.capture.frame_start 0 163*8975f5c5SAndroid Build Coastguard Worker $ adb shell setprop debug.angle.capture.label bar 164*8975f5c5SAndroid Build Coastguard Worker ``` 165*8975f5c5SAndroid Build Coastguard Worker 166*8975f5c5SAndroid Build Coastguard Worker3. Run the application, then pull the files to the capture_replay directory 167*8975f5c5SAndroid Build Coastguard Worker ``` 168*8975f5c5SAndroid Build Coastguard Worker $ cd samples/capture_replay 169*8975f5c5SAndroid Build Coastguard Worker $ adb pull /sdcard/Android/data/$PACKAGE_NAME/angle_capture replay_files 170*8975f5c5SAndroid Build Coastguard Worker $ cp replay_files/* . 171*8975f5c5SAndroid Build Coastguard Worker ``` 172*8975f5c5SAndroid Build Coastguard Worker 173*8975f5c5SAndroid Build Coastguard Worker4. Update your GN args to specifiy which context will be replayed. 174*8975f5c5SAndroid Build Coastguard Worker 175*8975f5c5SAndroid Build Coastguard Worker By default Context ID 1 will be replayed. On Android, Context ID 2 is more typical, some apps 176*8975f5c5SAndroid Build Coastguard Worker we've run go as high as ID 6. 177*8975f5c5SAndroid Build Coastguard Worker Note: this solution is temporary until EGL capture is in place. 178*8975f5c5SAndroid Build Coastguard Worker ``` 179*8975f5c5SAndroid Build Coastguard Worker angle_capture_replay_sample_context_id = 2 180*8975f5c5SAndroid Build Coastguard Worker ``` 181*8975f5c5SAndroid Build Coastguard Worker 182*8975f5c5SAndroid Build Coastguard Worker5. Replay the capture on desktop 183*8975f5c5SAndroid Build Coastguard Worker 184*8975f5c5SAndroid Build Coastguard Worker Until we have samples building for Android, the replay sample must be run on desktop. 185*8975f5c5SAndroid Build Coastguard Worker We will also be plumbing replay files into perf and correctness tests which will run on Android. 186*8975f5c5SAndroid Build Coastguard Worker ``` 187*8975f5c5SAndroid Build Coastguard Worker $ autoninja -C out/Release capture_replay_sample 188*8975f5c5SAndroid Build Coastguard Worker $ out/Release/capture_replay_sample 189*8975f5c5SAndroid Build Coastguard Worker ``` 190*8975f5c5SAndroid Build Coastguard Worker 191*8975f5c5SAndroid Build Coastguard Worker### Starting capture at an arbitrary frame 192*8975f5c5SAndroid Build Coastguard WorkerIn some scenarios, you don't know which frame you want to start on. You'll only know when target 193*8975f5c5SAndroid Build Coastguard Workercontent is being rendered. For that we've added a trigger that can allow starting the capture at 194*8975f5c5SAndroid Build Coastguard Workerany time. 195*8975f5c5SAndroid Build Coastguard Worker 196*8975f5c5SAndroid Build Coastguard WorkerTo use it, set the following environment variable, in addition to all the setup steps above. Set 197*8975f5c5SAndroid Build Coastguard Workerthe trigger value equal to the number of frames you'd like to capture. 198*8975f5c5SAndroid Build Coastguard Worker``` 199*8975f5c5SAndroid Build Coastguard Workeradb shell setprop debug.angle.capture.trigger 20 200*8975f5c5SAndroid Build Coastguard Worker``` 201*8975f5c5SAndroid Build Coastguard WorkerWhen this value is set, `ANGLE_CAPTURE_FRAME_START` and `ANGLE_CAPTURE_FRAME_END` will be ignored. 202*8975f5c5SAndroid Build Coastguard Worker 203*8975f5c5SAndroid Build Coastguard WorkerWhile your content is rendering, wait until you arrive at the scene you'd like to capture. Then 204*8975f5c5SAndroid Build Coastguard Workerset the value back to zero: 205*8975f5c5SAndroid Build Coastguard Worker``` 206*8975f5c5SAndroid Build Coastguard Workeradb shell setprop debug.angle.capture.trigger 0 207*8975f5c5SAndroid Build Coastguard Worker``` 208*8975f5c5SAndroid Build Coastguard WorkerANGLE will detect this change and start recording the requested number of frames. 209*8975f5c5SAndroid Build Coastguard Worker 210*8975f5c5SAndroid Build Coastguard Worker## Testing 211*8975f5c5SAndroid Build Coastguard Worker 212*8975f5c5SAndroid Build Coastguard Worker### Regression Testing Architecture 213*8975f5c5SAndroid Build Coastguard WorkerThe [python script][link_to_python_script] uses the job queue pattern. We spawn n-1 independent 214*8975f5c5SAndroid Build Coastguard Workerworker processes, where n is the value returned by multiprocessing.cpu_count(). Whenever a worker 215*8975f5c5SAndroid Build Coastguard Workerprocess finishes a job and becomes available, it grabs the next job from a shared job queue and 216*8975f5c5SAndroid Build Coastguard Workerruns that job on its CPU core. When there are no more jobs in the queue, the worker processes 217*8975f5c5SAndroid Build Coastguard Workerterminate and the main process reports results. 218*8975f5c5SAndroid Build Coastguard Worker 219*8975f5c5SAndroid Build Coastguard Worker 220*8975f5c5SAndroid Build Coastguard Worker 221*8975f5c5SAndroid Build Coastguard Worker### Job unit 222*8975f5c5SAndroid Build Coastguard WorkerA job unit is a test batch. Each test has to go through 3 stages: capture run, replay build, and 223*8975f5c5SAndroid Build Coastguard Workerreplay run. The test batch batches the replay build stage of multiple tests together, and the 224*8975f5c5SAndroid Build Coastguard Workerreplay run stage of multiple tests together. 225*8975f5c5SAndroid Build Coastguard Worker 226*8975f5c5SAndroid Build Coastguard Worker 227*8975f5c5SAndroid Build Coastguard Worker 228*8975f5c5SAndroid Build Coastguard Worker### Running tests 229*8975f5c5SAndroid Build Coastguard WorkerFrom the command line, navigate to the ANGLE root folder [angle][angle_folder] then run the 230*8975f5c5SAndroid Build Coastguard Workercommand below: 231*8975f5c5SAndroid Build Coastguard Worker``` 232*8975f5c5SAndroid Build Coastguard Workerpython3 src/tests/capture_replay_tests.py --gtest_filter=*/ES2_Vulkan --keep-temp-files --batch-count=8 233*8975f5c5SAndroid Build Coastguard Worker``` 234*8975f5c5SAndroid Build Coastguard Worker 235*8975f5c5SAndroid Build Coastguard Worker* `--gtest_filter` to run only specific tests 236*8975f5c5SAndroid Build Coastguard Worker* `--keep-temp-files` to keep the trace files 237*8975f5c5SAndroid Build Coastguard Worker* `--batch-count` to set the number of tests in a (capture) batch. More tests in a batch means that 238*8975f5c5SAndroid Build Coastguard Workerthe tests will finish faster, but also means a lower level of granularity. 239*8975f5c5SAndroid Build Coastguard WorkerAll command line arguments can be found at the top of the [python script][link_to_python_script]. 240*8975f5c5SAndroid Build Coastguard Worker 241*8975f5c5SAndroid Build Coastguard Worker[angle_folder]: ../ 242*8975f5c5SAndroid Build Coastguard Worker[capture_replay_test_folder]: ../src/tests/capture_replay_tests/ 243*8975f5c5SAndroid Build Coastguard Worker[link_to_python_script]: ../src/tests/capture_replay_tests.py 244*8975f5c5SAndroid Build Coastguard Worker[CaptureTrigger]: ../src/tests/restricted_traces/README.md#trigger-the-capture 245