Skip to content

Commit

Permalink
multi-worker rendering is working!
Browse files Browse the repository at this point in the history
  • Loading branch information
mkeeter committed Apr 20, 2024
1 parent 70e58b6 commit 43be92d
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 65 deletions.
3 changes: 3 additions & 0 deletions wasm-demo/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const RENDER_SIZE = 512;
export const WORKERS_PER_SIDE = 4;
export const WORKER_COUNT = WORKERS_PER_SIDE * WORKERS_PER_SIDE;
82 changes: 48 additions & 34 deletions wasm-demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import {
WorkerRequest,
} from "./message";

const RENDER_SIZE = 512;
const WORKERS_PER_SIDE = 4;
const WORKER_COUNT = WORKERS_PER_SIDE * WORKERS_PER_SIDE;
import {
RENDER_SIZE,
WORKERS_PER_SIDE,
WORKER_COUNT,
} from "./constants";

const INITIAL_SCRIPT = "y + x*x";

var fidget: any = null;
Expand All @@ -30,6 +33,8 @@ class App {
scene: Scene;
workers: Array<Worker>;
workers_started: number;
workers_done: number;
start_time: number;

constructor() {
this.scene = new Scene();
Expand All @@ -41,6 +46,7 @@ class App {
this.output = new Output(document.getElementById("output-outer"));
this.workers = [];
this.workers_started = 0;
this.workers_done = 0;

for (let i = 0; i < WORKER_COUNT; ++i) {
const worker = new Worker(new URL("./worker.ts", import.meta.url));
Expand All @@ -58,14 +64,11 @@ class App {
const shapeTree = fidget.eval_script(text);
result = "Ok(..)";

const startTime = performance.now();
this.start_time = performance.now();
this.workers_done = 0;
this.workers.forEach((w) => {
w.postMessage(new ScriptRequest(text));
});
shape = fidget.render(shapeTree, RENDER_SIZE);
const endTime = performance.now();
document.getElementById("status").textContent =
`Rendered in ${endTime - startTime} ms`;
} catch (error) {
// Do some string formatting to make errors cleaner
result = error
Expand All @@ -75,20 +78,27 @@ class App {
.replace(" (expecting ", "\n(expecting ");
}
this.output.setText(result);
if (shape) {
this.scene.setTexture(shape);
this.scene.draw();
}
}

onWorkerMessage(i: number, req: WorkerResponse) {
switch (req.kind) {
case ResponseKind.Image: {
console.log("GOT IMAGE");
const region_size = RENDER_SIZE / WORKERS_PER_SIDE;
const x = Math.trunc(i / WORKERS_PER_SIDE) * region_size;
const y = (WORKERS_PER_SIDE - (i % WORKERS_PER_SIDE) - 1) * region_size;
this.scene.setTextureRegion(x, y, region_size, req.data);
this.scene.draw();

this.workers_done += 1;
if (this.workers_done == WORKER_COUNT) {
const endTime = performance.now();
document.getElementById("status").textContent =
`Rendered in ${endTime - this.start_time} ms`;
}
break;
}
case ResponseKind.Started: {
this.workers[i].postMessage(new StartRequest(i, WORKERS_PER_SIDE));
this.workers[i].postMessage(new StartRequest(i));
this.workers_started += 1;
if (this.workers_started == WORKER_COUNT) {
this.onScriptChanged(INITIAL_SCRIPT);
Expand Down Expand Up @@ -229,34 +239,38 @@ class Scene {
this.buffers = new Buffers(this.gl);
this.programInfo = new ProgramInfo(this.gl);
this.texture = this.gl.createTexture();
this.setTexture(new Uint8Array(RENDER_SIZE * RENDER_SIZE * 4));
}

setTexture(data: Uint8Array) {
// Bind an initial texture of the correct size
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);

const level = 0;
const internalFormat = this.gl.RGBA;
const width = RENDER_SIZE;
const height = RENDER_SIZE;
const border = 0;
const srcFormat = this.gl.RGBA;
const srcType = this.gl.UNSIGNED_BYTE;
this.gl.texImage2D(
this.gl.TEXTURE_2D,
level,
internalFormat,
width,
height,
border,
srcFormat,
srcType,
data,
0,
this.gl.RGBA,
RENDER_SIZE,
RENDER_SIZE,
0, // border
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
new Uint8Array(RENDER_SIZE * RENDER_SIZE * 4),
);

this.gl.generateMipmap(this.gl.TEXTURE_2D);
}

setTextureRegion(x: number, y: number, size: number, data: Uint8Array) {
this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);
this.gl.texSubImage2D(
this.gl.TEXTURE_2D,
0,
x,
y,
size,
size,
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
data,
);
}

draw() {
this.gl.clearColor(0.0, 0.0, 0.0, 1.0);
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
Expand Down
31 changes: 9 additions & 22 deletions wasm-demo/message.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
enum RequestKind {
export enum RequestKind {
Start,
Script,
}

class StartRequest {
export class StartRequest {
kind: RequestKind.Start;
index: number;
workers_per_side: number;

constructor(index: number, workers_per_side: number) {
constructor(index: number) {
this.index = index;
this.workers_per_side = workers_per_side;
this.kind = RequestKind.Start;
}
}

class ScriptRequest {
export class ScriptRequest {
kind: RequestKind.Script;
script: string;

Expand All @@ -25,24 +23,24 @@ class ScriptRequest {
}
}

type WorkerRequest = ScriptRequest | StartRequest;
export type WorkerRequest = ScriptRequest | StartRequest;

////////////////////////////////////////////////////////////////////////////////

enum ResponseKind {
export enum ResponseKind {
Started,
Image,
}

class StartedResponse {
export class StartedResponse {
kind: ResponseKind.Started;

constructor() {
this.kind = ResponseKind.Started;
}
}

class ImageResponse {
export class ImageResponse {
kind: ResponseKind.Image;
data: Uint8Array;

Expand All @@ -52,15 +50,4 @@ class ImageResponse {
}
}

type WorkerResponse = StartedResponse | ImageResponse;

export {
ImageResponse,
RequestKind,
ResponseKind,
ScriptRequest,
StartRequest,
StartedResponse,
WorkerRequest,
WorkerResponse,
};
export type WorkerResponse = StartedResponse | ImageResponse;
14 changes: 11 additions & 3 deletions wasm-demo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,14 @@ pub fn render_region(
let mut ctx = Context::new();
let root = ctx.import(&t);

// Corner position in [0, 1] coordinates
// Corner position in [0, workers_per_side] coordinates
let mut corner = nalgebra::Vector2::new(
index / workers_per_side,
index % workers_per_side,
)
.cast::<f32>();
// Corner position in [-1, 1] coordinates
corner = (corner * 2.0).add_scalar(-1.0);
corner = (corner * 2.0 / workers_per_side as f32).add_scalar(-1.0);

// Scale of each tile
let scale = 2.0 / workers_per_side as f32;
Expand All @@ -90,7 +90,7 @@ pub fn render_region(
image_size: image_size / workers_per_side,
bounds: Bounds {
center,
size: scale,
size: scale / 2.0,
},
..RenderConfig::default()
};
Expand All @@ -102,6 +102,14 @@ pub fn render_region(
.flat_map(|b| {
let b = b as u8 * u8::MAX;
[b, b, b, 255]
/*
[
if index % 2 == 0 { 255 } else { 0 },
if (index / 2) % 2 == 0 { 255 } else { 0 },
if (index / 4) % 2 == 0 { 255 } else { 0 },
255,
]
*/
})
.collect())
}
Expand Down
18 changes: 12 additions & 6 deletions wasm-demo/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,30 @@ import {
WorkerRequest,
} from "./message";

import {
RENDER_SIZE,
WORKERS_PER_SIDE,
WORKER_COUNT,
} from "./constants";

var fidget: any = null;

class Worker {
/// Index of this worker, between 0 and workers_per_side
index: number;

/// Total number of workers per image side
workers_per_side: number;

constructor(req: StartRequest) {
this.index = req.index;
this.workers_per_side = req.workers_per_side;
}

render(s: ScriptRequest) {
const tree = fidget.eval_script(s.script);
const out = fidget.render_region(tree, 512, 0, 4);
const out = fidget.render_region(
tree,
RENDER_SIZE,
this.index,
WORKERS_PER_SIDE,
);
postMessage(new ImageResponse(out));
}
}
Expand All @@ -35,7 +42,6 @@ async function run() {
let req = e.data as WorkerRequest;
switch (req.kind) {
case RequestKind.Start: {
console.log("STARTING");
let r = req as StartRequest;
worker = new Worker(req as StartRequest);
break;
Expand Down

0 comments on commit 43be92d

Please sign in to comment.