Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Clone this wiki locally
Before doing anything make sure you have a few things installed:
sudo apt-get install libturbojpeg:i386 libturbojpeg libtinyxml-dev:i386 libtinyxml-dev
Then make sure you have the right build of vogl. If your app is 32-bit, you need to build the 32-bit version of vogl, etc. You won't get a good error if you mess this up, so use something like objdump, nm, etc. if you're not sure. See README.md for build instructions.
- Tracing using vogl_trace.sh
vogl/bin/vogl_trace.sh vogl/vogl_build/bin/glxspheres32 vogl/bin/vogl_trace.sh vogl/vogl_build/bin/glxspheres64
You should now have something like the following in your temp directory:
This method will be familiar to you if you've used apitrace's tracer (glxtrace.so) before. The major difference is libvogltrace.so doesn't default to automatically writing a trace file. In order to get a full-stream trace you must specify the "--vogl_tracefile X.bin" option in the
VOGL_CMD_LINE environment variable. Alternately, the tracer will try to read its command line options from the
vogl_cmd_line.txt file in the current directory. (Unlike apitrace, our tracer can write single/multi-frame snapshots too, which is why it doesn't default to writing a full-stream trace. See "Single/multi frame capturing mode during tracing", below.)
Here's a example bash script that'll create a full-stream trace of the executable specified on the command line:
# trace.sh #!/bin/bash export VOGL_CMD_LINE="--vogl_debug --vogl_tracefile trace.bin --vogl_pause" export LD_PRELOAD=/home/richg/dev/vogl_build/bin/libvogltrace32.so $*
If this works libvogltrace will wait for a keypress very early during initialization and then start full-stream tracing to "trace.bin". While the tracer is waiting you can attach gdb to the process if you want to debug the traced app or the tracer. If you fail to get a "waiting for keypress" message then something went wrong. The
LD_DEBUG environment variable can be useful when debugging LD_PRELOAD problems.
If for some reason LD_PRELOAD isn't your thing then go ahead and manually load libvogltrace32/64.so into your app and use dlsym() on the
gliGetProcAddressRAD exported function. (Or you can just call
glXGetProcAddress(), but I don't think that will work on Optimus. BTW, we don't officially support Optimus.)
If tracing causes your game to hitch, try writing the trace file to a SSD. You may also want to investigate tweaking your disk caching settings.
- Basic replay of a trace:
~/dev/vogl_build/bin/voglreplay32 replay trace
You basically just trace apitrace's glretrace app in --benchmark mode (so apitrace doesn't do tons of glGetErrors):
trace.sh glretrace blah.trace --benchmark
libvogltrace32/64.so will sit in between glretrace and the driver and capture all its calls to a vogl .bin trace file. We test apitrace capturing in our regression suite so we make sure it's very reliable. Note apitrace can't currently trace some more obscure things that we do, like the glXUseXFont() call that is used by glxspheres.
You can do single/multi-frame snapshots of glretrace's output too -- it's just another GL/GLX app to us. Note we don't support trace compression right now, so our traces are going to be larger vs. apitrace's. Storage and bandwidth is super cheap these days so it hasn't been a priority.
- To play back a trace with verbose debug output:
voglreplay32 replay --debug --verbose trace
- Force debug contexts during replaying:
voglreplay32 replay --force_debug_context trace
- Highest performance playback speed (no glGetErrors(), no divergence checks):
voglreplay32 replay --benchmark trace
- To losslessly dump the trace to JSON and directly play it back:
mkdir dump voglreplay32 replay --dump dump/jdump trace voglreplay32 dump/jdump
- Read a JSON trace and compile it back to a single file binary trace file:
voglreplay32 parse dump/jdump newtrace.bin
- To trim any type of trace (full-stream or a already trimmed trace) to a new trace file:
voglreplay32 replay newtrace.bin --trim_file trimmed.bin --trim_len 2 --trim_frame 10
- To play back a trace endlessly (useful for very short trimmed traces):
voglreplay32 replay trimmed.bin --endless
Feel free to edit JSON traces (and the loose files they refer to) as they are played back endlessly and see the results in semi-real time. Right now, if you introduce an error (like a compile or program link failure) the replayer will stop (we would like to flesh this feature out eventually).
- To play back a trace in basic "interactive" mode:
voglreplay32 trace -interactive
There will be no keyframes so seeking will be slow. (We'll add a wiki on this soon.)
Hit space to pause, s for slow mode, left/right arrows while paused to seek (ctrl, shift, alt + left/right seek further) - see the voglreplay help text for more keys. The J and T keys will trim at the current trace position.
Note: The replay will flicker while paused on a single frame at the moment because we now restore the frontbuffer's contents during a snapshot restore. After the snapshot restore we play the frame back, then swap (which changes the frontbuffer again) and rewind. We'll be adding a low-level flag to disable restoring the front buffer very soon (because it's of questionable value).
- Single/multi frame capturing mode during tracing
# single_frame_tracing.sh #!/bin/bash export VOGL_CMD_LINE="--vogl_debug --vogl_tracepath ./ --vogl_pause" export LD_PRELOAD=/home/richg/dev/vogl_build/bin/libvogltrace32.so $*
Now launch your app using this script, which uses
"--vogl_tracepath X" vs.
"--vogl_tracefile X". The tracer will monitor the current and trace directories for a file named
"__trigger_capture__". Once it sees this file it'll capture the next frame to a trace file (i.e. immediately after the next glXSwapBuffers).
Optionally, the first line of this file can specify the # of frames to capture ("all" = all remaining frames, or until the file named
"__stop_capture__" is detected). The optional 2nd line can contain the base filename of the resulting trace file.
- To search a trace for all
voglreplay32 --find trace -find_func glXCreateContext
- To search a trace for all instances of GL_DIFFUSE in any parameter or parameter array:
voglreplay32 --find trace -find_param GL_DIFFUSE
- To search a trace for all uses of texture handle 42 in a parameter or parameter array:
voglreplay32 --find q3_trace.bin --find_param 42 --find_namespace GLtexture
- To find all calls to functions beginning with the prefix "glX" using POSIX regex:
voglreplay32 --find --find_func "glX.*" q3_trace.bin
- To limit the find to the specified frame interval:
voglreplay32 --find --find_func "glX.*" --find_frame_low 8 --find_frame_high 10 q3_trace.bin
- To limit the find to the specified call interval:
voglreplay32 --find --find_func "glX.*" --find_call_low 10000 --find_call_high 12000 q3_trace.bin
There are many more --find options, see the help text for info. You can also just dump to JSON and grep the results but that can be a huge pain (due to aliasing and lack of context).
- To dump trace statistics (GL func and extension histogram, etc.):
voglreplay32 info trace.bin
- To dump a PNG screenshot after every draw or blit:
mkdir dump voglreplay32 replay steam_trimmed2 -dump_framebuffer_on_draw -dump_framebuffer_on_draw_prefix dump/cap
You'll wind up with a potentially large number of PNG files beginning with the "cap" prefix in the "dump" directory, like this:
The following info is encoded in each filename:
- GLCTR: GL call counter
- FR: Frame #
- DCTR: Frame draw counter
- W, H: Width/height of FBO (or the default framebuffer)
- FBO: Framebuffer object handle #
- FBO attachment
- Texture's internal format
- Texture handle #
The replayer will dump all FBO color attachments to separate PNG files.
- How to detect if libvogltrace is tracing your app:
See if you can successfully dlsym()
Another, more sneaky way is to map a buffer for write-only access. Then call
GL_BUFFER_ACCESS and make sure the buffer was really mapped as writable only. If it was mapped as read/write then somebody is tracing your calls. (Behind the scenes, libvogltrace will always force your buffer maps to be readable so it's able to safely trace the actual contents of buffers right before they are unmapped. Of course, somebody could just spoof the return value of glGetBufferParameteriv but we don't do that.)