nandi/vflutter_ffipublic Fork 0
f7c3825dc671305345e20a62ea6ac8facbc903bb
Commits
Clone
git clone https://git.rickub.com/nandi/vflutter_ffi.git
git clone ssh://git@rickub.com/nandi/vflutter_ffi.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Add a justfile f7c3825 · on f7c3825dc671305345e20a62ea6ac8facbc903bb · nandithebull · 4h ago
README.md · 96 lines · 3.3 KBmarkdown
Blame HistoryOpen raw

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 and vf_mandelbrot fills it in place, so no V
    memory crosses the boundary and there is nothing to vf_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
# 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 and `vf_mandelbrot` fills it in place, so no V
  memory crosses the boundary and there is nothing to `vf_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

```bash
just mandelbrot
```

or, driving Flutter yourself:

```bash
cd example
flutter run -d linux
```

Only the Linux runner is generated. For the other platforms, generate their
runner directories once first:

```bash
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:

```bash
./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:

```bash
./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:

```bash
dart compile exe example/lib/fractal_bench.dart -o /tmp/bench
LD_LIBRARY_PATH=build /tmp/bench
```