User Tools

Site Tools


newsletters:2023-10

October 2023 newsletter

What we've been up to

Applications and demos

    • Really want to do more of these very specific technical/physical guides – that's kind of what's nice about this newsletter, it can be very concrete and not explicitly philosophical but still communicate the underlying philosophical points
  • Cristóbal Sciutto has been working on a series of iterations of the concept of 'tableshots' (tweet)
    • img_8594.jpg
      • (Omar: You can start to see the real motivation for this work on tableshots: building a hybrid digital-physical 'reading desk' where you can take 'screenshots' of passages of real books. It's a project I've been excited about for years, so I'm glad it's starting to happen.)
  • Naveen Michaud-Agrawal made dials on cardboard tokens:
    • The physicality of the dial – that it's this round cardboard token – is surprisingly important. it would be so much worse for it to be an 8.5×11 sheet of paper, it would be much less of an 'object', you couldn't palm it and hold it by the edge, stuff like that
  • Naveen also made an observability demo where you can point at a performance metric and see a live plot of that metric:

Outreach and new systems

  • Wenjie Wu set up a new system in Sanya, China!
    • folk-wwj.jpg
  • We had a small open house on October 29 – it was fun to bring new people in and show off the system
    • 20231031-082535.jpeg 20231031-082547.jpeg 20231031-082458.jpeg 20231031-082446.jpeg

CNC and calibration

  • Omar and Andrés and friends finished building the CNC! (special shout-out to Riley Wong for their help)
    • Built a heavy tripod Folk system to cover it, including a bright 1080p projector
      • img_1928.jpg img_1925.jpg img_1927.jpg
      • The tripod is a lot more practical here than usual – we have a high ceiling in the workshop, so don't want to use a tension rod, and we can spare the floor space, and we want to mount a heavy projector so we have enough brightness to show up on the material
    • We cut some stuff and immediately felt the motivation to projection-map and use Folk here. There are so many pitfalls with the normal way of doing things, from running into clamps to getting depths and sizes wrong to having to fiddle with random software. See the discussion of the project/prototype below; we're looking forward to doing more here
  • Omar has been working on 3D/real-world/high-accuracy calibration, something we've wanted for a long time (but immediately motivated by the CNC project)
    • A lot of research into various calibration schemes for cameras and projectors. I think we have a really promising strategy for standalone end-to-end projector/camera calibration now! (thread)
      • Implemented the classic Zhang camera calibration technique that pretty much everyone uses on a branch inside Folk/Tcl/using AprilTags, which is a good sign (it's the building block for every end-to-end calibration scheme I can find)
      • There's an interesting set of choices here. We want to use the parts we have (AprilTag emitter and detector, projector, camera, Web server, printer) and not bloat the system with new computer vision pipelines…
    • Talked about this in previous months – this is exciting because full intrinsic projector/camera calibration will finally break us out of the 2D planes / page paradigm, and it'll let us have mobile systems (including phones that understand the world map), and high accuracy will break us out of coarse moving-pages-around – will allow checking boxes, handwriting in text fields, etc
    • Here is the 'calibration rig' right now… (the calibration virtual program sets up a Web endpoint where you get a calibration board PDF to print; then you'll measure its real-world metric and trigger end-to-end calibration in Folk, which will project more AprilTags into the gaps on the board)
    • It's inspiring to look at papers on projector-camera calibration, because the baseline from like 2009 – not even the state of the art – is error of like 0.7 pixels, while Folk still has error of like an entire inch.

Owen's projection-mapped CNC 'print preview' prototype

We've been working with Owen on this project to use Folk to help with CNC, and he put together a prototype that gives an impressively accurate 'print preview' of the CNC cut just using a local homography.

Here's his mini-test on his AxiDraw pen plotter:

Here's what it looks like on our CNC machine after cutting a tag; notice how accurate the projection is to the real cut:

Granted, this is a pain to calibrate each time (you have to calibrate camera, projector, and jog the CNC machine itself), and a reusable general-purpose calibration may not do as well as this (which is calibrated with a checkerboard only on the actual material), and we see some of that inaccuracy in Folk. But I think this shows that we can be very optimistic about technical accuracy, and the real open questions are about the user interface (and we can hopefully answer those questions with Folk).

Other system work

  • Omar: Spent a few hours looking into what it would take to use the Jim Tcl interpreter instead of standard Tcl.
    • (Jim Tcl's C API is a little different from standard Tcl, which is most of the work of adapting Folk to it.)
    • I'm by no means sold on switching, but I think it's very close to being usable to try, and it may have some fun benefits.
      • It may be faster for highly dynamic workloads like ours; it doesn't do bytecode compilation where you need a full lambda (which we can't provide good stability for), it just caches the parse, I think (which is probably stable for us).
      • It's only 15,000 lines of C or so, not much bigger than Folk itself – we would probably just vendor it into the Folk repository and take it over, so it really would be our language, and we could start changing it in serious ways (if we want to keep more data in the heap value struct, if we want a multiprocess heap, etc).
      • It has some built-in niceties: better error reporting, some lexical scope support, a first-class foreign reference type.
    • This would have been a harder sell a year ago, when we were bootstrapping off a lot of Tcl features like the event loop, Tk, and threading, but we mostly are doing our own stuff now (Web + Vulkan UIs, zygote/subprocesses, synchronous mailboxes)
  • Cristóbal made a number of small quality-of-life improvements: image scaling now works (easy to do now that we're on the GPU, just change the shader vertices); you can now do When $this has neighbor /n/ without needing to explicitly wish for neighbors; he also papered over a nasty collect bug for outlines

Andrés's tabletop editor

  • Andrés has been working on the editor. It supports:
    • Writing Folk code into a text area; as you type code is evaluated in realtime
    • Ctrl + r — reset editor text to Wish $this is outlined green, a basic piece of code to outline the active program.
    • Ctrl + p — print out code to
    • Ctrl + a/e — Move cursor to the beginning/end of the line
    • Ctrl + u/k — Delete text from cursor to beginning of line
    • Bugs to be worked out:
      • Standardize on connecting to the keyboard via: Claim $this is keyboard $MACaddress
      • Drawing a green cursor-line object — debugging pic of this below
      • Document setting a keyboard via Bluetooth
  • andres_editor_multi_line.jpeg andres_editor_cursor_debugging.jpeg

Omar's proposal for reactive Variables

(People really struggle with Commit and state management, and I think it'll be increasingly important as we build up more complex applications and simulations)

  • Looked into it a little bit. It can probably be implemented in terms of Observe, which I proposed a while ago, but implementing Observe/Given is also not that easy
    • Idea:

Display

  • Merged the Vulkan branch and the follow-up draw refactor branch, which together basically completely reimplement Folk's display system
    • All Folk drawing is now GPU-accelerated! Drawing generally runs at 60fps now
    • All Folk drawing now happens through wishes with keyword/optional arguments – feels really clean and extensible. All Display:: calls have been deprecated and will visibly warn on use. All drawing primitives now live in cleanly separated files in virtual-programs/display/ (which also serve as examples of how to use the GPU)
        • Notice how the rest pattern /...options/ is used to take the tail of the statement as the options object, and then parameters can just be pulled out of that object
        • A program can draw using Wish to draw a circle with radius 3 center [list 200 300] thickness 2 color green, for instance
    • Any (virtual or paper) program can now compile and run a custom shader; the built-in draw 'primitives' aren't privileged in any way :-)
    • Instructions (to install headless Vulkan on Linux / to install Folk) still need work but seem reasonably OK, except for Nvidia GPUs (which have a different Vulkan implementation)
  • Andrés made a few programs for fonts:
    • andres_font_big_if_true.jpeg
      • A tool for viewing installed fonts on the Folk system.
      • A tool to preview fonts at different sizes
    • andres_folder_font_book.jpeg

The new shader language

Folk now implements a new 'GPU FFI'1) which allows you to compile 'pipelines', which consist of a vertex shader and a fragment shader, which tell the GPU how to draw something.

There aren't great helpers for this yet, like shading a region or anything like that, so you need to work in projector coordinates by hand for now. Let me know what you think would be useful to have.

Here is a very basic shader that you can just paste as a virtual program (or print). It will color a triangle underneath itself green-blue.

Wish the GPU compiles pipeline "$this's triangle" {
    {vec2 p0 vec2 p1 vec2 p2} {
        vec2 vertices[4] = vec2[4](p0, p1, p2, p0);
        return vertices[gl_VertexIndex];
    } {
        return vec4(0, 0.1, 0.1, 1);
    }
}

Wish $this is outlined blue
When $this has region /r/ {
    set r' [region move $r down 100%]
    Wish the GPU draws pipeline "$this's triangle" with arguments [list {*}[lrange [region vertices ${r'}] 0 2]]
}

Notice how you compile the pipeline once (when the program is put down), and then it gets executed repeatedly (whenever the program's region changes).

The pipeline object that you pass after Wish the GPU compiles pipeline NAME has the form {ALL-ARGS VERT-SHADER [FRAG-ARGS] FRAG-SHADER}. See the GPU guide for more information about these pipeline parameters.


There's a nice layering and consistency and comprehensibility to how graphics works now, all the way down. See the ladder:

  1. Object-centric: Wish $this draws a circle with radius 3 ...
  2. Natural-language wish: Wish to draw a circle with radius 3 center {100 200} ...
  3. Vulkan pipeline wish: Wish the GPU draws pipeline "circle" with arguments {3 {100 200} ...}
  4. Tcl imperative: Gpu::draw $circlePipeline 3 {100 200} ...
  5. C FFI: Gpu::drawImpl $circlePipeline [encodeArgs $circlePipelineArgs]
  6. Vulkan/GPU driver: vkCmdDraw(...)

Side quests on the way to Vulkan display


Had to rewrite calibrate to use shaders instead of plotting pixels. Made its print output slightly friendlier


The Folk interprocess heap has been extended to allow freeing of heap allocations (it's now based on dlmalloc instead of just being a bump allocator) and to tag each heap slot with a random 64-bit 'version', as a hacky way to evict stale images that happen to reuse the same heap address (so we know to recopy them to the GPU)

This implementation is pretty inefficient and unsafe (it walks a capped-256 array of all allocations and has a single machine-wide lock) and we may want to replace it with an interval tree or something at some point & introduce finer synchronization


C FFI improvements: struct getter functions, some errors actually abort and throw to Tcl (using longjmp)


dict_getdef has been added


Subprocess code deployment has changed. You boot a subprocess now with Start process NAME, like:

Start process cool {
  Wish $::thisProcess shares statements like [list /someone/ wishes /z/ is labelled /x/]
  Wish $this is labelled "Hello!"
}

You can send more code to an already-existing subprocess with On process NAME:

On process cool {
  Wish $this is labelled "Wow"
}

This is used to deploy code from individual programs to the GPU process, so all GPU process lgoic doesn't have to be in one monolithic file anymore.

There are some catches / ugly bits: process names are global & you now have to explicitly opt into all sharing (either share or receive); there's no sharing by default anymore.


A note on the graphics rewrite

I wanted to talk a little about the motivation for this graphics project. Why did we rewrite Folk's display subsystem away from fbdev/libdrm/pixel-plotting/software-rendering and create this whole GPU-based system? (where everything needs to be a shader, and where we have to talk to Vulkan which then talks to the GPU on the Folk PC)

In a sense, it's like every other optimization we've done – we did it the easy way at first, and then we made the system do more stuff and it became too slow, so we had to rewrite it the hard way.

(Many parts of Folk began as some 100-line Tcl prototype, then became a few hundred lines of faster Tcl or mixed Tcl/C, and now are 1000-2000 lines of C. I was talking to Cristóbal about how this workflow seems surprisingly essential: I doubt that we could have started with the C, it would have been too much to bite off at once, we probably had to bootstrap through the working Tcl prototype to stay motivated and to plan.)

In this case, we added images and image rotation over the summer, and re-rotating like a 2000×2000 image or even a 500×500 chunk of text every frame (as a page's angle continually varies by fractions of a degree) was just very slow, milliseconds or tens of milliseconds per frame. So we switched to the GPU, which is built to do this; all kinds of draw operations are now virtually free. Workloads that used to bring the system down to 20fps now sit solidly at 60fps.2)

(it's surprising how often 2D drawing stuff is not actually hardware-accelerated, even today. we have it easy, because we only have like 3 draw operations anyway; we don't have to support arbitrary font paths or Bezier curves or rasterizing SVG or PostScript or whatever. so why shouldn't we just implement drawing ourselves on the GPU?)

And once the built-in drawing primitives use the GPU, we have to expose the same power – to compile and invoke arbitrary shaders – to the end user. I think it would be a violation of the spirit of Folk to fence it off.

(Jacob asked me about this a while ago, whether it's really idiomatic for people to be doing complex drawing, and if it's not idiomatic, do we actually need to expose the shader language. I think on average we don't necessarily want people rendering complex scenes, but it feels spiritually important for that capability to be available. Maybe you have some craggly public transit shapefile and you want to draw it without making 5000 drawLine calls. Maybe you want your pages to have a glowing halo around them. It feels important to give users the freedom and power to do things like that, without them needing to squeeze through some limited user-facing drawing API.)

Hmm

What we'll be up to in November

  • Tabletop editor
  • Still need to complete RFID refactor
  • Continuing work on new calibration (followed by refactoring a lot of the system to use real-world 3D coordinates, maybe followed by super-accurate camera slicing and OCR)
  • Want to do some follow-up work on Vulkan: user-facing shader language, resource disposal, increase the image limit maybe

Omar

Andrés

Arcade

1)
There's an obvious analogy to our 'C FFI': both systems have you embed arbitrary foreign (C or GLSL) code in a Folk program and make it easy to call from Folk with native Tcl-object parameters.
2)
We also had all kinds of weird issues with fbdev and libdrm: Charles's system would run slow, stuff like that. Vulkan just seems much more consistent and reliable for this type of work.
newsletters/2023-10.txt · Last modified: 2023/11/01 23:01 by admin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki