average of 350/360 fps on a AMD Ryzen 7 7840HS on ReleaseFast
This commit is contained in:
parent
c0f3adda16
commit
53a29a3a29
3 changed files with 159 additions and 40 deletions
|
|
@ -31,6 +31,7 @@ pub fn build(b: *std.Build) void {
|
|||
.{ .name = "raygui", .module = raygui },
|
||||
},
|
||||
}),
|
||||
.use_lld = false,
|
||||
});
|
||||
exe.root_module.linkLibrary(raylib_artifact);
|
||||
|
||||
|
|
|
|||
58
src/main.zig
58
src/main.zig
|
|
@ -6,11 +6,12 @@ const raylib = @import("raylib");
|
|||
const raygui = @import("raygui");
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const screenWidth = 800;
|
||||
const screenHeight = 450;
|
||||
const screenWidth = 600;
|
||||
const screenHeight = 600;
|
||||
|
||||
var async: [screenHeight]std.Io.Future(void) = undefined;
|
||||
|
||||
var grid: sand.Grid = try .init(screenWidth, screenHeight, init.gpa);
|
||||
// var gridCopy: sand.Grid = try .init(4, 4, init.gpa);
|
||||
defer grid.deinit(init.gpa);
|
||||
// defer gridCopy.deinit(init.gpa);
|
||||
//
|
||||
|
|
@ -36,18 +37,63 @@ pub fn main(init: std.process.Init) !void {
|
|||
raylib.initWindow(screenWidth, screenHeight, "sand");
|
||||
defer raylib.closeWindow();
|
||||
|
||||
raylib.setTargetFPS(60);
|
||||
raylib.setTargetFPS(144 * 3);
|
||||
|
||||
var timeForUpdate: u64 = 0;
|
||||
var timeForDraw: u64 = 0;
|
||||
|
||||
// init grid
|
||||
var random = std.Random.DefaultPrng.init(@bitCast(std.Io.Timestamp.now(init.io, .real).toMicroseconds()));
|
||||
for (0..300) |y| {
|
||||
for (y..(600 - y)) |x| {
|
||||
grid.arr[y][x] = .{ .alive = random.random().int(u8) > 179 };
|
||||
}
|
||||
}
|
||||
|
||||
const texture: []raylib.Color = try init.gpa.alloc(raylib.Color, screenHeight * screenWidth);
|
||||
defer init.gpa.free(texture);
|
||||
|
||||
const screenImage: raylib.Image = .{
|
||||
.data = @ptrCast(texture.ptr),
|
||||
.width = screenWidth,
|
||||
.height = screenHeight,
|
||||
.mipmaps = 1,
|
||||
.format = .uncompressed_r8g8b8a8,
|
||||
};
|
||||
const screenTexture = try raylib.loadTextureFromImage(screenImage);
|
||||
|
||||
var fps: struct {
|
||||
total: f64,
|
||||
count: f64,
|
||||
} = .{
|
||||
.total = 0,
|
||||
.count = 0,
|
||||
};
|
||||
|
||||
while (!raylib.windowShouldClose()) {
|
||||
grid.updateAll();
|
||||
const updateTimer = std.Io.Clock.now(.awake, init.io);
|
||||
try grid.updateAllConcurrent(init.gpa, init.io, &async);
|
||||
timeForUpdate += @intCast(updateTimer.durationTo(.now(init.io, .awake)).toMicroseconds());
|
||||
|
||||
raylib.beginDrawing();
|
||||
defer raylib.endDrawing();
|
||||
|
||||
const drawTimer = std.Io.Clock.now(.awake, init.io);
|
||||
for (grid.arr, 0..) |line, y| {
|
||||
for (line, 0..) |cell, x| {
|
||||
raylib.drawPixel(@intCast(x), @intCast(y), if (cell.alive) .white else .black);
|
||||
texture[x + screenWidth * y] = if (cell.alive) .white else .black;
|
||||
}
|
||||
}
|
||||
raylib.updateTexture(screenTexture, @ptrCast(texture));
|
||||
raylib.drawTexture(screenTexture, 0, 0, .white);
|
||||
|
||||
timeForDraw += @intCast(drawTimer.durationTo(.now(init.io, .awake)).toMicroseconds());
|
||||
|
||||
fps.count += 1;
|
||||
fps.total += @floatFromInt(raylib.getFPS());
|
||||
std.log.info("fps: {}", .{raylib.getFPS()});
|
||||
}
|
||||
|
||||
std.log.debug("time for draw: {}, time for update: {}", .{ timeForDraw, timeForUpdate });
|
||||
std.log.debug("median fps: {}", .{fps.total / fps.count});
|
||||
}
|
||||
|
|
|
|||
140
src/root.zig
140
src/root.zig
|
|
@ -57,18 +57,46 @@ pub const Grid = struct {
|
|||
allocator.free(self.arr);
|
||||
}
|
||||
|
||||
pub fn updateAll(self: *Grid) void {
|
||||
pub fn updateAll(self: *Grid, allocator: std.mem.Allocator) std.mem.Allocator.Error!void {
|
||||
var newGrid: Grid = try .init(self.max.x + 1, self.max.y + 1, allocator);
|
||||
|
||||
newGrid.leaning = self.leaning.opposite();
|
||||
|
||||
for (0..self.arr.len) |y| {
|
||||
for (0..self.arr[y].len) |x| {
|
||||
update(.{ .y = @truncate(y), .x = @truncate(x) }, self.*);
|
||||
update(.{ .y = @truncate(y), .x = @truncate(x) }, self.*, newGrid);
|
||||
}
|
||||
}
|
||||
self.leaning = self.leaning.opposite();
|
||||
|
||||
self.deinit(allocator);
|
||||
self.* = newGrid;
|
||||
}
|
||||
|
||||
pub fn updateAllConcurrent(self: *Grid, allocator: std.mem.Allocator, io: std.Io, async: []std.Io.Future(void)) (std.mem.Allocator.Error || std.Io.ConcurrentError)!void {
|
||||
var newGrid: Grid = try .init(self.max.x + 1, self.max.y + 1, allocator);
|
||||
|
||||
newGrid.leaning = self.leaning.opposite();
|
||||
|
||||
for (0..self.arr.len) |y| {
|
||||
async[y] = try io.concurrent((struct {
|
||||
pub fn updateLine(s: Grid, ng: Grid, fy: usize) void {
|
||||
for (0..s.arr[fy].len) |x| {
|
||||
update(.{ .y = @truncate(fy), .x = @truncate(x) }, s, ng);
|
||||
}
|
||||
}
|
||||
}).updateLine, .{ self.*, newGrid, y });
|
||||
}
|
||||
for (async) |*a| {
|
||||
a.await(io);
|
||||
}
|
||||
|
||||
self.deinit(allocator);
|
||||
self.* = newGrid;
|
||||
}
|
||||
|
||||
pub const copyError = error{wrongDimensions};
|
||||
pub fn copy(self: Grid, dest: *Grid) copyError!void {
|
||||
if (self.arr.len != dest.arr.len or self.arr[0].len != dest.arr[0].len) return copyError.wrongDimensions;
|
||||
pub fn copy(self: Grid, dest: *Grid) void {
|
||||
std.debug.assert(self.arr.len == dest.arr.len and self.arr[0].len == dest.arr[0].len);
|
||||
for (dest.arr, self.arr) |d, s| {
|
||||
@memcpy(d, s);
|
||||
}
|
||||
|
|
@ -87,43 +115,87 @@ pub const Grid = struct {
|
|||
}
|
||||
};
|
||||
|
||||
pub fn update(self: position, grid: Grid) void {
|
||||
if (self.y == grid.max.y) return;
|
||||
if (!grid.arr[self.y][self.x].alive) return;
|
||||
const nextline = grid.arr[self.y + 1];
|
||||
pub fn update(self: position, grid: Grid, newGrid: Grid) void {
|
||||
alive: switch (false) {
|
||||
false => {
|
||||
std.debug.assert(grid.max == newGrid.max);
|
||||
if (!grid.arr[self.y][self.x].alive) return;
|
||||
if (self.y == grid.max.y) continue :alive true;
|
||||
const nextline = grid.arr[self.y + 1];
|
||||
const newnextline = newGrid.arr[self.y + 1];
|
||||
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
if (self.x == grid.max.x) {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
}
|
||||
} else if (self.x == 0) {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
}
|
||||
} else {
|
||||
switch (grid.leaning) {
|
||||
.Right => {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
}
|
||||
down: switch (nextline[self.x].alive) {
|
||||
false => {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
continue :down true;
|
||||
} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
},
|
||||
.Left => {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
if (@cmpxchgStrong(bool, &nextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
true => {
|
||||
if (self.x == grid.max.x) {
|
||||
if (!nextline[self.x - 1].alive) {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (self.x == 0) {
|
||||
if (!nextline[self.x + 1].alive) {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
switch (grid.leaning) {
|
||||
.Right => {
|
||||
right: switch (nextline[self.x + 1].alive) {
|
||||
false => {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
continue :right true;
|
||||
} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
},
|
||||
true => {
|
||||
if (!nextline[self.x - 1].alive) {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.Left => {
|
||||
left: switch (nextline[self.x - 1].alive) {
|
||||
false => {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x - 1].alive, false, true, .seq_cst, .monotonic)) |_| {
|
||||
continue :left true;
|
||||
} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
},
|
||||
true => {
|
||||
if (!nextline[self.x + 1].alive) {
|
||||
if (@cmpxchgStrong(bool, &newnextline[self.x + 1].alive, false, true, .seq_cst, .monotonic)) |_| {} else {
|
||||
@atomicStore(bool, &newGrid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@atomicStore(bool, &grid.arr[self.y][self.x].alive, false, .seq_cst);
|
||||
continue :alive true;
|
||||
},
|
||||
true => @atomicStore(bool, &newGrid.arr[self.y][self.x].alive, true, .seq_cst),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue