graphics.gd FFI Performance Breakthrough (Godot Discussion #277)
This post summarizes a deep research write-up on graphics.gd, a Go language binding for Godot 4 built on GDExtension, and its recent FFI performance optimizations.
Key points
- Headline numbers: With Go 1.26 plus all project-specific optimizations, graphics.gd reaches 8.1 ns/op for arm64 method calls with return values — faster than GDScript's 12.8 ns/op. On x86_64, ring-batched void calls hit 23.3 ns/op (amortized, tight loop; non-batched return-value calls measure ~44.17 ns).
- Go 1.26 runtime change: Commit
7244e92(by Michael Knyszek, CR 646198) removes the_Psyscallstate, eliminating an atomic Store and an atomic CAS on the syscall path. Measured cgo overhead drops ~18–33% depending on hardware (~30% geometric mean). This builds on Go 1.24's#cgo noescape / nocallbackpragmas. - Three-tier optimization stack (all landed by Splizard in ~10 days, February 2026): 1. Leaf methods (~25% of API):
- An object representation rework (
gdreference.Object+pointers.Generic[T,S]) enables zero heap allocation via escape analysis with nearly no API breakage. - The 23.30 ns figure is amortized ring-batch; isolated calls with return values are closer to 44 ns.
- GDScript is a user-perceived latency reference, not the GDExtension FFI floor (bare Rust
extern "C"is ~4–10 ns; gdext cached builtin_ffi ~9–10 ns). - Claims of being "ahead of safe Rust" (gdext safe mode) are qualitative; no public comparable ns/op data.
- Web numbers: return 786.1 ns / void 209.2 ns / GDScript 50.62 ns — 9–18x slower than desktop.
- Uses a direct bridge: Go exposes engine→Go entries via
//go:wasmexport gd_on_*, avoiding JS trampolines and value boxing.GOOS=js GOARCH=wasmlacks full cgo, so a generated ABI shim is used. Thread-safety on web (commitc83a441) distinguishes frame vs. free goroutines under the single OS thread. - No pre-bridge web baseline was provided, so quantified improvement claims for the bridge cannot be made.
- Splizard distinguishes API stability (driven by Godot minor upgrades, ~5–10 breaking changes each, 1–2 hitting GDExtension users) from runtime stability (a version tag alone won't help).
- The actual 1.0 blockers are test coverage (~47 cases, green on Web/Android but lacking cross-platform demos) and sample projects. graphics.gd refuses to put major versions in import paths (citing Stripe's v100+ lesson).
- Recent 30-day commit focus: Godot 4.7 adaptation, multi-platform CI (Web/Android/iOS), thread safety, deterministic builds/musl hardening, mobile crash handling, and test expansion. No explicit 1.0/GA milestone yet, but release-grade finishing work is evident.
- Good fit: Go-only teams; projects needing web GDExtension; teams without mobile toolchains.
- Caution: pre-1.0 API drift; high bus factor (single maintainer); sparse samples.
- Not ideal: AAA-grade performance-critical projects; those needing mature IDE/debugger support; Godot newcomers (godot-cpp + GDScript is safer).
jumponly.Call uses an assembly trampoline that executes a direct CALL to the ptrcall function pointer, skipping cgo entirely. Leaf detection via Clang LibTooling static analysis skips implicit, template, ctor/dtor, and virtual methods.
2. Main-thread sequential void calls: a 256-slot ring buffer (internal/ring/) batches entries and flushes with a single cgo transition. Flush is triggered when full, before a call needing a return value, or before object Free. Order safety: jumponly calls check ring.Main.Pending() first.
3. Everything else: noescape.Call + cgocall with //go:noescape to skip escape analysis.
Benchmark reading caveats
WebAssembly path
Ecosystem positioning (data as of 2026-07-20)
| Binding | Language | Stars | Web | Godot | |---|---|---|---|---| | godot-cpp | C++ | official | yes | 4.3–4.6 | | gdext | Rust | 4,440+ | experimental | 4.6/4.7/4.8 | | Godot C# | C# | official | no | 4.x | | SwiftGodot | Swift | 1,700 | no | 4.4 | | graphics.gd | Go | ~790 | yes | 4.7.0 | | GodotJS | JS | 1,059 | — | 4.1 |
graphics.gd's niche: zero-SDK full-platform support (zig cc cross-compilation, no NDK/Xcode), strongly typed RIDs, native binaries without a .NET runtime, and the only strongly typed web-capable GDExtension binding.