Performance Tips
graphics.gd implements many performance optimisations, primarily intended to avoid allocations and
reduce cgo overhead. Here are some general performance tips:
- Due to internal pipelining and batching, calling engine functions that don’t return any values is faster than having to wait for a values to be returned by the engine.
- Constant strings are only allocated once in the engine, use them where possible, otherwise they’ll need to be copied over for each call.
- Use the advanced variant types and methods when you need more control of allocations. Initialise them up front and reuse them wherever possible.
- The main thread is faster (and safer) than goroutines. Most builtin optimisations are intended for accelerating engine calls made on the main thread.
Benchmarks
Section titled “Benchmarks”The spitebench project maintains benchmarks measuring the FFI overhead for different Godot languages.
Trampolines
Section titled “Trampolines”Trampolines help to keep baseline memory allocations low, occasional memory allocations are
absolutely fine but you do not want to be allocating memory for thousands of objects every frame.
A downside of the automatic script exports created by graphics.gd for methods and functions, is
that they use reflection calls under the hood which always allocate.
If a class has any exported methods intended for use in high performance scenarios (called by scripts many many times per frame), then you should create a trampoline for it. This is a special function that accepts raw variant.Arguments values from the engine and calls your function with them.
You only need to create one trampoline per combination of arguments, so if you have two different methods with the same signature, you only need to create one trampoline for both methods.
package main
import ( "graphics.gd/startup" "graphics.gd/variant/Object" "graphics.gd/classdb")
type MyClass struct { Object.Extension[MyClass]}
func (m *MyClass) ThisFunctionAllocates(a int64, b float64) {}
func main() { classdb.Register[MyClass]( classdb.MakeTrampoline(func(instance *MyClass, method func(*MyClass, int64, float64), args variant.Arguments) { method(instance, args.Get(0).Int64(), args.Get(1).Float64()) }) ) startup.Scene()}