Mabda (Arabic: مبدأ — origin, principle, starting point) is the GPU foundation layer for the AGNOS ecosystem. It wraps the wgpu-native C API and provides shared GPU infrastructure that all AGNOS GPU consumers build upon.
Written in Cyrius, the AGNOS systems language.
Version: 3.0.0-rc.3 (dual backend — wgpu + native AMD; see
Hardware support below. Official 3.0.0 ships after the rc.4
24-hour soak gate per docs/development/3-0-rc-4-punchlist.md;
rc.3 cleared the 6-hour soak on 2026-05-19 with the native render
EXP / SPI_SHADER_COL_FORMAT root-cause fixes landed.)
- Device lifecycle — GpuContext creation with adapter/device/queue management
- Buffer management — storage, uniform, vertex, index, staging, indirect buffers; synchronous readback; GrowableBuffer with generation tracking
- Compute pipelines — shader compilation, bind group layout, dispatch, PingPongBuffer
- Render pipelines —
render_pipeline_create_simplefor full-screen effects, legacyrpb_*builder for back-compat - Textures — RGBA creation, TextureCache, mip levels, dimension validation
- Render targets — offscreen framebuffers with optional MSAA and depth
- Profiling — FrameProfiler with EMA smoothing, frame history, explicit scope timing
- Caching — ShaderCache, PipelineCache, BindGroupCache for GPU resource deduplication
- Capabilities — GPU feature/limit detection, WebGPU compatibility constants
include "lib/mabda.cyr"
fn mabda_main(fn_table_ptr, preinit_ptr) {
color_init();
wgpu_ffi_init_table(fn_table_ptr);
# Create GPU context (via C launcher pre-init)
var res = gpu_context_from_preinit(preinit_ptr);
var ctx = payload(res);
var device = gpu_ctx_device(ctx);
var queue = gpu_ctx_queue(ctx);
# Create a storage buffer
var usage = WGPU_BUFFER_USAGE_STORAGE | WGPU_BUFFER_USAGE_COPY_DST;
var desc = wgpu_buffer_descriptor("my-buf", usage, 1024, 0);
var buf = wgpu_device_create_buffer(device, desc);
# Write data
var data[64];
store64(&data, 42);
wgpu_queue_write_buffer(queue, buf, 0, &data, 64);
wgpu_buffer_release(buf);
gpu_context_release(ctx);
return 0;
}
_cyrius_init() and alloc_init() are called by the C launcher before
mabda_main runs — see docs/stdlib-integration.md
for the full wiring.
| Layer | Modules |
|---|---|
| Core | error, color, capabilities, context, profiler, resource, debug |
| Buffers | buffer, typed_buffer, compute (workgroup math, dispatch, PingPongBuffer), gpu_timestamps |
| Graphics | vertex, blend, sampler, depth, texture, bind_group, instancing |
| Render | render_target, render_pipeline, render_pass, surface |
| Caching | cache_key, shader_cache, pipeline_cache, bind_group_cache |
FFI (@internal) |
wgpu_types, wgpu_descriptors, wgpu_ffi |
| Project | Use Case |
|---|---|
| soorat | Rendering engine (sprites, PBR, shadows, post-effects) |
| rasa | Image editor (GPU compute filters) |
| ranga | Image processing (GPU pixel ops) |
| bijli | EM simulation (FDTD compute) |
| aethersafta | Desktop compositor (GPU compositing) |
| kiran | Game engine (via soorat) |
Mabda owns the wgpu-native FFI boundary. Consumers depend on mabda, not on wgpu directly.
Consumer (soorat, bijli, ...)
↓
mabda (GPU abstraction)
↓
wgpu-native C API (via function table + C launcher) ← shipping today (v2.5.x)
↓
Vulkan / Metal / DX12
In v3.0 a second backend lands alongside the wgpu path. It is selected per-consumer; both coexist. Today the native backend is AMD-only:
Consumer (soorat, bijli, ...)
↓
mabda (GPU abstraction — same @public API on both backends)
↓
┌──────────────────────────────┐ ┌──────────────────────────────┐
│ wgpu backend (default) │ │ native backend (v3.0, opt-in)│
│ wgpu-native + C launcher │ │ pure Cyrius, AMD/amdgpu │
│ Vulkan / Metal / DX12 │ │ DRM ioctls + GFX9 ISA + PM4│
│ AMD / NVIDIA / Intel │ │ AMD only (GFX9 verified; │
│ on Linux/macOS/Windows │ │ NVIDIA + Intel = future │
│ │ │ work, see roadmap) │
└──────────────────────────────┘ └──────────────────────────────┘
Mabda's two backends have different hardware reach. The native backend lands one vendor at a time, and wgpu retires per-chipset as each vendor's native path matures — not all-at-once. The full roadmap is in docs/development/roadmap.md.
| Backend | Vendors | Status |
|---|---|---|
wgpu |
AMD, NVIDIA, Intel (anything wgpu-native + Vulkan/Metal/DX12 supports) | Default. Shipping. All v2.x consumers run here. Retires per-chipset as each vendor's native path matures. |
native (AMD) |
AMD | In development (v3.0, branch v3). Compute dispatch verified end-to-end on AMD Cezanne (gfx90c, GFX9). Other GFX families (GFX10/11/12, RDNA*) not yet exercised — same amdgpu / PM4 / DRM ioctl path, but each generation needs its own bring-up. |
native (NVIDIA) |
NVIDIA | Scoped to v4.0. Different submission path entirely (nouveau / nvgpu, no PM4, different ISA). NVIDIA consumers stay on wgpu until v4.0 ships. |
native (Intel) |
Intel | Tentative for v5.0. Different submission path (i915 / Xe, no PM4, Gen ISA). Intel consumers stay on wgpu until v5.0 ships. |
Per-chipset retirement. When a vendor's native backend has been in production for a full release cycle on that vendor's hardware, the wgpu path is retired for that vendor — the wgpu binding stays in-tree to serve the vendors whose native backends haven't shipped yet. The cutovers (per the roadmap):
- v4.0 — AMD wgpu retires. AMD consumers run on AMD native only. NVIDIA + Intel still on wgpu.
- v5.0 — NVIDIA wgpu retires. NVIDIA consumers run on NVIDIA native only. Intel still on wgpu.
- v5.1 — Intel wgpu retires; the wgpu+C path leaves the tree entirely. Mabda becomes fully native-Cyrius across every supported vendor.
No consumer is forced onto the native backend before their chipset's native path is real — it is opt-in per build, and the wgpu fallback exists for every vendor until that vendor's native backend is in production. Each retirement is gated on every consumer on that vendor having flipped voluntarily; calendar dates are not the gate.
Linux is the only OS the native backend targets. macOS and Windows
consumers stay on wgpu; cross-OS support beyond v5.1 is gated on a
non-wgpu story for those targets, which is not currently scoped.
See ADR 006 for the
multi-backend rationale.
Requires Cyrius 5.5.20+ and gcc
(for the GPU integration test only — CPU tests and benchmarks need
only cyrius).
# Resolve stdlib deps
cyrius deps
# Full gate sweep (lint, fmt, vet, version-check, distlib-sync, tests, bench)
make test-all
# CPU-only unit suite (387 assertions)
cyrius test tests/tcyr/mabda.tcyr
# CPU-only benchmark harness (7 benches; GPU benches via `make bench-gpu`)
cyrius bench tests/bcyr/mabda.bcyr
# Regenerate the dist bundle
cyrius distlib # → dist/mabda.cyr
# GPU integration tests (need wgpu-native in deps/wgpu-native/)
sh deps/fetch-wgpu.sh # one-time
make test-gpu # phase0 + compute_e2e + render_e2e + render_graph_e2e
make bench-gpu # 13 GPU benchesmabda/
├── src/ 30 @public modules + 3 @internal FFI modules
│ (src/lib.cyr is the single include chain)
├── tests/
│ ├── tcyr/mabda.tcyr Consolidated CPU-only suite (387 assertions)
│ └── bcyr/mabda.bcyr CPU-only benchmark harness (7 benches)
├── programs/ 5 GPU integration programs + `benchmarks.cyr`
│ ├── smoke.cyr Link-check — `cyrius build` entry point
│ ├── phase0.cyr GPU buffer/texture/pipeline smoke (10 PASS)
│ ├── compute_e2e.cyr Compute dispatch round-trip (7 PASS)
│ ├── render_e2e.cyr Render-pass clear + readback (8 PASS)
│ ├── render_graph_e2e.cyr Three-node DAG (compute → render → copy) (5 PASS)
│ └── benchmarks.cyr 13 GPU benchmarks, Rust-v1 parity set
├── lib/ Symlink to the installed Cyrius stdlib
├── deps/ C launcher (wgpu_main.c), wgpu-native v29 binaries
├── dist/mabda.cyr Bundled library (generated by `cyrius distlib`)
├── examples/stdlib-consumer/ Minimal "hello GPU" reference project
├── docs/ Architecture, roadmap, ADRs, audit history, guides
├── scripts/ version-check.sh, version-bump.sh
├── cyrius.cyml Package manifest (toolchain pin, [lib], [deps])
├── Makefile Thin wrapper over `cyrius` CLI + GPU path
├── VERSION 3.0.0-rc.3
└── CHANGELOG.md
The @public / @internal markers on line 1 of every src/*.cyr file
are load-bearing: @public = stable API surface that survives the v3.0
backend swap; @internal = FFI scaffolding that gets replaced. See
docs/adr/005-public-api-surface-marking.md
and docs/stdlib-integration.md.
The frozen Rust v1.0.0 source lives under git tag 1.0.0
(git checkout 1.0.0). Historical Rust benchmark numbers are preserved
at docs/rust-v1-bench-history.csv.
Mabda 2.3.0 shipped as the last audit-gated release before first-party trusted status. Full findings + remediation in docs/audit/2026-04-19-audit.md. Report vulnerabilities via the repository's Security tab. See SECURITY.md for the policy.
GPL-3.0-only