this repo has no description

added threaded image renderer + output as png

+125 -9
+1
.gitignore
··· 1 1 /zig-cache 2 2 /zig-out 3 + /out
+8 -1
build.zig
··· 4 4 const target = b.standardTargetOptions(.{}); 5 5 const optimize = b.standardOptimizeOption(.{}); 6 6 7 + const enable_spall = b.option(bool, "enable_spall", "Enable spall profiling") orelse false; 8 + const spall = b.dependency("spall", .{ 9 + .enable = enable_spall, 10 + }); 11 + 7 12 const rayray = b.addModule("rayray", .{ 8 13 .root_source_file = .{ .path = "src/rayray.zig" }, 9 14 .target = target, 10 15 .optimize = optimize, 11 16 }); 17 + rayray.addImport("spall", spall.module("spall")); 18 + 12 19 addDeps(b, rayray); 13 20 14 21 const exe = b.addExecutable(.{ ··· 17 24 .target = target, 18 25 .optimize = optimize, 19 26 }); 20 - 27 + exe.root_module.addImport("spall", spall.module("spall")); 21 28 exe.root_module.addImport("rayray", rayray); 22 29 23 30 b.installArtifact(exe);
+6 -3
build.zig.zon
··· 5 5 .dependencies = .{ 6 6 // See `zig fetch --save <url>` for a command-line interface for adding dependencies. 7 7 .zigimg = .{ 8 - .url = "https://github.com/zigimg/zigimg/archive/2224f91ea4cf70f2254848657e308761b8cc8c5d.tar.gz", 9 - // dumy hash, because zigimg does not contain a build.zig. zon 10 - .hash = "122029f65edf3965d86f7d0741fe141bcc1d68b1f013fa7280bbfda4e87c6affc15f", 8 + .url = "https://github.com/rockorager/zigimg/archive/19a49a7e44fb4b1c22341dfbd6566019de742055.tar.gz", 9 + .hash = "1220ebfa8587cfd644995fc08e218dbb3ebd7344fb8e129ff02bc5a6d52a2325370d", 10 + }, 11 + .spall = .{ 12 + .url = "https://git.sr.ht/~altagos/zig-spall/archive/7cae52aa2d1a519006e0c90fbd179cf7fcac0c83.tar.gz", 13 + .hash = "1220753b2f9e7c4f3fb6cdc8fc275cc9073904ea7032a1f5596aa776a857de69f72c", 11 14 }, 12 15 13 16 // libs folder
+22 -1
src/main.zig
··· 1 + const std = @import("std"); 2 + 3 + const spall = @import("spall"); 4 + 1 5 const Raytracer = @import("rayray").Raytracer; 2 6 3 7 pub fn main() !void { 4 - const raytracer = Raytracer.init(); 8 + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); 9 + defer arena.deinit(); 10 + const allocator = arena.allocator(); 11 + 12 + try spall.init("./out/trace.spall"); 13 + defer spall.deinit(); 14 + 15 + spall.init_thread(); 16 + defer spall.deinit_thread(); 17 + 18 + const s = spall.trace(@src(), "Main", .{}); 19 + 20 + var raytracer = try Raytracer.init(allocator); 5 21 defer raytracer.deinit(); 22 + 23 + const img = try raytracer.render(); 24 + 25 + s.end(); 26 + try img.writeToFilePath("./out/out.png", .{ .png = .{} }); 6 27 }
+88 -4
src/rayray.zig
··· 1 1 const std = @import("std"); 2 2 3 + const spall = @import("spall"); 4 + const zigimg = @import("zigimg"); 5 + const color = zigimg.color; 6 + 3 7 pub const Raytracer = struct { 4 8 const Self = @This(); 5 9 6 10 allocator: std.mem.Allocator, 7 11 8 - pub fn init(allocator: std.mem.Allocator) Self { 12 + camera: Camera, 13 + 14 + pub fn init(allocator: std.mem.Allocator) !Self { 9 15 return .{ 10 16 .allocator = allocator, 17 + .camera = try Camera.init(allocator, 256 * 10, 256 * 10), 11 18 }; 12 19 } 13 20 ··· 15 22 _ = self; 16 23 } 17 24 18 - pub fn render(self: *Self) void { 19 - _ = self; 25 + pub fn render(self: *Self) !zigimg.Image { 26 + const s = spall.trace(@src(), "render", .{}); 27 + defer s.end(); 28 + 29 + const rows: usize = try std.Thread.getCpuCount(); 30 + const row_height = @divTrunc(self.camera.height, rows); 31 + const num_threads = blk: { 32 + if (self.camera.height % rows == 0) { 33 + break :blk rows; 34 + } 35 + break :blk rows + 1; 36 + }; 37 + std.debug.print("rows: {}, row_height: {}, num_threads: {}", .{ rows, row_height, num_threads }); 38 + 39 + const threads = try self.allocator.alloc(std.Thread, num_threads); 40 + defer self.allocator.free(threads); 41 + 42 + for (0..num_threads) |row| { 43 + const t = try std.Thread.spawn(.{}, r, .{ &self.camera, row, row_height }); 44 + threads[row] = t; 45 + } 46 + 47 + for (threads) |t| { 48 + t.join(); 49 + } 50 + 51 + return self.camera.image; 52 + } 53 + 54 + fn r(camera: *Camera, row: usize, height: usize) void { 55 + spall.init_thread(); 56 + defer spall.deinit_thread(); 57 + 58 + const s = spall.trace(@src(), "thread {}", .{row}); 59 + defer s.end(); 60 + 61 + for (0..height) |iy| { 62 + const y = iy + height * row; 63 + if (y >= camera.height) break; 64 + 65 + for (0..camera.width) |x| { 66 + @setRuntimeSafety(false); 67 + if (iy <= height - 5) { 68 + camera.setPixel(x, y, color.Rgba32.initRgba( 69 + @intCast(x), 70 + @intCast(y), 71 + 0, 72 + 255, 73 + )) catch break; 74 + } else { 75 + camera.setPixel(x, y, color.Rgba32.initRgba( 76 + 0, 77 + 0, 78 + 255, 79 + 255, 80 + )) catch break; 81 + } 82 + } 83 + } 20 84 } 21 85 }; 22 86 23 - pub const Camera = struct {}; 87 + pub const Camera = struct { 88 + width: usize, 89 + height: usize, 90 + image: zigimg.Image, 91 + 92 + pub fn init(allocator: std.mem.Allocator, width: usize, height: usize) !Camera { 93 + const img = try zigimg.Image.create(allocator, width, height, zigimg.PixelFormat.rgba32); 94 + 95 + return Camera{ 96 + .width = width, 97 + .height = height, 98 + .image = img, 99 + }; 100 + } 101 + 102 + pub fn setPixel(self: *Camera, x: usize, y: usize, c: color.Rgba32) !void { 103 + if (x >= self.width or y >= self.height) return error.OutOfBounds; 104 + const i = x + self.width * y; 105 + self.image.pixels.rgba32[i] = c; 106 + } 107 + };