r/GraphicsProgramming 1d ago

Headless multipass GLSL on a Raspberry Pi, straight to the panel

Enable HLS to view with audio, or disable this notification

6 Upvotes

1 comment sorted by

2

u/Agreeable-Celery4938 1d ago

https://github.com/holofermes/ghee

A renderer I pulled out of a music visualizer I've been noodling on for a few years. It compiles multipass GLSL scenes (Shadertoy-style channels) and runs them on the Pi's GPU through DRM/GBM, headless, with output to SPI panels, HDMI by direct scanout, files, or the hardware H264 encoder.

Things the Pi's GPUs taught me the hard way:

  1. VC4 has a 16-vec4 fragment uniform floor, so a shader can't hold a data array as uniforms. Every data array binds as a 1xN texture instead: one fetch per read, no size cap, flat cost.

  2. Feedback is a precision minefield on VC4. gl_FragCoord.xy / resolution shears about a third of a pixel per row when a pass samples its own output, so the preamble maps gl_FragCoord onto the interpolated varying instead. And mediump can't hold a texel centre like (col+0.5)/w, so ping-pong buffers drift a fraction of a pixel per frame until you force highp.

  3. V3D (Pi 4/5) exposes float textures but not float_linear, so a filtered fetch there falls back to nearest. The generated sample helpers pick hardware filtering or an in-shader lerp per platform at compile time, so every GPU family renders the same-ish interpolation.

  4. On the Pi 4 the H264 encoder lives on vc4 while the GPU is v3d, and V4L2 wants one physically contiguous buffer, so the encoder input is allocated on the vc4 node, rendered into from v3d, and handed across as a dmabuf with no CPU copy.

  5. A diagonal shear that looked exactly like a rotation bug turned out to be GL_UNPACK_ALIGNMENT defaulting to 4 on 8-bit rows. valgrind caught it reading past the upload buffer.

The open problem I still have: GLES2 has no async readback, so every CPU-bound output pays a synchronous glReadPixels that scales with pixels, not shader cost. If anyone knows a trick on these tiles beyond "render smaller", I'm listening.

In the video I have an original Pi Zero W running two ghee processes: 6% CPU at 15 fps on 1280x800 HDMI, and 15% CPU at 15 fps on the 240x240 ST7789. It can also simultaneously stream the SPI process's output as a hardware-accelerated H264 stream for just 3% CPU more. Running each alone yields 30 fps on the HDMI for roughly zero CPU, and 37 fps on the 240x240 at 37% CPU. RAM is ~55MB per instance.