Chapter 4 of 5
Common patterns
Start with Ripple Pond's coarse request/result seam. Expand it when a concrete consumer needs more data, independent computation or an authored asset. Each link below leads to runnable source; there is no separate recipe runtime.
Return or stage a whole buffer
Ripple Pond's frame method returns the pure subsystem's retained RGBA bytes:
@(gododin)
ripple_pond_frame_bytes :: proc(self: ^Ripple_Pond) -> []u8 {
if self.pond == nil {
self.last_error = 1
return nil
}
return pond.pond_frame(self.pond)
}The slice belongs to the pond. The Host consumes it synchronously during the
callback and copies it once into the returned Godot PackedByteArray.
GDScript owns that value; it never receives a retained pointer into Odin.
This keeps calls coarse, but returning a new array is different from retaining
engine staging across frames and does not claim allocation-free transport.
For large recurring uploads, use an explicit staging owner: the producer writes a slice of retained engine storage while it is uniquely owned and unresized, then publishes the bulk update. Mutable access may detach copy-on-write; resizing invalidates the slice. Never retain a borrowed method input beyond the callback or mutate its read-only view. Cavern Lab's mask refinement copies the admitted packed-byte input into its own mutable workspace.
For many rendered instances, study
Boid Flock's native adapter
and the existing
MultiMesh_Stream owner.
It owns retained staging buffers and their write/publish/retirement sequence,
and borrows the scene's MultiMesh RID. Keep that MultiMesh Resource alive until
the stream closes; closing the stream releases its buffers, not the Resource
or server storage. Godot still owns the rendering concept. The
parity matrix owns named workloads and measured bounds;
these patterns inherit no general speed claim.
Put pure computation on a worker
Cavern Lab's worker owner accepts owned requests, runs the seeded kernel with its own allocator/context, and publishes an owned result through a bounded handoff. Its native adapter submits, cancels and polls on Main, then emits terminal signals for the game consumer.
The pattern has one active request, one replaceable pending request and one completed-result slot. New requests supersede older work; cancellation is cooperative. Consume or release each result once, and reject a retired instance's result. Deinit cancels, joins and drains before releasing worker storage. The worker retains no Godot handle, callback scratch or Main/Render capability. Godot-facing publication occurs in a valid callback after polling. The background example owns its lifecycle tests and workload-specific limits.
Bake data while authoring
Use Cavern Lab's bake designer flow when native computation should produce a durable asset. Godot owns the request Resource, UI and asset identity. A supervised headless child executes the accepted native code; validation and atomic publication replace the asset only on success. Digests identify fresh versus stale output. Cancelled, failed or superseded work preserves the last valid asset.
The shell, child and request/data Resources stay example-specific. They implement bounded process ownership and cleanup, not a general job/editor framework. Bake before export; players consume the resulting asset without the compiler or authoring helper.
Where to go next
- Saved/shared configuration: Cavern Lab's native settings Resource in its
authored package.
A
gd.Ref(Class)property is retained/released by the bridge; a raw pointer or bitwise copy is not a reference owner. - Render-thread work: the compositor fixture
shows
gd.Render_Call, explicit device provenance and reverse-order RID cleanup. Main and Render authority are not interchangeable. - Native libraries: Rewind Lab links its declared static archive into the native image. Its README owns the build prerequisites and runtime closure.
Next: Shipping and updating.