diff --git a/src/render/framebuffer.zig b/src/render/framebuffer.zig index 2121756..9e38b88 100644 --- a/src/render/framebuffer.zig +++ b/src/render/framebuffer.zig @@ -112,6 +112,7 @@ pub const Framebuffer = struct { } /// Draw a filled rectangle + /// Optimized with SIMD-friendly @memset for solid colors (alpha=255) pub fn fillRect(self: *Self, x: i32, y: i32, w: u32, h: u32, color: Color) void { const x_start = @max(0, x); const y_start = @max(0, y); @@ -121,16 +122,28 @@ pub const Framebuffer = struct { if (x_start >= x_end or y_start >= y_end) return; const c = color.toABGR(); + const row_width = @as(u32, @intCast(x_end - x_start)); + const ux_start = @as(u32, @intCast(x_start)); - var py = y_start; - while (py < y_end) : (py += 1) { - const row_start = @as(u32, @intCast(py)) * self.width; - var px = x_start; - while (px < x_end) : (px += 1) { - const idx = row_start + @as(u32, @intCast(px)); - if (color.a == 255) { - self.pixels[idx] = c; - } else if (color.a > 0) { + // FAST PATH: Solid colors (alpha=255) use @memset which is SIMD-optimized + if (color.a == 255) { + var py: u32 = @intCast(y_start); + const uy_end: u32 = @intCast(y_end); + while (py < uy_end) : (py += 1) { + const row_start = py * self.width + ux_start; + @memset(self.pixels[row_start..][0..row_width], c); + } + return; + } + + // SLOW PATH: Alpha blending (pixel by pixel) + if (color.a > 0) { + var py = y_start; + while (py < y_end) : (py += 1) { + const row_start = @as(u32, @intCast(py)) * self.width; + var px = x_start; + while (px < x_end) : (px += 1) { + const idx = row_start + @as(u32, @intCast(px)); const existing = self.pixels[idx]; const bg = Color{ .r = @truncate(existing),