Neo GPU is a 25KB NEON-optimized GPU inspired by Pico GPU, for the ARM Cortex-A72 (Pi4) processor family.
C
4
140 commits
updated Apr 2, 2026
Message-native runtime substrate for graphics, tooling, and experimental inference on ARM/NEON hardware.
NeoGPU is a message-native runtime substrate. Rendering is its clearest proof surface today. Tooling and IPC are operationally real peers in the same runtime. ML exists in the tree, but remains experimental until it reaches the same operational standard.
hs_audio.h)hs_storage.h)# Build all
make build
# Run demo
make run
make neogpu_pong
sudo ./neogpu_pong
# Controls: W/S or UP/DOWN arrows, Q to quit
make neogpu_pong_ai
sudo ./neogpu_pong_ai
make neogpu_pong_llm
sudo ./neogpu_pong_llm --model models/bitnet-2b4t-i2s.gguf --prompt "Hello"
This demonstrates:
make neogpu_capture_demo
sudo ./neogpu_capture_demo
# Output: /tmp/neogpu_capture.bin (HSCAP1 format)
# Already built: tools/neogpu_bitnet_chat
sudo ./tools/neogpu_bitnet_chat --model models/bitnet-2b4t-i2s.gguf --prompt "Hello"
neogpu_demo exposes in-process tooling via --tool:
./neogpu_demo --tool --query-stats --query-fabric
# Set record mask (example: record render+rt)
./neogpu_demo --tool --set-record-mask 0x00000006 --query-stats
# Set render budget and query
./neogpu_demo --tool --set-budget 2 8192 --query-stats
Start an IPC server to attach external tools:
# Unix socket (local)
./neogpu_demo --ipc-server /tmp/neogpu.sock --ipc-ms 5000
# TCP/IP (remote)
./neogpu_demo --ipc-tcp 8765 --ipc-ms 5000
Then use the standalone neogpu_tool client:
make tool
./neogpu_tool --sock /tmp/neogpu.sock query-stats
./neogpu_tool --sock /tmp/neogpu.sock query-fabric
./neogpu_tool --host localhost --port 8765 query-fabric # TCP/IP
Channel IDs: 1=RT, 2=RENDER, 3=TELEM
NeoGPU implements explicit RT/RENDER/TELEM channel semantics:
| Channel | QoS | Budget (msgs/tick) | Behavior |
|---|---|---|---|
| RT | Critical | 4096 | Strict priority, no drops |
| RENDER | Interactive | 16384 | Fair share, limited drops |
| TELEM | Background | 1024 | Best-effort, auto-drop |
Query fabric stats:
./neogpu_tool --sock /tmp/neogpu.sock query-fabric
# Output includes: spsc_ok, spsc_full, mpsc_ok, submit_full, submit_hw, telem_dropped
make build
make CC=aarch64-linux-gnu-gcc STRIP=aarch64-linux-gnu-strip build
The clearest proof that NeoGPU is real is visible hardware behavior plus runtime tooling:
tests/test_06_raycast.c - shader-driven sphere demo with live FPS HUDtests/test_07_message_triangle.c - message-driven render path demo./neogpu_demo --tool --query-stats --query-fabric - runtime fabric introspectionIf a change improves local code but weakens these proof surfaces, treat it as suspect until revalidated.
src/
hs_core.c - Message queue, OpCodes, system core
hs_nodes.c - Node message handlers (Shader, Buffer, Texture, Output, Sound)
hs_gpu.c - High-level GPU API
hs_ipc.c - IPC server (Unix domain + TCP/IP)
hs_ml_*.c - ML inference (BitNet 2B)
main.c - Demo/test suite
benchmark.c - Benchmarks
include/
hs_core.h - Core header (includes toolbus for IPC)
hs_ipc.h - IPC server interface
hs_nodes.h - Node headers
hs_gpu.h - GPU API header
hs_math_neon.h - NEON-optimized vec4/mat4 math
hs_buffer.h - Buffer/Texture data types
hs_input.h - Input/controls system
hs_audio.h - 4-channel audio system (48KHz)
hs_storage.h - Persistent storage (16 slots × 256B)
hs_graphics.h - GBM/EGL/GLES graphics backend
hs_ml_infer.h - ML inference API
tools/
neogpu_bitnet_chat.c - Standalone LLM chat
neogpu_pong.c - Simple Pong game
neogpu_pong_ai.c - Pong with AI commentary
neogpu_pong_llm.c - Pong + real BitNet inference
neogpu_capture_demo.c - Message capture demo
neogpu_viz.c - ML visualization
tests/
test_01_clear.c - Clear screen test
test_02_triangle.c - Single triangle
test_03_instancing.c - Hardware instancing
test_04_blending.c - Alpha blending
test_05_cube3d.c - 3D rotating cube
test_06_raycast.c - Ray casting spheres (270 FPS on Pi)
src/archive_ternary_kernels/
- Archived kernel variants (v2-v21)
HSGpu gpu;
hs_gpu_init(&gpu);
hs_gpu_clear(&gpu, v4_make(0, 0, 0, 1)); // Clear with color
hs_gpu_set_shader(&gpu, 0); // Set shader
hs_gpu_set_param(&gpu, 0, v4_one()); // Set param
hs_gpu_set_camera(&gpu, m4_identity()); // Set camera
hs_gpu_load_buffer(&gpu, 0); // Load buffer
hs_gpu_draw(&gpu, 0); // Draw
hs_gpu_cull(&gpu, 1); // Back-face culling
hs_gpu_blend(&gpu, 1, 0); // No blending
hs_gpu_alpha(&gpu, true); // Alpha blending
hs_gpu_depth(&gpu, true); // Enable depth test
hs_gpu_color_mask(&gpu, 0x0F); // RGBA mask
hs_gpu_clip(&gpu, 0, 0, 640, 480);
hs_gpu_load_texture(&gpu, 0);
hs_gpu_set_target(&gpu, 0, 0); // Texture + depth
hs_gpu_show_texture(&gpu, 0);
hs_gpu_texture_filter(&gpu, 0, true); // Linear filtering
hs_gpu_texture_wrap(&gpu, 0, true); // Repeat wrap
hs_gpu_start_recording(&gpu);
hs_gpu_frame_begin(&gpu);
// ... draw calls ...
hs_gpu_frame_end(&gpu);
hs_gpu_present(&gpu);
u32 msg_count = hs_gpu_stop_recording(&gpu);
// Replay later
hs_gpu_replay(&gpu, gpu.log_buffer, msg_count);
Notes:
HSSystem.record_mask and hs_set_record_mask().hs_gpu_fence(&gpu, CHAN_RENDER, cid) to request an apply-time fence result via OP_RESULT.OP_QUERY_STATS / OP_QUERY_FABRIC to retrieve runtime fabric stats via OP_RESULT.HSInput input;
hs_input_init(&input);
// Poll each frame
hs_input_tick(&input);
f32 dx = hs_dir_x(&input); // -1 to 1
f32 dy = hs_dir_y(&input); // -1 to 1
bool btn = hs_button(&input);
f32 mx = hs_mouse_x(&input);
f32 t = hs_time(&input); // Frame time
HSAudio audio;
hs_audio_init(&audio);
// Set channel 0 to shader 1
hs_audio_set_channel(&audio, 0, 1);
// Get audio buffer for channel 0
float* buf = hs_audio_get_buffer(&audio, 0);
if (buf) {
// Fill with samples (3000 samples per buffer)
for (int i = 0; i < HS_AUDIO_BUFFER_SIZE; i++) {
buf[i] = sinf(i * 0.01f); // Simple sine wave
}
}
// Advance to next buffer
hs_audio_advance(&audio, 0);
// Stop channel
hs_audio_stop(&audio, 0);
HSStorage store;
hs_storage_init(&store);
// Load or create slot
HSStorageSlot* slot = hs_storage_load(&store, "savegame1");
// Read/write data
u8 val = hs_storage_get_u8(&store, "savegame1", 0);
hs_storage_set_u8(&store, "savegame1", 0, 42);
f32 fval = hs_storage_get_f32(&store, "savegame1", 4);
hs_storage_set_f32(&store, "savegame1", 4, 3.14f);
// Save to file
hs_storage_save(&store, "save.dat");
// Load from file
hs_storage_load_file(&store, "save.dat");
HSGraphics gfx;
hs_graphics_init(&gfx); // Opens DRM, GBM, EGL
// Create texture from buffer
HSTexture* tex = hs_graphics_create_texture(&gfx, 0, 256, 256, pixel_data);
// Check if texture is disposed
bool disposed = hs_graphics_texture_disposed(&gfx, 0);
// Clear and present
hs_graphics_clear(&gfx, 0.0f, 0.0f, 0.0f, 1.0f);
hs_graphics_present(&gfx);
// Cleanup
hs_graphics_finish(&gfx);
All math uses ARM NEON SIMD for maximum performance:
vec4 v1 = v4_make(1, 2, 3, 4);
vec4 v2 = v4_make(5, 6, 7, 8);
vec4 sum = v4_add(v1, v2);
vec4 diff = v4_sub(v1, v2);
f32 dot = v4_dot(v1, v2);
vec4 cross = v4_cross(v1, v2);
vec4 norm = v4_normalize(v1);
vec4 lerp = v4_lerp(v1, v2, 0.5f);
mat4 m1 = m4_identity();
mat4 m2 = m4_translation(1, 2, 3);
mat4 m3 = m4_multiply(m1, m2);
mat4 inv = m4_invert(m3);
#define HS_FPS 60
#define HS_WIDTH 640
#define HS_HEIGHT 480
#define HS_MAX_NODES 16
#define HS_MAX_MSG_LOG 65536
#define HS_QUEUE_SIZE 256
Enable verbose debug output:
gcc -DHS_DEBUG=1 -O3 -Iinclude -c src/main.c -o main.o
...
make build && ./neogpu_demo
One-liner to compile and run any test (replace XX with 01-06):
make build && gcc -O3 -march=armv8.2-a+fp16+simd -mtune=cortex-a72 -Iinclude -c tests/test_XX_raycast.c -o /tmp/test.o && gcc src/hs_core.o src/hs_gpu.o src/hs_nodes.o /tmp/test.o -o /tmp/test -lm -lGLESv2 -lgbm -ldrm -lEGL && sudo /tmp/test
Available tests:
| Test | Description |
|---|---|
| test_01_clear | Clear screen |
| test_02_triangle | Single triangle |
| test_03_instancing | Hardware instancing |
| test_04_blending | Alpha blending |
| test_05_cube3d | 3D rotating cube |
| test_06_raycast | Ray casting spheres (270 FPS) |
Run specific test:
# Test 06 (raycast)
make build && gcc -O3 -march=armv8.2-a+fp16+simd -mtune=cortex-a72 -Iinclude -c tests/test_06_raycast.c -o /tmp/test.o && gcc src/hs_core.o src/hs_gpu.o src/hs_nodes.o /tmp/test.o -o /tmp/test -lm -lGLESv2 -lgbm -ldrm -lEGL && sudo /tmp/test
Test results on Raspberry Pi 4:
| Feature | Status |
|---|---|
| Message queue (64-byte aligned) | ✅ |
| 5 nodes (Shader, Buffer, Texture, Output, Sound) | ✅ |
| Recording & replay (HSCAP1 format) | ✅ |
| Overflow detection | ✅ |
| All vec4/mat4 ops (NEON) | ✅ |
| Input system | ✅ |
| Alpha blending | ✅ |
| Render targets + depth | ✅ |
| Texture filter/wrap | ✅ |
| Audio system (4 channels, 48KHz) | ✅ |
| Storage (16 slots × 256B, file I/O) | ✅ |
| Graphics (GBM/EGL/GLES for Pi display) | ✅ |
| Test suite (6 graphics tests) | ✅ |
| BitNet inference (1.58-bit, 2B params) | ✅ |
| Pong game demo | ✅ |
| Pong + LLM combined demo | ✅ |
| Message capture & replay | ✅ |
| Component | Size |
|---|---|
| Full HSGpu (with buffers) | 1,055 KB |
| Core system only (no logs) | 32 KB |
| Per-frame bandwidth @60fps | 1.9 KB/frame |
| Section | Size |
|---|---|
| text (code) | 24 KB |
| data | 1 KB |
| bss (buffers at runtime) | 2.1 MB |
| Total | ~25 KB (stripped) |
This is a standalone C implementation inspired by PicoGPU by Nicolas Cannasse.
140 commits
C
62.7%
Python
19.5%
C++
17.3%
Neo GPU is a 25KB NEON-optimized GPU inspired by Pico GPU, for the ARM Cortex-A72 (Pi4) processor family.
C
4
140 commits
updated Apr 2, 2026
Message-native runtime substrate for graphics, tooling, and experimental inference on ARM/NEON hardware.
NeoGPU is a message-native runtime substrate. Rendering is its clearest proof surface today. Tooling and IPC are operationally real peers in the same runtime. ML exists in the tree, but remains experimental until it reaches the same operational standard.
hs_audio.h)hs_storage.h)# Build all
make build
# Run demo
make run
make neogpu_pong
sudo ./neogpu_pong
# Controls: W/S or UP/DOWN arrows, Q to quit
make neogpu_pong_ai
sudo ./neogpu_pong_ai
make neogpu_pong_llm
sudo ./neogpu_pong_llm --model models/bitnet-2b4t-i2s.gguf --prompt "Hello"
This demonstrates:
make neogpu_capture_demo
sudo ./neogpu_capture_demo
# Output: /tmp/neogpu_capture.bin (HSCAP1 format)
# Already built: tools/neogpu_bitnet_chat
sudo ./tools/neogpu_bitnet_chat --model models/bitnet-2b4t-i2s.gguf --prompt "Hello"
neogpu_demo exposes in-process tooling via --tool:
./neogpu_demo --tool --query-stats --query-fabric
# Set record mask (example: record render+rt)
./neogpu_demo --tool --set-record-mask 0x00000006 --query-stats
# Set render budget and query
./neogpu_demo --tool --set-budget 2 8192 --query-stats
Start an IPC server to attach external tools:
# Unix socket (local)
./neogpu_demo --ipc-server /tmp/neogpu.sock --ipc-ms 5000
# TCP/IP (remote)
./neogpu_demo --ipc-tcp 8765 --ipc-ms 5000
Then use the standalone neogpu_tool client:
make tool
./neogpu_tool --sock /tmp/neogpu.sock query-stats
./neogpu_tool --sock /tmp/neogpu.sock query-fabric
./neogpu_tool --host localhost --port 8765 query-fabric # TCP/IP
Channel IDs: 1=RT, 2=RENDER, 3=TELEM
NeoGPU implements explicit RT/RENDER/TELEM channel semantics:
| Channel | QoS | Budget (msgs/tick) | Behavior |
|---|---|---|---|
| RT | Critical | 4096 | Strict priority, no drops |
| RENDER | Interactive | 16384 | Fair share, limited drops |
| TELEM | Background | 1024 | Best-effort, auto-drop |
Query fabric stats:
./neogpu_tool --sock /tmp/neogpu.sock query-fabric
# Output includes: spsc_ok, spsc_full, mpsc_ok, submit_full, submit_hw, telem_dropped
make build
make CC=aarch64-linux-gnu-gcc STRIP=aarch64-linux-gnu-strip build
The clearest proof that NeoGPU is real is visible hardware behavior plus runtime tooling:
tests/test_06_raycast.c - shader-driven sphere demo with live FPS HUDtests/test_07_message_triangle.c - message-driven render path demo./neogpu_demo --tool --query-stats --query-fabric - runtime fabric introspectionIf a change improves local code but weakens these proof surfaces, treat it as suspect until revalidated.
src/
hs_core.c - Message queue, OpCodes, system core
hs_nodes.c - Node message handlers (Shader, Buffer, Texture, Output, Sound)
hs_gpu.c - High-level GPU API
hs_ipc.c - IPC server (Unix domain + TCP/IP)
hs_ml_*.c - ML inference (BitNet 2B)
main.c - Demo/test suite
benchmark.c - Benchmarks
include/
hs_core.h - Core header (includes toolbus for IPC)
hs_ipc.h - IPC server interface
hs_nodes.h - Node headers
hs_gpu.h - GPU API header
hs_math_neon.h - NEON-optimized vec4/mat4 math
hs_buffer.h - Buffer/Texture data types
hs_input.h - Input/controls system
hs_audio.h - 4-channel audio system (48KHz)
hs_storage.h - Persistent storage (16 slots × 256B)
hs_graphics.h - GBM/EGL/GLES graphics backend
hs_ml_infer.h - ML inference API
tools/
neogpu_bitnet_chat.c - Standalone LLM chat
neogpu_pong.c - Simple Pong game
neogpu_pong_ai.c - Pong with AI commentary
neogpu_pong_llm.c - Pong + real BitNet inference
neogpu_capture_demo.c - Message capture demo
neogpu_viz.c - ML visualization
tests/
test_01_clear.c - Clear screen test
test_02_triangle.c - Single triangle
test_03_instancing.c - Hardware instancing
test_04_blending.c - Alpha blending
test_05_cube3d.c - 3D rotating cube
test_06_raycast.c - Ray casting spheres (270 FPS on Pi)
src/archive_ternary_kernels/
- Archived kernel variants (v2-v21)
HSGpu gpu;
hs_gpu_init(&gpu);
hs_gpu_clear(&gpu, v4_make(0, 0, 0, 1)); // Clear with color
hs_gpu_set_shader(&gpu, 0); // Set shader
hs_gpu_set_param(&gpu, 0, v4_one()); // Set param
hs_gpu_set_camera(&gpu, m4_identity()); // Set camera
hs_gpu_load_buffer(&gpu, 0); // Load buffer
hs_gpu_draw(&gpu, 0); // Draw
hs_gpu_cull(&gpu, 1); // Back-face culling
hs_gpu_blend(&gpu, 1, 0); // No blending
hs_gpu_alpha(&gpu, true); // Alpha blending
hs_gpu_depth(&gpu, true); // Enable depth test
hs_gpu_color_mask(&gpu, 0x0F); // RGBA mask
hs_gpu_clip(&gpu, 0, 0, 640, 480);
hs_gpu_load_texture(&gpu, 0);
hs_gpu_set_target(&gpu, 0, 0); // Texture + depth
hs_gpu_show_texture(&gpu, 0);
hs_gpu_texture_filter(&gpu, 0, true); // Linear filtering
hs_gpu_texture_wrap(&gpu, 0, true); // Repeat wrap
hs_gpu_start_recording(&gpu);
hs_gpu_frame_begin(&gpu);
// ... draw calls ...
hs_gpu_frame_end(&gpu);
hs_gpu_present(&gpu);
u32 msg_count = hs_gpu_stop_recording(&gpu);
// Replay later
hs_gpu_replay(&gpu, gpu.log_buffer, msg_count);
Notes:
HSSystem.record_mask and hs_set_record_mask().hs_gpu_fence(&gpu, CHAN_RENDER, cid) to request an apply-time fence result via OP_RESULT.OP_QUERY_STATS / OP_QUERY_FABRIC to retrieve runtime fabric stats via OP_RESULT.HSInput input;
hs_input_init(&input);
// Poll each frame
hs_input_tick(&input);
f32 dx = hs_dir_x(&input); // -1 to 1
f32 dy = hs_dir_y(&input); // -1 to 1
bool btn = hs_button(&input);
f32 mx = hs_mouse_x(&input);
f32 t = hs_time(&input); // Frame time
HSAudio audio;
hs_audio_init(&audio);
// Set channel 0 to shader 1
hs_audio_set_channel(&audio, 0, 1);
// Get audio buffer for channel 0
float* buf = hs_audio_get_buffer(&audio, 0);
if (buf) {
// Fill with samples (3000 samples per buffer)
for (int i = 0; i < HS_AUDIO_BUFFER_SIZE; i++) {
buf[i] = sinf(i * 0.01f); // Simple sine wave
}
}
// Advance to next buffer
hs_audio_advance(&audio, 0);
// Stop channel
hs_audio_stop(&audio, 0);
HSStorage store;
hs_storage_init(&store);
// Load or create slot
HSStorageSlot* slot = hs_storage_load(&store, "savegame1");
// Read/write data
u8 val = hs_storage_get_u8(&store, "savegame1", 0);
hs_storage_set_u8(&store, "savegame1", 0, 42);
f32 fval = hs_storage_get_f32(&store, "savegame1", 4);
hs_storage_set_f32(&store, "savegame1", 4, 3.14f);
// Save to file
hs_storage_save(&store, "save.dat");
// Load from file
hs_storage_load_file(&store, "save.dat");
HSGraphics gfx;
hs_graphics_init(&gfx); // Opens DRM, GBM, EGL
// Create texture from buffer
HSTexture* tex = hs_graphics_create_texture(&gfx, 0, 256, 256, pixel_data);
// Check if texture is disposed
bool disposed = hs_graphics_texture_disposed(&gfx, 0);
// Clear and present
hs_graphics_clear(&gfx, 0.0f, 0.0f, 0.0f, 1.0f);
hs_graphics_present(&gfx);
// Cleanup
hs_graphics_finish(&gfx);
All math uses ARM NEON SIMD for maximum performance:
vec4 v1 = v4_make(1, 2, 3, 4);
vec4 v2 = v4_make(5, 6, 7, 8);
vec4 sum = v4_add(v1, v2);
vec4 diff = v4_sub(v1, v2);
f32 dot = v4_dot(v1, v2);
vec4 cross = v4_cross(v1, v2);
vec4 norm = v4_normalize(v1);
vec4 lerp = v4_lerp(v1, v2, 0.5f);
mat4 m1 = m4_identity();
mat4 m2 = m4_translation(1, 2, 3);
mat4 m3 = m4_multiply(m1, m2);
mat4 inv = m4_invert(m3);
#define HS_FPS 60
#define HS_WIDTH 640
#define HS_HEIGHT 480
#define HS_MAX_NODES 16
#define HS_MAX_MSG_LOG 65536
#define HS_QUEUE_SIZE 256
Enable verbose debug output:
gcc -DHS_DEBUG=1 -O3 -Iinclude -c src/main.c -o main.o
...
make build && ./neogpu_demo
One-liner to compile and run any test (replace XX with 01-06):
make build && gcc -O3 -march=armv8.2-a+fp16+simd -mtune=cortex-a72 -Iinclude -c tests/test_XX_raycast.c -o /tmp/test.o && gcc src/hs_core.o src/hs_gpu.o src/hs_nodes.o /tmp/test.o -o /tmp/test -lm -lGLESv2 -lgbm -ldrm -lEGL && sudo /tmp/test
Available tests:
| Test | Description |
|---|---|
| test_01_clear | Clear screen |
| test_02_triangle | Single triangle |
| test_03_instancing | Hardware instancing |
| test_04_blending | Alpha blending |
| test_05_cube3d | 3D rotating cube |
| test_06_raycast | Ray casting spheres (270 FPS) |
Run specific test:
# Test 06 (raycast)
make build && gcc -O3 -march=armv8.2-a+fp16+simd -mtune=cortex-a72 -Iinclude -c tests/test_06_raycast.c -o /tmp/test.o && gcc src/hs_core.o src/hs_gpu.o src/hs_nodes.o /tmp/test.o -o /tmp/test -lm -lGLESv2 -lgbm -ldrm -lEGL && sudo /tmp/test
Test results on Raspberry Pi 4:
| Feature | Status |
|---|---|
| Message queue (64-byte aligned) | ✅ |
| 5 nodes (Shader, Buffer, Texture, Output, Sound) | ✅ |
| Recording & replay (HSCAP1 format) | ✅ |
| Overflow detection | ✅ |
| All vec4/mat4 ops (NEON) | ✅ |
| Input system | ✅ |
| Alpha blending | ✅ |
| Render targets + depth | ✅ |
| Texture filter/wrap | ✅ |
| Audio system (4 channels, 48KHz) | ✅ |
| Storage (16 slots × 256B, file I/O) | ✅ |
| Graphics (GBM/EGL/GLES for Pi display) | ✅ |
| Test suite (6 graphics tests) | ✅ |
| BitNet inference (1.58-bit, 2B params) | ✅ |
| Pong game demo | ✅ |
| Pong + LLM combined demo | ✅ |
| Message capture & replay | ✅ |
| Component | Size |
|---|---|
| Full HSGpu (with buffers) | 1,055 KB |
| Core system only (no logs) | 32 KB |
| Per-frame bandwidth @60fps | 1.9 KB/frame |
| Section | Size |
|---|---|
| text (code) | 24 KB |
| data | 1 KB |
| bss (buffers at runtime) | 2.1 MB |
| Total | ~25 KB (stripped) |
This is a standalone C implementation inspired by PicoGPU by Nicolas Cannasse.
140 commits
C
62.7%
Python
19.5%
C++
17.3%