WindowServer: Limit msync to 60 Hz and only sync necessary pages
This speeds up GUI a lot. I can now run GUI on real hardware at almost 60 Hz.
This commit is contained in:
parent
fd3cf5d2b1
commit
d58a569660
|
@ -11,6 +11,15 @@
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
WindowServer::WindowServer(Framebuffer& framebuffer)
|
||||||
|
: m_framebuffer(framebuffer)
|
||||||
|
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
||||||
|
, m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)))
|
||||||
|
{
|
||||||
|
MUST(m_pages_to_sync_bitmap.resize(BAN::Math::div_round_up<size_t>(m_framebuffer.width * m_framebuffer.height * sizeof(uint32_t), 4096 * 8), 0));
|
||||||
|
invalidate(m_framebuffer.area());
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> WindowServer::set_background_image(BAN::UniqPtr<LibImage::Image> image)
|
BAN::ErrorOr<void> WindowServer::set_background_image(BAN::UniqPtr<LibImage::Image> image)
|
||||||
{
|
{
|
||||||
if (image->width() != (uint64_t)m_framebuffer.width || image->height() != (uint64_t)m_framebuffer.height)
|
if (image->width() != (uint64_t)m_framebuffer.width || image->height() != (uint64_t)m_framebuffer.height)
|
||||||
|
@ -350,10 +359,52 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
||||||
uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
||||||
mmap_start &= ~(uintptr_t)0xFFF;
|
|
||||||
msync(reinterpret_cast<void*>(mmap_start), mmap_end - mmap_start, MS_SYNC);
|
uintptr_t mmap_addr = mmap_start & ~(uintptr_t)0xFFF;
|
||||||
|
while (mmap_addr < mmap_end)
|
||||||
|
{
|
||||||
|
size_t index = (mmap_addr - reinterpret_cast<uintptr_t>(m_framebuffer.mmap)) / 4096;
|
||||||
|
size_t byte = index / 8;
|
||||||
|
size_t bit = index % 8;
|
||||||
|
m_pages_to_sync_bitmap[byte] |= 1 << bit;
|
||||||
|
mmap_addr += 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::sync()
|
||||||
|
{
|
||||||
|
size_t synced_pages = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
|
||||||
|
{
|
||||||
|
size_t byte = i / 8;
|
||||||
|
size_t bit = i % 8;
|
||||||
|
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t len = 1;
|
||||||
|
while (i + len < m_pages_to_sync_bitmap.size() * 8)
|
||||||
|
{
|
||||||
|
size_t byte = (i + len) / 8;
|
||||||
|
size_t bit = (i + len) % 8;
|
||||||
|
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
|
||||||
|
break;
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
msync(
|
||||||
|
reinterpret_cast<uint8_t*>(m_framebuffer.mmap) + i * 4096,
|
||||||
|
len * 4096,
|
||||||
|
MS_SYNC
|
||||||
|
);
|
||||||
|
synced_pages += len;
|
||||||
|
|
||||||
|
i += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(m_pages_to_sync_bitmap.data(), 0, m_pages_to_sync_bitmap.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle WindowServer::cursor_area() const
|
Rectangle WindowServer::cursor_area() const
|
||||||
|
|
|
@ -19,13 +19,7 @@
|
||||||
class WindowServer
|
class WindowServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
WindowServer(Framebuffer& framebuffer)
|
WindowServer(Framebuffer& framebuffer);
|
||||||
: m_framebuffer(framebuffer)
|
|
||||||
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
|
||||||
, m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)))
|
|
||||||
{
|
|
||||||
invalidate(m_framebuffer.area());
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>);
|
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>);
|
||||||
|
|
||||||
|
@ -38,6 +32,7 @@ public:
|
||||||
|
|
||||||
void set_focused_window(BAN::RefPtr<Window> window);
|
void set_focused_window(BAN::RefPtr<Window> window);
|
||||||
void invalidate(Rectangle area);
|
void invalidate(Rectangle area);
|
||||||
|
void sync();
|
||||||
|
|
||||||
Rectangle cursor_area() const;
|
Rectangle cursor_area() const;
|
||||||
|
|
||||||
|
@ -53,6 +48,8 @@ private:
|
||||||
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||||
BAN::Vector<int> m_client_fds;
|
BAN::Vector<int> m_client_fds;
|
||||||
|
|
||||||
|
BAN::Vector<uint8_t> m_pages_to_sync_bitmap;
|
||||||
|
|
||||||
BAN::UniqPtr<LibImage::Image> m_background_image;
|
BAN::UniqPtr<LibImage::Image> m_background_image;
|
||||||
|
|
||||||
bool m_is_mod_key_held { false };
|
bool m_is_mod_key_held { false };
|
||||||
|
|
|
@ -181,8 +181,21 @@ int main()
|
||||||
if (auto ret = window_server.set_background_image(BAN::move(config.background_image)); ret.is_error())
|
if (auto ret = window_server.set_background_image(BAN::move(config.background_image)); ret.is_error())
|
||||||
dwarnln("Could not set background image: {}", ret.error());
|
dwarnln("Could not set background image: {}", ret.error());
|
||||||
|
|
||||||
|
constexpr uint64_t sync_interval_us = 1'000'000 / 60;
|
||||||
|
timespec last_sync { .tv_sec = 0, .tv_nsec = 0 };
|
||||||
while (!window_server.is_stopped())
|
while (!window_server.is_stopped())
|
||||||
{
|
{
|
||||||
|
timespec current_ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_ts);
|
||||||
|
|
||||||
|
uint64_t us_since_last_sync = (current_ts.tv_sec - last_sync.tv_sec) * 1'000'000 + (current_ts.tv_nsec - last_sync.tv_nsec) / 1000;
|
||||||
|
if (us_since_last_sync > sync_interval_us)
|
||||||
|
{
|
||||||
|
window_server.sync();
|
||||||
|
us_since_last_sync = 0;
|
||||||
|
last_sync = current_ts;
|
||||||
|
}
|
||||||
|
|
||||||
int max_fd = server_fd;
|
int max_fd = server_fd;
|
||||||
|
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
@ -200,7 +213,14 @@ int main()
|
||||||
}
|
}
|
||||||
max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds));
|
max_fd = BAN::Math::max(max_fd, window_server.get_client_fds(fds));
|
||||||
|
|
||||||
if (select(max_fd + 1, &fds, nullptr, nullptr, nullptr) == -1)
|
timeval select_timeout {
|
||||||
|
.tv_sec = 0,
|
||||||
|
.tv_usec = static_cast<long>(sync_interval_us - us_since_last_sync)
|
||||||
|
};
|
||||||
|
int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout);
|
||||||
|
if (nselect == 0)
|
||||||
|
continue;
|
||||||
|
if (nselect == -1)
|
||||||
{
|
{
|
||||||
dwarnln("select: {}", strerror(errno));
|
dwarnln("select: {}", strerror(errno));
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue