From e075667cd2dc878dd9dceb07c85719f6712bcda1 Mon Sep 17 00:00:00 2001 From: James Barnett Date: Sun, 2 Jan 2022 18:23:36 +0000 Subject: Implement multi-threaded rendering --- src/RaytraceDispatcher.ts | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/RaytraceDispatcher.ts (limited to 'src/RaytraceDispatcher.ts') diff --git a/src/RaytraceDispatcher.ts b/src/RaytraceDispatcher.ts new file mode 100644 index 0000000..866d2d1 --- /dev/null +++ b/src/RaytraceDispatcher.ts @@ -0,0 +1,70 @@ +import {Colour} from './Colour'; +import {Framebuffer} from './Framebuffer'; +import {RaytraceContext} from './RaytraceContext'; +import {instanceToPlain} from 'class-transformer'; +import 'reflect-metadata'; + +export class RaytraceDispatcher { + private renderStartMs: number; + private responsesReceived = 0; + constructor( + readonly framebuffer: Framebuffer, + readonly context: RaytraceContext + ) { + this.renderStartMs = new Date().getTime(); + } + + requestRender() { + // Assumes height and threads are always even + const rowBatchSize = this.context.height / this.context.options.numThreads; + + for (let y = 0; y < this.context.height; y += rowBatchSize) { + const rowStartIndex = y; + const rowEndIndex = y + rowBatchSize - 1; + this.dispatchRaytraceWorker(rowStartIndex, rowEndIndex, this.context); + } + } + + private dispatchRaytraceWorker( + rowStartIndex: number, + rowEndIndex: number, + context: RaytraceContext + ) { + console.log( + `Dispatching worker for lines ${rowStartIndex} to ${rowEndIndex}` + ); + + const raytracer = new Worker(new URL('./Raytracer.ts', import.meta.url)); + + raytracer.postMessage({ + type: 'raytraceStart', + rowStartIndex: rowStartIndex, + rowEndIndex: rowEndIndex, + context: JSON.stringify(instanceToPlain(context)), + }); + + raytracer.onmessage = ({data}) => { + if (data.type === 'raytraceResultRow') { + this.processResponse(data.rowIndex, data.resultBuffer); + } + if (data.type === 'raytraceComplete') { + this.handleWorkerComplete(); + } + }; + } + + private handleWorkerComplete() { + if (++this.responsesReceived === this.context.options.numThreads) { + console.log( + `Render completed in ${new Date().getTime() - this.renderStartMs}ms` + ); + } + } + + private processResponse(rowIndex: number, rowData: Colour[]) { + for (let x = 0; x < this.framebuffer.width; x++) { + this.framebuffer.writePixelAt(x, rowIndex, rowData[x]); + } + this.framebuffer.flush(); + } +} -- cgit v1.2.3