import type { Framebuffer } from "engine/render/Framebuffer" import { RenderProtocol, type RenderWorkerInit } from "engine/render/RenderProtocol" import { RenderScene, type RenderInstance } from "engine/render/RenderScene" const ctx = globalThis as unknown as { addEventListener: ( type: "message", handler: (e: { data: RenderWorkerInit }) => void, ) => void } ctx.addEventListener("message", (e) => { const m = e.data const fb: Framebuffer = { width: m.width, height: m.height, color: new Uint32Array(m.colorSAB), depth: new Float32Array(m.depthSAB), } const ctrl = new Int32Array(m.ctrlSAB) const cameraData = new Float64Array(m.cameraSAB) const viewProjection = new Float32Array(m.viewProjectionSAB) const visibleChunks = new Int32Array(m.visibleChunkSAB) const instanceIds = new Int32Array(m.instanceIdSAB) const instanceTransforms = new Float32Array(m.instanceTransformSAB) const times = new Float64Array(m.timesSAB) const { scene, band, config, skyStep, workerIndex } = m const instances: RenderInstance[] = [] // Lock-free frame loop: block until main bumps the frame counter, render this // band, record the band time, and signal done. No messages per frame. let last = 0 for (;;) { Atomics.wait(ctrl, RenderProtocol.FRAME, last) last = Atomics.load(ctrl, RenderProtocol.FRAME) const t0 = performance.now() const frameCamera = RenderProtocol.readCamera(cameraData) const count = Atomics.load(ctrl, RenderProtocol.VISIBLE_CHUNKS) const visible = [...visibleChunks.subarray(0, count)] const instanceCount = Atomics.load(ctrl, RenderProtocol.VISIBLE_INSTANCES) RenderProtocol.readInstances( instanceIds, instanceTransforms, instanceCount, instances, ) RenderScene.renderBand( fb, scene, frameCamera.camera, viewProjection, visible, instances, config, skyStep, frameCamera.time, band[0], band[1], ) times[workerIndex] = performance.now() - t0 Atomics.add(ctrl, RenderProtocol.DONE, 1) } })