zigrtiow: multithreaded renderer.

This commit is contained in:
Bill Thiede 2022-08-09 21:18:02 -07:00
parent ac73d13fb0
commit e5ffe87192

View File

@ -8,6 +8,8 @@ const hittable = @import("./hittable.zig");
const hittable_list = @import("./hittable_list.zig");
const material = @import("./material.zig");
const Thread = std.Thread;
const Queue = std.atomic.Queue;
const Camera = camera.Camera;
const Color = vec.Color;
const Hittable = hittable.Hittable;
@ -38,6 +40,43 @@ fn ray_color(r: Ray, world: Hittable, depth: isize) Color {
return Color.init(1, 1, 1).scale(1 - t).add(Color.init(0.5, 0.7, 1.0).scale(t));
}
const Task = struct {
cam: Camera,
samples_per_pixel: usize,
max_depth: isize,
row_idx: usize,
image_height: isize,
image_width: isize,
row_pixels: []Color,
world: Hittable,
};
fn render_row(q: *Queue(Task)) void {
var prng = std.rand.DefaultPrng.init(0);
const rand = prng.random();
while (true) {
if (q.get()) |node| {
const task = node.data;
info("Rendering row: {}", .{task.row_idx});
const j = task.row_idx;
var i: usize = 0;
while (i < task.image_width) : (i += 1) {
var pixel_color = Color.init(0, 0, 0);
var s: isize = 0;
while (s < task.samples_per_pixel) : (s += 1) {
const u = (@intToFloat(f32, i) + rand.float(f32)) / @intToFloat(f32, task.image_width - 1);
const v = (@intToFloat(f32, j) + rand.float(f32)) / @intToFloat(f32, task.image_height - 1);
const r = task.cam.get_ray(u, v);
pixel_color = pixel_color.add(ray_color(r, task.world, task.max_depth));
}
task.row_pixels[i] = pixel_color;
}
} else {
return;
}
}
}
pub fn main() anyerror!void {
// Image
const aspect_ratio: f32 = 16.0 / 9.0;
@ -64,27 +103,56 @@ pub fn main() anyerror!void {
const cam = Camera.init();
// Render
const Node = Queue(Task).Node;
const allocator = std.heap.page_allocator;
const cpus = try Thread.getCpuCount();
var pixels: [image_width * image_height]Color = undefined;
var q = Queue(Task).init();
var threads: std.ArrayList(std.Thread) = std.ArrayList(std.Thread).init(allocator);
var row: usize = 0;
while (row < image_height) : (row += 1) {
const node = try allocator.create(Node);
const start: usize = row * image_width;
const end: usize = (row + 1) * image_width;
node.* = .{
.prev = undefined,
.next = undefined,
.data = Task{
.cam = cam,
.samples_per_pixel = samples_per_pixel,
.max_depth = max_depth,
.row_idx = row,
.image_width = image_width,
.image_height = image_height,
.row_pixels = pixels[start..end],
.world = world,
},
};
q.put(node);
}
var t: usize = 0;
while (t < cpus) : (t += 1) {
try threads.append(try Thread.spawn(.{}, render_row, .{&q}));
}
// Wait for all threads to finish.
for (threads.items) |thread| {
Thread.join(thread);
}
const stdout = std.io.getStdOut();
info("Writing image {d}x{d}", .{ image_width, image_height });
try stdout.writer().print("P3\n{d} {d}\n255\n", .{ image_width, image_height });
var prng = std.rand.DefaultPrng.init(0);
const rand = prng.random();
var j: isize = image_height - 1;
while (j >= 0) : (j -= 1) {
info("Scanlines remaining: {d}", .{j});
var i: isize = 0;
var j: usize = 0;
while (j < image_height) : (j += 1) {
var i: usize = 0;
while (i < image_width) : (i += 1) {
var pixel_color = Color.init(0, 0, 0);
var s: isize = 0;
while (s < samples_per_pixel) : (s += 1) {
const u = (@intToFloat(f32, i) + rand.float(f32)) / @intToFloat(f32, image_width - 1);
const v = (@intToFloat(f32, j) + rand.float(f32)) / @intToFloat(f32, image_height - 1);
const r = cam.get_ray(u, v);
pixel_color = pixel_color.add(ray_color(r, world, max_depth));
}
// Flip image upside down.
const j_idx = @as(usize, image_height) - j - 1;
const pixel_color = pixels[i + j_idx * image_width];
try write_color(pixel_color, samples_per_pixel);
}
}