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