newsletters:2025-08
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
newsletters:2025-08 [2025/08/30 22:41] – [Anti-blinking: display list settling] osnr | newsletters:2025-08 [2025/09/01 01:46] (current) – [folk2 on the gadget] osnr | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== August 2025 newsletter | + | ====== August 2025 newsletter ====== |
If you'd like to see the latest updates on Folk in person, **our next Folk open house is [[https:// | If you'd like to see the latest updates on Folk in person, **our next Folk open house is [[https:// | ||
Line 26: | Line 26: | ||
The idea here is that you have a LRU cache on each thread (Tcl interpreter) that maps string -> Jim object. | The idea here is that you have a LRU cache on each thread (Tcl interpreter) that maps string -> Jim object. | ||
- | Then every time you take in a statement on that thread (when it runs a When block), you look up each term in the statement in the thread-local cache, so if you already have a shimmered Jim object that's a parsed list or code expression or something, you can reuse it and save yourself the effort of parsing the term string. | + | Then every time you take in a statement on that thread (when it runs a When block), you look up each term in the statement in the thread-local cache, so if you already have a shimmered Jim object that's a parsed list or code expression or something, you can reuse it and save yourself the effort of parsing the term string. |
(My theory is that we are spending most of our time in folk2 reparsing stuff; every individual When block evaluation seems to take at least 50-100 microseconds, | (My theory is that we are spending most of our time in folk2 reparsing stuff; every individual When block evaluation seems to take at least 50-100 microseconds, | ||
- | You discard any cache entries that haven' | + | (I got it to work this time by making it a more proper LRU cache with a linked list for eviction, as opposed to the hacky double-table scheme I had last time.) |
- | I got it to work this time by making it a more proper LRU cache with a linked list for eviction. | + | The cache hasn't helped as much as I expected, although it does help. Mason reports that calibration cycle time improves from like 200ms to 160ms. |
- | + | ||
- | This hasn't helped as much as I expected, although it does help. Mason reports that calibration cycle time improves from like 200ms to 160ms. | + | |
The thread-local object cache does seem to successfully prevent re-parsing of code on every eval: | The thread-local object cache does seem to successfully prevent re-parsing of code on every eval: | ||
{{: | {{: | ||
+ | |||
+ | I'm not sure why it's not helping more. (I have the same question about Mason' | ||
=== Performance experiment: Mason' | === Performance experiment: Mason' | ||
Line 48: | Line 48: | ||
=== Anti-blinking: | === Anti-blinking: | ||
- | Since the spring, we've had this concept in folk2 of ' | + | Since the spring, we've had this concept in folk2 of [[newsletters/ |
Canvases exist so that we can accurately transform page-local drawings as you lift up and skew the page, and so that we don't have to redraw page-local content when the display list doesn' | Canvases exist so that we can accurately transform page-local drawings as you lift up and skew the page, and so that we don't have to redraw page-local content when the display list doesn' | ||
- | One problem, though, is that drawing to canvases has been a parallel process to drawing on the screen, which means that you need a way to synchronize so you don't draw a canvas to the screen while the canvas is itself being drawn onto. Until this month, we were double-buffering canvases, but this was really annoying to coordinate. I simplified everything to just run in a single loop on the GPU thread and render to canvases before then rendering to the screen. Then we can just have 1 buffer (GPU texture) per canvas, since textures are guaranteed to never be drawn to the screen in an inconsistent state. We have a decent amount of headroom on the GPU thread, so I'm hoping this is good enough for now. | + | One problem, though, is that drawing to canvases has been a parallel process to drawing on the screen, which means that you need a way to synchronize so you don't draw a canvas to the screen while the canvas is itself being drawn onto. Until this month, we were double-buffering canvases, but this was really annoying to coordinate |
+ | |||
+ | I simplified everything | ||
=== Anti-blinking: | === Anti-blinking: | ||
Line 63: | Line 65: | ||
</ | </ | ||
- | If you're familiar with folk2, you might anticipate blinking problems here, because there' | + | If you're familiar with folk2, you might anticipate blinking problems here, because there' |
- | You could do overlap here, where you '' | + | {{:newsletters: |
- | But I don't want to resort to system-wide convergence where you don't see anything until everything in the universe has converged, so I'm trying this concept of per-canvas //settle time//. Basically, the Collect statement that figures out the display list for each canvas won't fire until the display list has been stable for 3ms. This prevents the user from seeing transient states with 0 or 2 label statements above. | ||
- | TODO: Sign error | + | |
+ | You could have a bridge period here, where you '' | ||
+ | |||
+ | But I don't want to resort to system-wide convergence where you don't see anything until everything in the universe has converged, so I'm trying this concept of per-canvas //settle time//: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | Basically, the Collect statement above, which figures out the display list to render onto each canvas every frame, won't re-fire/ | ||
+ | |||
+ | (among other things, had a [[https:// | ||
=== Camera slice blinking fix: destructor inheritance in Collect === | === Camera slice blinking fix: destructor inheritance in Collect === | ||
Line 194: | Line 204: | ||
Omar: I've been [[https:// | Omar: I've been [[https:// | ||
+ | === Fasteners === | ||
+ | |||
+ | Spent some time looking into fasteners to try to keep the AnyBeam projector from swiveling/ | ||
+ | |||
+ | I got some threadlocker glue, and these washers, which I haven' | ||
+ | |||
+ | {{: | ||
+ | |||
+ | === folk2 on the gadget === | ||
+ | |||
+ | folk2 is a surprisingly nice improvement for the gadget. The text is scaled to be a constant real-world size no matter where you hold the gadget, and the whole critical path of Folk runs faster, so even on this mediocre calibration, | ||
+ | |||
+ | {{: | ||
+ | |||
+ | It's hacky and not 100% correct, but to give you an idea of the differences, | ||
+ | |||
+ | < | ||
+ | < | ||
+ | < | ||
+ | # Copy this file to ~/ | ||
+ | # changes. | ||
+ | |||
+ | if {[llength [info commands Assert!]] == 0} { | ||
+ | # We're on folk1. | ||
+ | proc Assert! args { tailcall Assert {*}$args } | ||
+ | |||
+ | set fd [open |[list python3 "/ | ||
+ | fconfigure $fd -buffering line | ||
+ | fileevent $fd readable [list apply {{fd} { | ||
+ | if {[gets $fd line] < 0} { | ||
+ | if {[eof $fd]} { | ||
+ | close $fd | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if {[regexp {Percent: | ||
+ | Hold battery {Claim the battery percentage is $percent} | ||
+ | } | ||
+ | }} $fd] | ||
+ | |||
+ | When display /disp/ has width /w/ height /h/ { | ||
+ | When the button is /state/ { | ||
+ | When the clock time is /t/ { | ||
+ | set color [expr {$state eq " | ||
+ | Wish to draw a dashed stroke with points \ | ||
+ | [list [list 0 0] \ | ||
+ | [list $w 0] \ | ||
+ | [list $w $h] \ | ||
+ | [list 0 $h] \ | ||
+ | [list 0 0]] \ | ||
+ | color $color width 10 dashlength 40 dashoffset [expr {fmod($t, 10)*-120}] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | set cc [c create] | ||
+ | $cc include < | ||
+ | $cc proc gpioInit {} void { | ||
+ | // gpio mode 16 up | ||
+ | FOLK_ENSURE(wiringPiSetup() != -1); | ||
+ | pinMode(16, INPUT); | ||
+ | pullUpDnControl(16, | ||
+ | } | ||
+ | $cc proc gpioRead {} int { | ||
+ | // gpio read 16 | ||
+ | return digitalRead(16); | ||
+ | } | ||
+ | |||
+ | c loadlib / | ||
+ | $cc compile | ||
+ | exec sudo chmod 666 /dev/mem | ||
+ | |||
+ | gpioInit | ||
+ | When the clock time is /t/ { | ||
+ | set pressed [expr {![gpioRead]}] | ||
+ | Hold button \ | ||
+ | {Claim the button is [expr {$pressed ? " | ||
+ | } | ||
+ | puts stderr READY! | ||
+ | |||
+ | } else { | ||
+ | # We're on folk2. | ||
+ | |||
+ | exec v4l2-ctl --set-ctrl auto_exposure=1 | ||
+ | exec v4l2-ctl --set-ctrl exposure_time_absolute=1500 | ||
+ | |||
+ | When { | ||
+ | set fd [open |[list python3 "/ | ||
+ | fconfigure $fd -buffering line | ||
+ | while {[gets $fd line] >= 0} { | ||
+ | if {[eof $fd]} { | ||
+ | close $fd | ||
+ | } | ||
+ | |||
+ | if {[regexp {Percent: | ||
+ | Hold! -key battery \ | ||
+ | Claim the battery percentage is $percent | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | When display /disp/ has width /w/ height /h/ { | ||
+ | When the button is /state/ { | ||
+ | When the clock time is /t/ { | ||
+ | set color [expr {$state eq " | ||
+ | Wish (keep 10ms) to draw a dashed line with points \ | ||
+ | [list [list -1 -1] \ | ||
+ | [list 1 -1] \ | ||
+ | [list 1 1] \ | ||
+ | [list -1 1] \ | ||
+ | [list -1 -1]] \ | ||
+ | color $color width 0.05 dashlength 0.1 dashoffset [expr {fmod($t, 10)*-0.4}] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | set cc [C] | ||
+ | $cc include < | ||
+ | $cc proc gpioInit {} void { | ||
+ | // gpio mode 16 up | ||
+ | FOLK_ENSURE(wiringPiSetup() != -1); | ||
+ | pinMode(16, INPUT); | ||
+ | pullUpDnControl(16, | ||
+ | } | ||
+ | $cc proc gpioRead {} int { | ||
+ | // gpio read 16 | ||
+ | return digitalRead(16); | ||
+ | } | ||
+ | |||
+ | $cc endcflags -L/ | ||
+ | set gpioLib [$cc compile] | ||
+ | exec sudo chmod 666 /dev/mem | ||
+ | |||
+ | $gpioLib gpioInit | ||
+ | When the clock time is /t/ { | ||
+ | set pressed [expr {![$gpioLib gpioRead]}] | ||
+ | Hold! -key button \ | ||
+ | Claim the button is [expr {$pressed ? " | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | Assert! $this wishes $::thisNode uses camera "/ | ||
+ | width 3200 height 1200 \ | ||
+ | crop {x 500 y 0 width 1000 height 800} | ||
+ | |||
+ | Assert! $this wishes $::thisNode uses display 0 | ||
+ | |||
+ | |||
+ | When the battery percentage is /percent/ { | ||
+ | Wish to draw text with text " | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
==== Mason' | ==== Mason' | ||
+ | |||
+ | Mason has been [[https:// | ||
+ | |||
+ | {{newsletters: | ||
==== Projects ==== | ==== Projects ==== | ||
- | * Rob Fielding created a full-fledged system for presenting slides that are fully controlled by programs in Folk: | + | * Rob Fielding |
* {{youtube> | * {{youtube> | ||
Line 203: | Line 372: | ||
==== Outreach ==== | ==== Outreach ==== | ||
- | * Omar hosted [[https:// | + | * Omar hosted |
* {{newsletters: | * {{newsletters: | ||
* Andrés went to Taiwan and visited [[https:// | * Andrés went to Taiwan and visited [[https:// | ||
Line 213: | Line 382: | ||
=== New installations === | === New installations === | ||
- | * TODO: Fractal | + | * The Fractal |
- | * TODO: Baltimore | + | * [[https:// |
- | * TODO: Cambridge | + | * Hamish Todd has been continuing to work on his Cambridge, UK installation and was asking questions about geometry and C API in Discord |
===== What we'll be up to in September ===== | ===== What we'll be up to in September ===== |
newsletters/2025-08.1756593693.txt.gz · Last modified: 2025/08/30 22:41 by osnr