src/: core tracer, replay, Vulkan layer code; headers live alongside implementations.tests/: C++ regression and performance tests plus small generators (gen_*). Extend here when adding features.cmake/: toolchain presets for platform cross-compilationscripts/: Python code generators (e.g.,lava.pygeneration).doc/holds design notesexternal/tracks vendored depstraces/can store sample trace filesgenerated/holds generated c++ files created by the python scripts- The loader manifest is
VkLayer_lavatube.json. - Use separate build directories (e.g.
build/) to keep the tree clean. - Files and classes with
writein the name are related to trace capture, whilereadis related to trace replay. - Vulkan headers:
external/tracetooltests/external/Vulkan-Headers/include/vulkan/(do not use the system headers)
- Bootstrap deps:
git submodule update --init --recursive. - Configure:
mkdir -p build && cd build && cmake ..(add-DCMAKE_BUILD_TYPE=Debugwhile iterating). - Build:
make -C build -j$(nproc). - Tests:
cd build && make testorctest -Vfor verbose runs.
- C++ with tab indentation and Allman braces (opening brace on a new line). Mirror existing spacing and logging patterns.
- Names are generally lower_snake_case for functions/files; macros and constants stay uppercase.
- Keep headers and implementations paired in
src/; avoid introducing extra dependencies without CMake updates. - Do not modify generated files in
generated/directly. First line in a generated file says which script generated it. - If there is an error in the app that we capture, we should be resistant to this and keep running if possible; but if there are problems caused by our capturing code, we should fail as early as possible with a clear error message so we can fix them, not try to work around them with defensive code.
- Do not create new globals. If we need to track data betweeen commands, either use one of the tracked meta objects defined
in
src/lavatube.hor create a new one. Each Vulkan object has a tracked meta-object that can be used to store data. If there is no specialized trackable, then create a new one that inherits fromtrackableand then add it intrackable_type_map_generalinscripts/vkconfig.pyfor autogeneration.
- Add new tests under
tests/(seecontainer_test.cpp,tracing*.cppfor patterns) and reuse helpers intests/common.*. - Favor GPU-independent checks; prefer noscreen/blackhole modes when possible to keep runs fast and deterministic.
- Run
ctest(ormake test) before submitting; include any trace assets needed for reproducing issues but avoid committing large binaries.
- Keep in mind that lavatube is multi-threaded. For more information on the multi-threaded design, see Multithreading.md.
- For investigations into memory management, read MemoryManagement.md.
- At the lowest level of file processing we handle chunks, at the higher level we process packets. One chunk may contain many packets.
- We try to avoid using mutexes. Avoid modifying another thread's state directly, instead leave information for it be pick up and let it modify itself before processing its next packet. This way we keep thread state consistent while processing a packet.
- Each trace file contains a command dictionary that we remap on replay, so we do not need to worry about changing command ID numbers.
- Do not run compilation or tests as part of code reviews.
- For troubleshooting, set
LAVATUBE_DEBUGenvironment variable, value from 1 (some extra logging) to 3 (the most verbose). - Trace files are actually containers that contain other files. Some of these may contain useful information for debugging, and these
may be inspected with the
packtoolutility. If they are JSON format, they can be printed withpacktool print. Example usage:build/packtool print limits.json build/vulkan_general.vk - The contained file
limits.jsoncounts how many of each Vulkan object were created during the capture. - The contained file
tracking.jsoncontains immutable or accumulated meta-information for each Vulkan object. - The contained file
metadata.jsoncontains information on presented device capabilities (given by capture device) and requested capabilities (as requested by the captured application or by our capture layer).
- Capture is often also called
writeortracein the code. - Capture file IO code is in
src/filewriter.cppand higher-level code insrc/write.cpp. - Manually implemented functions are found in
src/hardcode_write.cpp - Capture is often initiated from the script
scripts/lava-capture.py - Fetch metadata tracking objects with
writer.parent->records.<type>_index.at(<native handle>)
- Replay is often also called
readorretracein the code. - Replay file IO code is in
src/filereader.cppand higher-level code insrc/read.cpp. - Manually implemented functions are found in
src/hardcode_read.cpp. Replacement functions are calledretrace_<name>. - Callbacks called before the function are called
replay_pre_<name>and callbacks called after are calledreplay_post_<name>. - The memory suballocator is in
src/suballocator.cpp - General window management (WSI) code is in
src/window.cpp - The replay binary is built from
src/replay.cpp - Fetch metadata tracking objects with
<type>_index.at(<index>)
- The post-processing tool uses both capture and replay functionality (as described above).
- The post-process binary is built from
src/tool.cppand most of its code is in callbacks calledpostprocess_<name>. TheCALLBACKmacro is used to register callbacks. - Most post-process callback functions are in
src/postprocess.cpp, but if they require tool context, they are insrc/tool. Some special callbacks eg for draw calls have hardcoded calls created inscripts/util.py. - SPIRV simulation is handled in
src/execute_commands.cpp - Fetch metadata tracking objects with
<type>_index.at(<index>)