
I wrote a vulkan visualizer for my crate I probably shouldn't release
So, three months ago I started writing a Vulkan wrapper alongside my Super Hexagon clone because every existing one made me angry for different reasons. ash is too low level (although i love it), vulkano makes choices for you, wgpu is a different abstraction entirely. Fine, i'll do it myself, how hard can it be?
Turns out hard. But that's not the point... and I made it zero-dependency. It relies on ash only. Without egui, winit or etc. Pure FFI, pure ash.
The point is two weeks ago I was debugging a missing barrier between a compute write and a fragment read, and I sat in renderdoc for forty minutes scrolling through a frame capture trying to figure out which of my 60 dispatches was the one. and I thought, you know what, I have all this state in my own library already, I just need to render it somewhere.
So now I have an ipc (im tired pressing shift sorry) ring buffer between my lib and a separate viewer process, and the viewer draws:
- A frame graph that updates live. Sugiyama layout because i tried force-directed first and it looked like spaghetti. Nodes for passes and resources, edges for dependencies, it animates when things change so you can see what got added.
- A sync dag with queue lanes and submission bars. Detects deadlock cycles between queues. tints lanes red when it finds one. Found three real bugs in my own code with this, which is either good (it works) or bad (i had three deadlock bugs).
- Memory layout. Horizontal strips per VkDeviceMemory with colored rectangles for allocations. Hover for call site and age. Heap budget bars on top. Nothing groundbreaking, but it's right there in the same window as everything else.
- A pass profiler and a separate gpu timeline. CPU side shows how long recording took, gpu side shows actual gpu timestamps split by stage. They don't align in time because the clocks aren't correlated without vkGetCalibratedTimestamps which i didn't bother wiring up.
- Validation log with filtering, search, click-to-pin. When a vl warning mentions an image, the node for that image gets a little red exclamation badge.
- Canary monitor for buffer overflows when using my hardened allocator. shows hex diff of expected vs actual guard bytes with carets under the ones that differ. You can tell from the pattern what wrote there: 0xCD means uninit, 0xDD means freed memory, ASCII means a string ended up in your vertex buffer somehow.
- Determinism checker. Runs the same workload N times, hashes outputs, table goes red if hashes diverge. opens a bmp showing diff pixels. caught one (1) actual atomic race in my code so i guess it works.
- Tabs at the top, draggable, pinnable, persisted across runs. a scrubber for rewinding the last 16k events. ctrl+p freezes the stream so you can stare at a frame.
- The renderer is a cpu rasterizer that copies into a swapchain image. no pipelines, no shaders. I did this partly because i didn't want to write shaders for my debug tool and partly because if my main vulkan code is broken i still want the debug tool to render.
here's the thing though!
It's coupled to my own vulkan wrapper. The ipc protocol is mine, the event kinds are mine. someone on vulkano (why tho lmao) would need to write a bridge, someone on wgpu wouldn't benefit because wgpu hides most of what this shows. It's also windows only - rendering is portable but the window code is win32. and the viewer is one binary where every view shares an Rc<RefCell<World>>, which works fine but probably wouldn't survive a code review.
if you've shipped a niche tool like this, was the maintenance worth it?
btw yes i know about gpuopen rdna profiler. yes i tried it. yes it's better at what it does. mine does different things.