vflutter_ffi example
A Mandelbrot explorer whose pixels are computed in V. Scroll to zoom smoothly,
tap to zoom in, right-click to zoom out — all anchored at the cursor. Sliders
control the iteration cap and how many isolates the frame is split across;
"Reset view" restores the framing without disturbing either.
It exists to exercise the parts of the bridge the string demo cannot:
- Bulk data across the boundary. Each frame is a full RGBA buffer, not a
string. Dart allocates it andvf_mandelbrotfills it in place, so no V
memory crosses the boundary and there is nothing tovf_free. - Band parallelism. The image splits into horizontal strips rendered on
separate isolates. Bands are independent by construction, and-gc none
means no stop-the-world phase to serialise them. - An honest benchmark. The same algorithm is written twice — in V
(src/vflutter.v) and in Dart (lib/mandelbrot_dart.dart) — and the
Benchmark button times both. The tests assert the two agree pixel-for-pixel,
which is what makes the comparison meaningful.
What the numbers actually say
Measured here (800x600, maxIter 500, release build, 8-core Linux):
| time | |
|---|---|
| V, one isolate | ~152 ms |
| V, 4 isolates | ~65 ms |
| Dart AOT, one isolate | ~165 ms |
V is not meaningfully faster than Dart at this. For a scalar
floating-point loop, V-through-C and Dart AOT land within ~10% of each other.
The 2.5x comes from the parallel split, which Dart could do on its own without
any FFI. Treat this app as a demonstration of the bridge — bulk buffers,
caller-owned memory, safe multi-isolate calls — not as a speed claim for V.
Reach for V here because you want to write the logic in V, or already have it
in V, not because C-via-V is expected to outrun Dart AOT on arithmetic.
Run it
just mandelbrot
or, driving Flutter yourself:
cd example
flutter run -d linux
Only the Linux runner is generated. For the other platforms, generate their
runner directories once first:
flutter create --platforms=android,ios,macos,windows .
flutter create leaves lib/, test/ and pubspec.yaml alone. The native
library is built by the plugin itself: CMake invokes v on Linux, Windows and
Android; iOS and macOS compile the pre-generated C in ios/Classes/.
Tests
flutter test runs on the host VM rather than in the app bundle, so it needs
the native library on the loader path:
./tool/build.sh
cd example && LD_LIBRARY_PATH=../build flutter test
The suite covers the zoom maths as a property (the point under the cursor stays
put), the buffer contract, the band split matching a single-shot render, and
the V and Dart kernels agreeing exactly.
Headless scripts
No Flutter SDK needed — only dart and the host library. Run from the
repository root, which resolves without Flutter:
./tool/build.sh
LD_LIBRARY_PATH=build dart example/lib/fractal_bench.dart # V vs Dart timings
LD_LIBRARY_PATH=build dart example/lib/main_test.dart # string round-trips
LD_LIBRARY_PATH=build dart example/lib/memory_check.dart # RSS regression guard
For a like-for-like comparison with a release app, compile the benchmark AOT
first — dart run uses the JIT:
dart compile exe example/lib/fractal_bench.dart -o /tmp/bench
LD_LIBRARY_PATH=build /tmp/bench
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
|