Compare commits

..

No commits in common. "15b9cf47a77d9d7d95285ef5186c7e468c20a49e" and "4b7069b0762f8bec791223c11ed30099d7f89e10" have entirely different histories.

2 changed files with 3 additions and 148 deletions

View file

@ -48,9 +48,10 @@ pub const Sdl2Backend = struct {
errdefer c.SDL_DestroyWindow(window);
// Create renderer with hardware acceleration and VSync
// VSync syncs with monitor refresh rate (typically 60Hz):
// VSync syncs with monitor refresh rate (typically 60Hz) which:
// - Eliminates screen tearing
// - Reduces CPU/GPU usage
// - Reduces CPU usage (no busy-wait needed)
// - Provides consistent frame timing
// Falls back to software renderer if GPU not available
const renderer = c.SDL_CreateRenderer(
window,

View file

@ -87,16 +87,6 @@ pub const Context = struct {
/// Whether the entire screen needs redraw
full_redraw: bool,
// =========================================================================
// Dirty Panel System (granularity per named panel)
// =========================================================================
/// Registered panel areas by name (e.g., "who_list", "doc_detail")
panel_areas: std.StringHashMapUnmanaged(Layout.Rect),
/// Dirty flags per panel (true = needs redraw)
dirty_panels: std.StringHashMapUnmanaged(bool),
/// Frame statistics
stats: FrameStats,
@ -167,8 +157,6 @@ pub const Context = struct {
.height = height,
.dirty_rects = .{},
.full_redraw = true,
.panel_areas = .{},
.dirty_panels = .{},
.stats = .{},
.focus = FocusSystem.init(),
};
@ -189,8 +177,6 @@ pub const Context = struct {
.height = height,
.dirty_rects = .{},
.full_redraw = true,
.panel_areas = .{},
.dirty_panels = .{},
.stats = .{},
.focus = FocusSystem.init(),
};
@ -202,8 +188,6 @@ pub const Context = struct {
self.overlay_commands.deinit(self.allocator);
self.id_stack.deinit(self.allocator);
self.dirty_rects.deinit(self.allocator);
self.panel_areas.deinit(self.allocator);
self.dirty_panels.deinit(self.allocator);
self.frame_arena.deinit();
}
@ -254,10 +238,6 @@ pub const Context = struct {
// Reset full_redraw for next frame
self.full_redraw = false;
// Clear dirty panel flags AFTER rendering
// (renderer uses getDirtyPanelRects during frame)
self.clearDirtyPanels();
}
// =========================================================================
@ -763,132 +743,6 @@ pub const Context = struct {
self.width = width;
self.height = height;
self.invalidateAll();
self.markAllPanelsDirty(); // Resize requires all panels to redraw
}
// =========================================================================
// Dirty Panel System (granularity per named panel)
//
// The application registers panel areas at startup:
// ctx.registerPanelArea("who_list", rect);
//
// When data changes, the application marks panels dirty:
// ctx.invalidatePanel("who_list");
//
// The renderer checks which panels are dirty:
// const dirty_rects = ctx.getDirtyPanelRects();
// renderer.clearDirtyRegions(dirty_rects);
//
// At endFrame(), dirty flags are cleared automatically.
// =========================================================================
/// Register a named panel area. Call at startup or when layout changes.
/// The ID should be descriptive (e.g., "who_list", "doc_detail").
pub fn registerPanelArea(self: *Self, id: []const u8, rect: Layout.Rect) void {
self.panel_areas.put(self.allocator, id, rect) catch {
// If we can't register, fall back to full redraw
self.full_redraw = true;
};
// New panels start dirty (need initial draw)
self.dirty_panels.put(self.allocator, id, true) catch {};
}
/// Update a panel's rect (e.g., after window resize).
/// Does NOT mark the panel dirty - call invalidatePanel separately if needed.
pub fn updatePanelArea(self: *Self, id: []const u8, rect: Layout.Rect) void {
if (self.panel_areas.getPtr(id)) |ptr| {
ptr.* = rect;
}
}
/// Mark a panel as needing redraw.
/// Call this when data changes that affects the panel's content.
pub fn invalidatePanel(self: *Self, id: []const u8) void {
if (self.dirty_panels.getPtr(id)) |ptr| {
ptr.* = true;
} else {
// Panel not registered - this is probably a bug
// For safety, do full redraw
self.full_redraw = true;
}
}
/// Check if a panel is marked dirty.
pub fn isPanelDirty(self: *Self, id: []const u8) bool {
if (self.full_redraw) return true;
return self.dirty_panels.get(id) orelse false;
}
/// Mark all registered panels as dirty.
/// Use for resize, tab change, or other global invalidation.
pub fn markAllPanelsDirty(self: *Self) void {
var iter = self.dirty_panels.iterator();
while (iter.next()) |entry| {
entry.value_ptr.* = true;
}
}
/// Get rectangles of all dirty panels (for renderer).
/// Returns slice allocated from frame arena (valid until next beginFrame).
pub fn getDirtyPanelRects(self: *Self) []const Layout.Rect {
if (self.full_redraw) {
// Return single rect covering entire screen
const full = Layout.Rect{
.x = 0,
.y = 0,
.w = self.width,
.h = self.height,
};
const result = self.frame_arena.alloc_slice(Layout.Rect, 1) orelse return &.{};
result[0] = full;
return result;
}
// Count dirty panels
var dirty_count: usize = 0;
var iter = self.dirty_panels.iterator();
while (iter.next()) |entry| {
if (entry.value_ptr.*) dirty_count += 1;
}
if (dirty_count == 0) return &.{};
// Allocate result array from frame arena
const result = self.frame_arena.alloc_slice(Layout.Rect, dirty_count) orelse return &.{};
// Fill with dirty panel rects
var i: usize = 0;
var iter2 = self.dirty_panels.iterator();
while (iter2.next()) |entry| {
if (entry.value_ptr.*) {
if (self.panel_areas.get(entry.key_ptr.*)) |rect| {
result[i] = rect;
i += 1;
}
}
}
return result[0..i];
}
/// Check if any panel is dirty (useful for skip-redraw optimization).
pub fn hasAnyDirtyPanel(self: *Self) bool {
if (self.full_redraw) return true;
var iter = self.dirty_panels.iterator();
while (iter.next()) |entry| {
if (entry.value_ptr.*) return true;
}
return false;
}
/// Clear all dirty panel flags.
/// Called automatically at endFrame(), but can be called manually if needed.
pub fn clearDirtyPanels(self: *Self) void {
var iter = self.dirty_panels.iterator();
while (iter.next()) |entry| {
entry.value_ptr.* = false;
}
}
// =========================================================================