José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 1 | About **apitrace** |
| 2 | ================== |
| 3 | |
| 4 | **apitrace** consists of a set of tools to: |
| 5 | |
| 6 | * trace OpenGL, D3D9, D3D8, D3D7, and DDRAW APIs calls to a file; |
| 7 | |
| 8 | * retrace OpenGL calls from a file; |
| 9 | |
José Fonseca | 892cad6 | 2011-09-23 08:24:28 +0100 | [diff] [blame^] | 10 | * inspect OpenGL state at any call while retracing; |
| 11 | |
| 12 | * visualize and edit trace files. |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 13 | |
| 14 | |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 15 | Basic usage |
| 16 | =========== |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 17 | |
| 18 | |
| 19 | Linux |
| 20 | ----- |
| 21 | |
| 22 | Run the application you want to trace as |
| 23 | |
| 24 | LD_PRELOAD=/path/to/glxtrace.so /path/to/application |
| 25 | |
| 26 | and it will generate a trace named `application.trace` in the current |
| 27 | directory. You can specify the written trace filename by setting the |
| 28 | `TRACE_FILE` environment variable before running. |
| 29 | |
| 30 | View the trace with |
| 31 | |
| 32 | /path/to/tracedump application.trace | less -R |
| 33 | |
| 34 | Replay the trace with |
| 35 | |
| 36 | /path/to/glretrace application.trace |
| 37 | |
| 38 | Pass the `-sb` option to use a single buffered visual. Pass `--help` to |
| 39 | glretrace for more options. |
| 40 | |
| 41 | Start the GUI as |
| 42 | |
| 43 | /path/to/qapitrace application.trace |
| 44 | |
| 45 | |
| 46 | The `LD_PRELOAD` mechanism should work with most applications. There are some |
| 47 | applications, e.g., Unigine Heaven, which global function pointers with the |
| 48 | same name as GL entrypoints, living in a shared object that wasn't linked with |
| 49 | `-Bsymbolic` flag, so relocations to those globals function pointers get |
| 50 | overwritten with the address to our wrapper library, and the application will |
| 51 | segfault when trying to write to them. For these applications it is possible |
| 52 | to trace by using `glxtrace.so` as an ordinary `libGL.so` and injecting into |
| 53 | `LD_LIBRARY_PATH`: |
| 54 | |
| 55 | ln -s glxtrace.so libGL.so |
| 56 | ln -s glxtrace.so libGL.so.1 |
| 57 | ln -s glxtrace.so libGL.so.1.2 |
| 58 | export LD_LIBRARY_PATH=/path/to/directory/where/glxtrace/is:$LD_LIBRARY_PATH |
| 59 | export TRACE_LIBGL=/path/to/real/libGL.so.1 |
| 60 | /path/to/application |
| 61 | |
José Fonseca | ed348d5 | 2011-07-04 10:20:42 +0100 | [diff] [blame] | 62 | See the `ld.so` man page for more information about `LD_PRELOAD` and |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 63 | `LD_LIBRARY_PATH` environment flags. |
| 64 | |
José Fonseca | cf61ced | 2011-07-02 15:42:57 +0100 | [diff] [blame] | 65 | |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 66 | |
| 67 | Mac OS X |
| 68 | -------- |
| 69 | |
| 70 | Usage on Mac OS X is similar to Linux above, except for the tracing procedure, |
| 71 | which is instead: |
| 72 | |
| 73 | DYLD_LIBRARY_PATH=/path/to/apitrace/wrappers /path/to/application |
| 74 | |
| 75 | Note that although Mac OS X has an `LD_PRELOAD` equivalent, |
| 76 | `DYLD_INSERT_LIBRARIES`, it is mostly useless because it only works with |
| 77 | `DYLD_FORCE_FLAT_NAMESPACE=1` which breaks most applications. See the `dyld` man |
| 78 | page for more details about these environment flags. |
| 79 | |
| 80 | |
| 81 | Windows |
| 82 | ------- |
| 83 | |
| 84 | * Copy `opengl32.dll`, `d3d8.dll`, or `d3d9.dll` from build/wrappers directory |
| 85 | to the directory with the application you want to trace. |
| 86 | |
| 87 | * Run the application. |
| 88 | |
| 89 | * View the trace with |
| 90 | |
José Fonseca | ed348d5 | 2011-07-04 10:20:42 +0100 | [diff] [blame] | 91 | \path\to\tracedump application.trace |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 92 | |
| 93 | * Replay the trace with |
| 94 | |
José Fonseca | ed348d5 | 2011-07-04 10:20:42 +0100 | [diff] [blame] | 95 | \path\to\glretrace application.trace |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 96 | |
| 97 | |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 98 | Advanced command line usage |
| 99 | =========================== |
| 100 | |
| 101 | |
José Fonseca | e62cabc | 2011-09-18 10:31:04 +0100 | [diff] [blame] | 102 | Emitting annotations to the trace from GL applications |
| 103 | ------------------------------------------------------ |
| 104 | |
| 105 | You can emit string and frame annotations through the |
| 106 | [`GL_GREMEDY_string_marker`](http://www.opengl.org/registry/specs/GREMEDY/string_marker.txt) |
| 107 | and |
| 108 | [`GL_GREMEDY_frame_terminator`](http://www.opengl.org/registry/specs/GREMEDY/frame_terminator.txt) |
| 109 | GL extensions. |
| 110 | |
José Fonseca | 892cad6 | 2011-09-23 08:24:28 +0100 | [diff] [blame^] | 111 | **apitrace** will advertise and intercept these GL extensions independently of |
José Fonseca | e62cabc | 2011-09-18 10:31:04 +0100 | [diff] [blame] | 112 | the GL implementation. So all you have to do is to use these extensions when |
| 113 | available. |
| 114 | |
| 115 | For example, if you use [GLEW](http://glew.sourceforge.net/) to dynamically |
| 116 | detect and use GL extensions, you could easily accomplish this by doing: |
| 117 | |
| 118 | void foo() { |
| 119 | |
| 120 | if (GLEW_GREMEDY_string_marker) { |
| 121 | glStringMarkerGREMEDY(0, __FUNCTION__ ": enter"); |
| 122 | } |
| 123 | |
| 124 | ... |
| 125 | |
| 126 | if (GLEW_GREMEDY_string_marker) { |
| 127 | glStringMarkerGREMEDY(0, __FUNCTION__ ": leave"); |
| 128 | } |
| 129 | |
| 130 | } |
| 131 | |
| 132 | This has the added advantage of working equally well with gDEBugger. |
| 133 | |
| 134 | |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 135 | Dump GL state at a particular call |
| 136 | ---------------------------------- |
| 137 | |
| 138 | You can get a dump of the bound GL state at call 12345 by doing: |
| 139 | |
| 140 | /path/to/glretrace -D 12345 application.trace > 12345.json |
| 141 | |
| 142 | This is precisely the mechanism the GUI obtains its own state. |
| 143 | |
| 144 | You can compare two state dumps with the jsondiff.py script: |
| 145 | |
| 146 | ./scripts/jsondiff.py 12345.json 67890.json |
| 147 | |
| 148 | |
| 149 | Comparing two traces side by side |
| 150 | --------------------------------- |
| 151 | |
| 152 | ./scripts/tracediff.sh trace1.trace trace2.trace |
| 153 | |
| 154 | This works only on Unices, and it will truncate the traces due to performance |
| 155 | limitations. |
| 156 | |
| 157 | |
| 158 | Recording a video with FFmpeg |
| 159 | ----------------------------- |
| 160 | |
| 161 | You can make a video of the output by doing |
| 162 | |
| 163 | /path/to/glretrace -s - application.trace \ |
| 164 | | ffmpeg -r 30 -f image2pipe -vcodec ppm -i pipe: -vcodec mpeg4 -y output.mp4 |
| 165 | |
| 166 | |
| 167 | Advanced usage for OpenGL implementors |
| 168 | ====================================== |
| 169 | |
José Fonseca | ff42758 | 2011-09-18 10:49:13 +0100 | [diff] [blame] | 170 | There are several advanced usage examples meant for OpenGL implementors. |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 171 | |
| 172 | |
| 173 | Regression testing |
| 174 | ------------------ |
| 175 | |
José Fonseca | 892cad6 | 2011-09-23 08:24:28 +0100 | [diff] [blame^] | 176 | These are the steps to create a regression test-suite around **apitrace**: |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 177 | |
| 178 | * obtain a trace |
| 179 | |
| 180 | * obtain reference snapshots, by doing: |
| 181 | |
| 182 | mkdir /path/to/snapshots/ |
| 183 | /path/to/glretrace -s /path/to/reference/snapshots/ application.trace |
| 184 | |
| 185 | on reference system. |
| 186 | |
| 187 | * prune the snapshots which are not interesting |
| 188 | |
| 189 | * to do a regression test, do: |
| 190 | |
| 191 | /path/to/glretrace -c /path/to/reference/snapshots/ application.trace |
| 192 | |
| 193 | Alternatively, for a HTML summary, use the snapdiff script: |
| 194 | |
| 195 | /path/to/glretrace -s /path/to/current/snapshots/ application.trace |
| 196 | ./scripts/snapdiff.py --output summary.html /path/to/reference/snapshots/ /path/to/current/snapshots/ |
| 197 | |
| 198 | |
| 199 | Automated git-bisection |
| 200 | ----------------------- |
| 201 | |
| 202 | With tracecheck.py it is possible to automate git bisect and pinpoint the |
| 203 | commit responsible for a regression. |
| 204 | |
| 205 | Below is an example of using tracecheck.py to bisect a regression in the |
| 206 | Mesa-based Intel 965 driver. But the procedure could be applied to any GL |
| 207 | driver hosted on a git repository. |
| 208 | |
| 209 | First, create a build script, named build-script.sh, containing: |
| 210 | |
| 211 | #!/bin/sh |
| 212 | set -e |
| 213 | export PATH=/usr/lib/ccache:$PATH |
| 214 | export CFLAGS='-g' |
| 215 | export CXXFLAGS='-g' |
| 216 | ./autogen.sh --disable-egl --disable-gallium --disable-glut --disable-glu --disable-glw --with-dri-drivers=i965 |
| 217 | make clean |
| 218 | make "$@" |
| 219 | |
| 220 | It is important that builds are both robust, and efficient. Due to broken |
| 221 | dependency discovery in Mesa's makefile system, it was necessary invoke `make |
| 222 | clean` in every iteration step. `ccache` should be installed to avoid |
| 223 | recompiling unchanged source files. |
| 224 | |
| 225 | Then do: |
| 226 | |
| 227 | cd /path/to/mesa |
| 228 | export LIBGL_DEBUG=verbose |
| 229 | export LD_LIBRARY_PATH=$PWD/lib |
| 230 | export LIBGL_DRIVERS_DIR=$PWD/lib |
| 231 | git bisect start \ |
| 232 | 6491e9593d5cbc5644eb02593a2f562447efdcbb 71acbb54f49089b03d3498b6f88c1681d3f649ac \ |
| 233 | -- src/mesa/drivers/dri/intel src/mesa/drivers/dri/i965/ |
| 234 | git bisect run /path/to/tracecheck.py \ |
| 235 | --precision-threshold 8.0 \ |
| 236 | --build /path/to/build-script.sh \ |
| 237 | --gl-renderer '.*Mesa.*Intel.*' \ |
| 238 | --retrace=/path/to/glretrace \ |
| 239 | -c /path/to/reference/snapshots/ \ |
| 240 | topogun-1.06-orc-84k.trace |
| 241 | |
| 242 | The trace-check.py script will skip automatically when there are build |
| 243 | failures. |
| 244 | |
| 245 | The `--gl-renderer` option will also cause a commit to be skipped if the |
| 246 | `GL_RENDERER` is unexpected (e.g., when a software renderer or another GL |
José Fonseca | ff42758 | 2011-09-18 10:49:13 +0100 | [diff] [blame] | 247 | driver is unintentionally loaded due to missing symbol in the DRI driver, or |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 248 | another runtime fault). |
| 249 | |
| 250 | |
| 251 | Side by side retracing |
| 252 | ---------------------- |
| 253 | |
| 254 | In order to determine which draw call a regression first manifests one could |
José Fonseca | 05ba419 | 2011-09-17 21:18:57 +0100 | [diff] [blame] | 255 | generate snapshots for every draw call, using the `-S` option. That is, however, |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 256 | very inefficient for big traces with many draw calls. |
| 257 | |
| 258 | A faster approach is to run both the bad and a good GL driver side-by-side. |
José Fonseca | ff42758 | 2011-09-18 10:49:13 +0100 | [diff] [blame] | 259 | The latter can be either a previously known good build of the GL driver, or a |
José Fonseca | 6d61700 | 2011-09-06 01:17:48 +0100 | [diff] [blame] | 260 | reference software renderer. |
| 261 | |
| 262 | This can be achieved with retracediff.py script, which invokes glretrace with |
| 263 | different environments, allowing to choose the desired GL driver by |
| 264 | manipulating variables such as `LD_LIBRARY_PATH` or `LIBGL_DRIVERS_DIR`. |
| 265 | |
| 266 | For example: |
| 267 | |
| 268 | ./scripts/retracediff.py \ |
| 269 | --ref-env LD_LIBRARY_PATH=/path/to/reference/GL/implementation \ |
| 270 | -r ./glretrace \ |
| 271 | --diff-prefix=/path/to/output/diffs \ |
| 272 | application.trace |
| 273 | |
| 274 | |
| 275 | |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 276 | Links |
| 277 | ===== |
| 278 | |
| 279 | About **apitrace**: |
| 280 | |
Zack Rusin | d029d5f | 2011-08-22 21:50:08 -0400 | [diff] [blame] | 281 | * [Official mailing list](http://lists.freedesktop.org/mailman/listinfo/apitrace) |
| 282 | |
José Fonseca | 0b21731 | 2011-06-30 14:32:57 +0100 | [diff] [blame] | 283 | * [Zack Rusin's blog introducing the GUI](http://zrusin.blogspot.com/2011/04/apitrace.html) |
| 284 | |
| 285 | * [Jose's Fonseca blog introducing the tool](http://jrfonseca.blogspot.com/2008/07/tracing-d3d-applications.html) |
| 286 | |
| 287 | |
| 288 | Direct3D |
| 289 | -------- |
| 290 | |
| 291 | Open-source: |
| 292 | |
| 293 | * [Proxy DLL](http://www.mikoweb.eu/index.php?node=21) |
| 294 | |
| 295 | * [Intercept Calls to DirectX with a Proxy DLL](http://www.codeguru.com/cpp/g-m/directx/directx8/article.php/c11453/) |
| 296 | |
| 297 | * [Direct3D 9 API Interceptor](http://graphics.stanford.edu/~mdfisher/D3D9Interceptor.html) |
| 298 | |
| 299 | Closed-source: |
| 300 | |
| 301 | * [Microsoft PIX](http://msdn.microsoft.com/en-us/library/ee417062.aspx) |
| 302 | |
| 303 | * [D3DSpy](http://doc.51windows.net/Directx9_SDK/?url=/directx9_sdk/graphics/programmingguide/TutorialsAndSamplesAndToolsAndTips/Tools/D3DSpy.htm): the predecessor of PIX |
| 304 | |
| 305 | * [AMD GPU PerfStudio](http://developer.amd.com/gpu/PerfStudio/pages/APITraceWindow.aspx) |
| 306 | |
| 307 | |
| 308 | OpenGL |
| 309 | ------ |
| 310 | |
| 311 | Open-source: |
| 312 | |
| 313 | * [BuGLe](http://www.opengl.org/sdk/tools/BuGLe/) |
| 314 | |
| 315 | * [GLIntercept](http://code.google.com/p/glintercept/) |
| 316 | |
| 317 | * [tracy](https://gitorious.org/tracy): OpenGL ES and OpenVG trace, retrace, and state inspection |
| 318 | |
| 319 | Closed-source: |
| 320 | |
| 321 | * [gDEBugger](http://www.gremedy.com/products.php) |
| 322 | |
| 323 | * [glslDevil](http://cumbia.informatik.uni-stuttgart.de/glsldevil/index.html) |
| 324 | |
| 325 | * [AMD GPU PerfStudio](http://developer.amd.com/gpu/PerfStudio/pages/APITraceWindow.aspx) |
| 326 | |