nandi/vflutter_ffipublic Fork 0
main
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.

vflutter.v · 117 lines · 3.3 KBCoq Blame HistoryRaw
  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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
module main

import math

// ---------------------------------------------------------------------------
// C-ABI surface consumed by Dart FFI.
//
// Rules for everything below:
//   * only C-compatible types cross the boundary (int, f64, &char, voidptr)
//   * V strings/arrays/options/sumtypes never cross; convert first
//   * anything V allocates and hands out is released by vf_free
// ---------------------------------------------------------------------------

// Touches the V runtime so the GC and global initialisers are demonstrably
// live. The ELF/Mach-O constructor emitted by `v -shared` already does this;
// this exists for static-archive builds (iOS) where the caller wants a
// guaranteed, idempotent entry point.
@[export: 'vf_init']
fn vf_init() {
	probe := 'vf'
	_ = probe.len
}

@[export: 'vf_add']
fn vf_add(a int, b int) int {
	return a + b
}

// Returns a V-allocated C string. Caller releases it with vf_free.
//
// Built with `-gc none`, so every intermediate V allocation here must be
// freed by hand. Only the returned buffer outlives the call.
@[export: 'vf_greet']
fn vf_greet(name &char) &char {
	n := unsafe { cstring_to_vstring(name) }
	res := 'Hello, ${n}, from V!'
	out := unsafe { res.str }
	unsafe { n.free() }
	return out
}

@[export: 'vf_free']
fn vf_free(p voidptr) {
	unsafe { free(p) }
}

// ---------------------------------------------------------------------------
// Mandelbrot kernel.
//
// The buffer is allocated and owned by the *caller*: V only fills it. That
// sidesteps the -gc none ownership rules entirely for bulk data  there is
// nothing to vf_free, and no allocation happens inside the hot loop.
//
// Rows [y0, y1) of a w x h image are written as RGBA8888, packed from the
// start of `buf`, so each call fills a self-contained horizontal band and
// several bands can be computed concurrently from different isolates.
// ---------------------------------------------------------------------------
@[export: 'vf_mandelbrot']
fn vf_mandelbrot(buf &u8, w int, h int, cx f64, cy f64, scale f64, max_iter int, y0 int, y1 int) {
	if w <= 0 || h <= 0 || max_iter <= 0 {
		return
	}
	aspect := f64(w) / f64(h)
	inv_w := 1.0 / f64(w)
	inv_h := 1.0 / f64(h)

	for y := y0; y < y1; y++ {
		im := cy + (f64(y) * inv_h - 0.5) * scale
		row := (y - y0) * w * 4
		for x := 0; x < w; x++ {
			re := cx + (f64(x) * inv_w - 0.5) * scale * aspect

			mut zr := 0.0
			mut zi := 0.0
			mut zr2 := 0.0
			mut zi2 := 0.0
			mut i := 0
			for i < max_iter {
				zr2 = zr * zr
				zi2 = zi * zi
				if zr2 + zi2 > 4.0 {
					break
				}
				zi = 2.0 * zr * zi + im
				zr = zr2 - zi2 + re
				i++
			}

			idx := row + x * 4
			if i >= max_iter {
				// Inside the set.
				unsafe {
					buf[idx] = u8(0)
					buf[idx + 1] = u8(0)
					buf[idx + 2] = u8(0)
					buf[idx + 3] = u8(255)
				}
				continue
			}

			// Smooth (fractional) escape count, so bands don't posterise.
			mag := math.sqrt(zr2 + zi2)
			mut nu := f64(i)
			if mag > 1.0 {
				nu = f64(i) + 1.0 - math.log(math.log(mag) / math.log(2.0)) / math.log(2.0)
			}
			t := nu / f64(max_iter)

			unsafe {
				buf[idx] = u8(255.0 * (0.5 + 0.5 * math.sin(3.0 + t * 18.0)))
				buf[idx + 1] = u8(255.0 * (0.5 + 0.5 * math.sin(3.6 + t * 18.0)))
				buf[idx + 2] = u8(255.0 * (0.5 + 0.5 * math.sin(4.2 + t * 18.0)))
				buf[idx + 3] = u8(255)
			}
		}
	}
}