From 0b0514d46bddf56052ca5a892d3a4b20aa8249c1 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 15 Jan 2021 12:11:22 +0100 Subject: [PATCH] LibGUI+WindowServer: Use anonymous files for window backing stores :^) This patch replaces the use of shbufs for GUI::Window backing stores with the new anonymous files mechanism. Backing bitmaps are now built on memory allocated with anon_create(). They are passed across the IPC socket as IPC::File. This means that WindowServer now pledges "recvfd" and graphical clients need to pledge "sendfd" to work. To support the cached bitmap swapping optimization on the WindowServer side, each backing store is assigned an incrementing serial number on the client side. (This allows us to re-use an already mapped file.) --- Userland/Libraries/LibGUI/Window.cpp | 32 +++++++++++++++---- .../WindowServer/ClientConnection.cpp | 14 ++++---- Userland/Services/WindowServer/Window.h | 9 +++++- .../Services/WindowServer/WindowServer.ipc | 2 +- Userland/Services/WindowServer/main.cpp | 4 +-- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index 5fd2625dc4..e89bfffce6 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -48,10 +49,13 @@ namespace GUI { +static i32 s_next_backing_store_serial; + class WindowBackingStore { public: WindowBackingStore(NonnullRefPtr bitmap) : m_bitmap(bitmap) + , m_serial(++s_next_backing_store_serial) { } @@ -60,8 +64,11 @@ public: Gfx::IntSize size() const { return m_bitmap->size(); } + i32 serial() const { return m_serial; } + private: NonnullRefPtr m_bitmap; + const i32 m_serial; }; static NeverDestroyed> all_windows; @@ -351,7 +358,7 @@ void Window::handle_multi_paint_event(MultiPaintEvent& event) m_back_store = create_backing_store(event.window_size()); ASSERT(m_back_store); } else if (m_double_buffering_enabled) { - bool still_has_pixels = m_back_store->bitmap().shared_buffer()->set_nonvolatile(); + bool still_has_pixels = m_back_store->bitmap().set_nonvolatile(); if (!still_has_pixels) { m_back_store = create_backing_store(event.window_size()); ASSERT(m_back_store); @@ -678,7 +685,7 @@ void Window::set_hovered_widget(Widget* widget) void Window::set_current_backing_store(WindowBackingStore& backing_store, bool flush_immediately) { auto& bitmap = backing_store.bitmap(); - WindowServerConnection::the().send_sync(m_window_id, 32, bitmap.pitch(), bitmap.shbuf_id(), bitmap.has_alpha_channel(), bitmap.size(), flush_immediately); + WindowServerConnection::the().send_sync(m_window_id, 32, bitmap.pitch(), bitmap.anon_fd(), backing_store.serial(), bitmap.has_alpha_channel(), bitmap.size(), flush_immediately); } void Window::flip(const Vector& dirty_rects) @@ -691,7 +698,7 @@ void Window::flip(const Vector& dirty_rects) m_back_store = create_backing_store(m_front_store->size()); ASSERT(m_back_store); memcpy(m_back_store->bitmap().scanline(0), m_front_store->bitmap().scanline(0), m_front_store->bitmap().size_in_bytes()); - m_back_store->bitmap().shared_buffer()->set_volatile(); + m_back_store->bitmap().set_volatile(); return; } @@ -700,7 +707,7 @@ void Window::flip(const Vector& dirty_rects) for (auto& dirty_rect : dirty_rects) painter.blit(dirty_rect.location(), m_front_store->bitmap(), dirty_rect); - m_back_store->bitmap().shared_buffer()->set_volatile(); + m_back_store->bitmap().set_volatile(); } RefPtr Window::create_shared_bitmap(Gfx::BitmapFormat format, const Gfx::IntSize& size) @@ -718,7 +725,18 @@ RefPtr Window::create_shared_bitmap(Gfx::BitmapFormat format, const OwnPtr Window::create_backing_store(const Gfx::IntSize& size) { auto format = m_has_alpha_channel ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32; - auto bitmap = create_shared_bitmap(format, size); + + ASSERT(!size.is_empty()); + size_t pitch = Gfx::Bitmap::minimum_pitch(size.width(), format); + size_t size_in_bytes = size.height() * pitch; + + auto anon_fd = anon_create(round_up_to_power_of_two(size_in_bytes, PAGE_SIZE), O_CLOEXEC); + if (anon_fd < 0) { + perror("anon_create"); + return {}; + } + + auto bitmap = Gfx::Bitmap::create_with_anon_fd(format, anon_fd, size, Gfx::Bitmap::ShouldCloseAnonymousFile::No); if (!bitmap) return {}; return make(bitmap.release_nonnull()); @@ -870,9 +888,9 @@ void Window::notify_state_changed(Badge, bool minimized, if (!store) return; if (minimized || occluded) { - store->bitmap().shared_buffer()->set_volatile(); + store->bitmap().set_volatile(); } else { - if (!store->bitmap().shared_buffer()->set_nonvolatile()) { + if (!store->bitmap().set_nonvolatile()) { store = nullptr; update(); } diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index f0e4402d81..33ce6e9bcb 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -571,17 +571,15 @@ OwnPtr ClientConnection:: return {}; } auto& window = *(*it).value; - if (window.last_backing_store() && window.last_backing_store()->shbuf_id() == message.shbuf_id()) { + if (window.last_backing_store() && window.last_backing_store_serial() == message.serial()) { window.swap_backing_stores(); } else { - auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id()); - if (!shared_buffer) - return make(); - auto backing_store = Gfx::Bitmap::create_with_shared_buffer( + auto backing_store = Gfx::Bitmap::create_with_anon_fd( message.has_alpha_channel() ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32, - *shared_buffer, - message.size()); - window.set_backing_store(move(backing_store)); + message.anon_file().take_fd(), + message.size(), + Gfx::Bitmap::ShouldCloseAnonymousFile::Yes); + window.set_backing_store(move(backing_store), message.serial()); } if (message.flush_immediately()) diff --git a/Userland/Services/WindowServer/Window.h b/Userland/Services/WindowServer/Window.h index 286d543cc4..c2c54311d5 100644 --- a/Userland/Services/WindowServer/Window.h +++ b/Userland/Services/WindowServer/Window.h @@ -190,18 +190,23 @@ public: const Gfx::Bitmap* backing_store() const { return m_backing_store.ptr(); } Gfx::Bitmap* backing_store() { return m_backing_store.ptr(); } - void set_backing_store(RefPtr&& backing_store) + void set_backing_store(RefPtr backing_store, i32 serial) { m_last_backing_store = move(m_backing_store); m_backing_store = move(backing_store); + + m_last_backing_store_serial = m_backing_store_serial; + m_backing_store_serial = serial; } void swap_backing_stores() { swap(m_backing_store, m_last_backing_store); + swap(m_backing_store_serial, m_last_backing_store_serial); } Gfx::Bitmap* last_backing_store() { return m_last_backing_store.ptr(); } + i32 last_backing_store_serial() const { return m_last_backing_store_serial; } void set_global_cursor_tracking_enabled(bool); void set_automatic_cursor_tracking_enabled(bool enabled) { m_automatic_cursor_tracking_enabled = enabled; } @@ -340,6 +345,8 @@ private: bool m_occluded { false }; RefPtr m_backing_store; RefPtr m_last_backing_store; + i32 m_backing_store_serial { -1 }; + i32 m_last_backing_store_serial { -1 }; int m_window_id { -1 }; i32 m_client_id { -1 }; float m_opacity { 1 }; diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index 72399de1db..20f4d946bd 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -68,7 +68,7 @@ endpoint WindowServer = 2 SetGlobalCursorTracking(i32 window_id, bool enabled) => () SetWindowOpacity(i32 window_id, float opacity) => () - SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, i32 shbuf_id, bool has_alpha_channel, Gfx::IntSize size, bool flush_immediately) => () + SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, IPC::File anon_file, i32 serial, bool has_alpha_channel, Gfx::IntSize size, bool flush_immediately) => () WM_SetActiveWindow(i32 client_id, i32 window_id) =| WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =| diff --git a/Userland/Services/WindowServer/main.cpp b/Userland/Services/WindowServer/main.cpp index ca8d997f0d..917db89646 100644 --- a/Userland/Services/WindowServer/main.cpp +++ b/Userland/Services/WindowServer/main.cpp @@ -39,7 +39,7 @@ int main(int, char**) { - if (pledge("stdio video thread shared_buffer accept rpath wpath cpath unix proc fattr sigaction", nullptr) < 0) { + if (pledge("stdio video thread recvfd shared_buffer accept rpath wpath cpath unix proc fattr sigaction", nullptr) < 0) { perror("pledge"); return 1; } @@ -84,7 +84,7 @@ int main(int, char**) WindowServer::EventLoop loop; - if (pledge("stdio video thread shared_buffer accept rpath wpath cpath proc", nullptr) < 0) { + if (pledge("stdio video thread recvfd shared_buffer accept rpath wpath cpath proc", nullptr) < 0) { perror("pledge"); return 1; }