Ryan GattisGraphics & Systems Engineer
← Projects

Vulkan Fragment Renderer

Real-time GLSL shader viewer with hot reload, stereo XR rendering, and depth-buffer compositing.

  • C++23
  • Vulkan
  • OpenXR
  • GLSL
  • shaderc
  • VMA
  • Dear ImGui

Implementation AI-generated. I designed the architecture, chose the approach, and directed the engineering decisions; the code itself was generated rather than hand-written. Noted here so the nature of the work is clear up front.

Mandelbox fractal detail rendered in the Vulkan fragment shader viewer
Mandelbox fractal detail rendered in the Vulkan fragment shader viewer
Shader reload
Runtime, no restart
XR
Per-eye frustums

A Vulkan port of shader-viewer-4, replacing OpenGL and adding HMD support and a descriptor set architecture built for extension.

The original is the useful comparison: I wrote that one myself, in OpenGL, by hand. This port covers the same ground in Vulkan with the implementation AI-generated, which means the decisions below — the descriptor set split, submitting depth to the XR runtime, the two-phase initialization — are the part that carried over.

Rendering

VMA handles memory, the swapchain is sRGB, and synchronization uses per-swapchain-image semaphores with deferred destruction of GPU resources still in flight.

Fragment shaders write gl_FragDepth through the projection matrix, which means shader output composites correctly against rasterized geometry. In XR mode that depth is submitted to the runtime so reprojection — ASW/SpaceWarp — has something to work with, rather than warping a flat image.

XR

Stereo rendering with per-eye asymmetric frustums and 6DoF head tracking, plus a desktop mirror. Initialization runs in two phases so that Vulkan can satisfy the instance and device extensions OpenXR requires, and the whole path falls back cleanly to desktop-only when no headset is present.

Interaction

Runtime GLSL compilation through shaderc with hot reload — edit a shader, press R, see it. The camera is quaternion-based to avoid gimbal lock, with velocity physics, friction, and movement scaled by pivot distance so navigation stays usable at every zoom level.

Descriptor set 0 carries view, projection, resolution, and time for every shader; set 1 carries precomputed inverse matrices for ray marching. Push constants are reserved for per-object model matrices.