From 6bb53d6a80c9bc7e88876fa6774a253aa0ec2af5 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sat, 24 Jul 2021 22:58:53 +0200 Subject: LibGUI: Handle GUI::Window non-volatile backing store issues better Instead of crashing when we can't make the back buffer non-volatile, we now transition the window into single-buffered mode instead (assuming it was originally in double-buffered mode.) This reduces GUI fidelity a bit (by potentially making windows flicker during repaint) but since it's only triggered in low-memory conditions, it seems like a reasonable thing to sacrifice in order for the system to carry on. This patch also stops us from allocating entirely new backing stores after the old ones were purged. If they were purged but reallocated just fine, there's no need to allocate new memory again. We already have fresh zero-filled pages in the existing bitmap at this point. --- Userland/Libraries/LibGUI/Window.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'Userland') diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index e0c7068d30..6945cb230f 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -412,9 +412,19 @@ void Window::handle_multi_paint_event(MultiPaintEvent& event) } else if (m_double_buffering_enabled) { bool was_purged = false; bool bitmap_has_memory = m_back_store->bitmap().set_nonvolatile(was_purged); - if (!bitmap_has_memory || was_purged) { - m_back_store = create_backing_store(event.window_size()); - VERIFY(m_back_store); + if (!bitmap_has_memory) { + // We didn't have enough memory to make the bitmap non-volatile! + // Fall back to single-buffered mode for this window. + // FIXME: Once we have a way to listen for system memory pressure notifications, + // it would be cool to transition back into double-buffered mode once + // the coast is clear. + dbgln("Not enough memory to make backing store non-volatile. Falling back to single-buffered mode."); + m_double_buffering_enabled = false; + m_back_store = move(m_front_store); + created_new_backing_store = true; + } else if (was_purged) { + // The backing store bitmap was cleared, but it does have memory. + // Act as if it's a new backing store so the entire window gets repainted. created_new_backing_store = true; } } @@ -1018,9 +1028,15 @@ void Window::notify_state_changed(Badge, bool minimized, } else { bool was_purged = false; bool bitmap_has_memory = store->bitmap().set_nonvolatile(was_purged); - if (!bitmap_has_memory || was_purged) { + if (!bitmap_has_memory) { + // Not enough memory to make the bitmap non-volatile. Lose the bitmap and schedule an update. + // Let the paint system figure out what to do. store = nullptr; update(); + } else if (was_purged) { + // The bitmap memory was purged by the kernel, but we have all-new zero-filled pages. + // Schedule an update to regenerate the bitmap. + update(); } } } -- cgit v1.2.3