Skip to content

Commit

Permalink
batch small tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
mixtur committed Jul 13, 2024
1 parent 14dd2f9 commit 9b18d00
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 26 deletions.
30 changes: 24 additions & 6 deletions src/js/entry-points/render_worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import '../materials';
import '../texture';
import { render_tile } from '../render_tile';

export interface RenderWorkerMessageData {
export interface TileResult {
tile_index: number;
x: number;
y: number;
Expand All @@ -22,6 +22,7 @@ onmessage = (ev: MessageEvent<InitRenderWorkerParameters>) => {
render(ev.data);
};

const BATCH_THRESHOLD = 100;
function render(
{
aspect_ratio,
Expand All @@ -38,13 +39,22 @@ function render(
const full_work = work.reduce((sum, tile) => sum + tile.width * tile.height * tile.sample_count, 0);
let work_so_far = 0;
const max_tile_size = work.reduce((max_size, tile) => Math.max(max_size, tile.width * tile.height), 0);
const output_allocator = new ArenaVec3Allocator(max_tile_size);
for (let i = 0; i < work.length; i++){
const output_allocators: ArenaVec3Allocator[] = [];
const tile_report: TileResult[] = [];
let t0 = 0;
for (let i = 0; i < work.length; i++) {
if (tile_report.length === 0) {
t0 = performance.now();
}
if (output_allocators[tile_report.length] === undefined) {
output_allocators[tile_report.length] = new ArenaVec3Allocator(max_tile_size);
}
const output_allocator = output_allocators[tile_report.length];
const tile = work[i];
output_allocator.reset();
render_tile(tile, scene, image_width, image_height, max_depth, output_allocator);
work_so_far += tile.width * tile.height * tile.sample_count;
const message: RenderWorkerMessageData = {
tile_report.push({
tile_index: tile.tile_index,
x: tile.x,
y: tile.y,
Expand All @@ -53,7 +63,15 @@ function render(
pixels: output_allocator.dump,
samples_per_pixel: tile.sample_count,
progress: work_so_far / full_work
};
postMessage(message);
});
const dt = performance.now() - t0;
if (dt > BATCH_THRESHOLD) {
postMessage(tile_report);
tile_report.length = 0;
}
}

if (tile_report.length > 0) {
postMessage(tile_report);
}
}
41 changes: 22 additions & 19 deletions src/js/multi_threaded_render.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InitRenderWorkerParameters, RenderParameters } from './types';
import { ColorWriter } from './ui/color-writers';
import { RenderWorkerMessageData } from './entry-points/render_worker';
import { TileResult } from './entry-points/render_worker';
import { color } from './math/vec3.gen';
import { ProgressReporter } from './ui/progress-reporters';
import { ColorFlowItem } from './color-flow';
Expand Down Expand Up @@ -56,28 +56,31 @@ export async function multi_threaded_render({render_parameters, thread_count, wr
promises.push(new Promise<void>(resolve => {
worker.onmessage = (ev: MessageEvent): void => {
event_count++;
const {tile_index, x, y, width, height, pixels, samples_per_pixel, progress} = ev.data as RenderWorkerMessageData;
rays_casted_per_tile[tile_index] += samples_per_pixel;
const tiles = ev.data as TileResult[];
for (let i = 0; i < tiles.length; i++){
const {tile_index, x, y, width, height, pixels, samples_per_pixel, progress} = tiles[i];
rays_casted_per_tile[tile_index] += samples_per_pixel;

for (let i = 0; i < height; i++) {
const w_offset = ((y + i) * image_width + x) * 3;
const r_offset = (i * width) * 3;
for (let j = 0; j < width; j++) {
tmp_color[0] = output_buffer[w_offset + j * 3] += pixels[r_offset + j * 3];
tmp_color[1] = output_buffer[w_offset + j * 3 + 1] += pixels[r_offset + j * 3 + 1];
tmp_color[2] = output_buffer[w_offset + j * 3 + 2] += pixels[r_offset + j * 3 + 2];
write_color(x + j, (image_height - y - i - 1), tmp_color, rays_casted_per_tile[tile_index], color_flow);
for (let i = 0; i < height; i++) {
const w_offset = ((y + i) * image_width + x) * 3;
const r_offset = (i * width) * 3;
for (let j = 0; j < width; j++) {
tmp_color[0] = output_buffer[w_offset + j * 3] += pixels[r_offset + j * 3];
tmp_color[1] = output_buffer[w_offset + j * 3 + 1] += pixels[r_offset + j * 3 + 1];
tmp_color[2] = output_buffer[w_offset + j * 3 + 2] += pixels[r_offset + j * 3 + 2];
write_color(x + j, (image_height - y - i - 1), tmp_color, rays_casted_per_tile[tile_index], color_flow);
}
}
}

dump_tile(x, (image_height - y - height), width, height);
const dt = performance.now() - t0;
progress_reporter.report(thread_id, progress, samples_per_pixel * width * height, total_rays, dt);
dump_tile(x, (image_height - y - height), width, height);
const dt = performance.now() - t0;
progress_reporter.report(thread_id, progress, samples_per_pixel * width * height, total_rays, dt);

if (event_count === load[thread_id].length) {
progress_reporter.report_thread_done(thread_id);
worker.terminate();
resolve();
if (event_count === load[thread_id].length) {
progress_reporter.report_thread_done(thread_id);
worker.terminate();
resolve();
}
}
};
}));
Expand Down
1 change: 0 additions & 1 deletion todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
- hitting bvh with triangles is too slow. Need more efficient in-memory structure after loading gltf. This may also help with messy UV/vertex-normals related code.
- pdf mixer with explicit weights. When using image based importance sampling with PBR material, specular/diffuse rays will get only quarter priority instead of one third. More general mixer may fix that.
- configuration UI
- batch render messages with few samples
- work stealing
- stratified sampling
- scene creation progress ui
Expand Down

0 comments on commit 9b18d00

Please sign in to comment.