EVE Ray Tracer

Parallel ray tracing with shared-memory workers

Loading...

How it works

This demo renders a ray-traced scene using Web Workers that share memory through SharedArrayBuffer, powered by cljs-thread and the EVE AtomDomain.

  • Scene + framebuffer are stored in a shared EVE atom backed by SharedArrayBuffer. Workers deref the atom to read scene data and write pixels directly to the shared framebuffer — zero serialization.
  • Work distribution uses pmap to parallelize tile rendering across all available workers. Each tile is rendered independently.
  • Live preview — the screen thread runs a 60fps draw loop, continuously blitting the shared framebuffer to canvas while workers render.

The Core Parallelism

The entire render loop is just a parallel map over tile indices:

;; Render all tiles in parallel across workers
(pmap (fn [tile-idx]
        (render-tile! app-state tile-idx
                      tile-w tile-h img-w img-h spp))
      tile-indices)

Each worker reads scene data from the shared atom and writes directly to the shared framebuffer:

;; Worker — render one tile directly to shared framebuffer
(defn render-tile! [app-state tile-idx tile-w tile-h img-w img-h spp]
  (let [state @app-state
        {:keys [spheres materials camera-opts]} (unpack-scene state)
        camera (cam/make-camera camera-opts)
        framebuffer (arr/get-typed-view (:framebuffer state))]
    (render-tile-to-framebuffer! tile-idx tile-w tile-h img-w img-h spp
                                  framebuffer camera spheres materials)
    tile-idx))

The screen thread continuously draws the framebuffer while rendering proceeds:

;; Screen thread draw loop (runs at 60fps)
(in :screen
  (letfn [(draw-loop []
            (when (:rendering? @app-state)
              (let [buf (arr/get-typed-view (:framebuffer @app-state))
                    img-data (.createImageData ctx img-w img-h)]
                (.set (.-data img-data) buf)
                (.putImageData ctx img-data 0 0))
              (js/requestAnimationFrame draw-loop)))]
    (js/requestAnimationFrame draw-loop)))