const std = @import(“std”);
const WIDTH = 800;
const HEIGHT = 600;
var pixels: [WIDTH*HEIGHT]u32 = undefined;
pub fn main() !void {
grig_fill(&pixels, 0xFF00FF00);
try grig_save_as_ppm(&pixels, “pixels.ppm”);
}
fn grig_fill(p: [WIDTHHEIGHT]u32, color: u32) void {
for (0…WIDTHHEIGHT) |i| {
p.[i] = color;
}
}
fn grig_save_as_ppm(p: [WIDTHHEIGHT]u32, path: []const u8) !void {
var out = try std.fs.cwd().createFile(path, .{});
defer out.close();
try out.writer().print("P6\n{} {} 255\n", .{WIDTH, HEIGHT});
for (p) |pixel| {
var bytes = [_]u8{
@intCast((pixel>>(8*0)) & 0xFF),
@intCast((pixel>>(8*1)) & 0xFF),
@intCast((pixel>>(8*2)) & 0xFF),
};
_ = try out.write(&bytes);
}
}
// this works but its too slow. where as c version is so fast.
2 Likes
I think you can try using BufferedWriter
.
const std = @import("std");
const WIDTH = 800;
const HEIGHT = 600;
var pixels: [WIDTH * HEIGHT]u32 = undefined;
pub fn main() !void {
grig_fill(&pixels, 0xFF00FF00);
try grig_save_as_ppm(&pixels, "pixels.ppm");
}
fn grig_fill(p: *[WIDTH * HEIGHT]u32, color: u32) void {
for (0..WIDTH * HEIGHT) |i| {
p.*[i] = color;
}
}
fn grig_save_as_ppm(p: *[WIDTH * HEIGHT]u32, path: []const u8) !void {
var file = try std.fs.cwd().createFile(path, .{});
defer file.close();
var out = std.io.bufferedWriter(file.writer());
try out.writer().print("P6\n{} {} 255\n", .{ WIDTH, HEIGHT });
for (p) |pixel| {
var bytes = [_]u8{
@intCast((pixel >> (8 * 0)) & 0xFF),
@intCast((pixel >> (8 * 1)) & 0xFF),
@intCast((pixel >> (8 * 2)) & 0xFF),
};
_ = try out.write(&bytes);
}
}
Additionally, you can add -Doptimize=ReleaseFast
when building exe.
4 Likes
You are getting bad performance because you are doing a system call per pixel here:
for (p) |pixel| {
var bytes = [_]u8{
@intCast((pixel >> (8 * 0)) & 0xFF),
@intCast((pixel >> (8 * 1)) & 0xFF),
@intCast((pixel >> (8 * 2)) & 0xFF),
};
_ = try out.write(&bytes); <------- HERE
}`
And there are going to be WIDTH * HEIGHT system calls, which is a lot.
So, when using a buffered writer, you are creating a buffer in which your payload is saved (or buffered) until you reach the buffer limit (I think the default is 4096 bytes), and only then is the system call actually done.
2 Likes
…and don’t forget to flush at the end!
try out.flush()
Here’s a good read on the subject: How to Add Buffering to a Reader / Writer in Zig - Zig NEWS
3 Likes
Thank you it works fine now.