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/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)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
||||
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
||||
|
||||
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
|
||||
|
|
|
@ -19,13 +19,7 @@
|
|||
class WindowServer
|
||||
{
|
||||
public:
|
||||
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());
|
||||
}
|
||||
WindowServer(Framebuffer& framebuffer);
|
||||
|
||||
BAN::ErrorOr<void> set_background_image(BAN::UniqPtr<LibImage::Image>);
|
||||
|
||||
|
@ -38,6 +32,7 @@ public:
|
|||
|
||||
void set_focused_window(BAN::RefPtr<Window> window);
|
||||
void invalidate(Rectangle area);
|
||||
void sync();
|
||||
|
||||
Rectangle cursor_area() const;
|
||||
|
||||
|
@ -53,6 +48,8 @@ private:
|
|||
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||
BAN::Vector<int> m_client_fds;
|
||||
|
||||
BAN::Vector<uint8_t> m_pages_to_sync_bitmap;
|
||||
|
||||
BAN::UniqPtr<LibImage::Image> m_background_image;
|
||||
|
||||
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())
|
||||
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())
|
||||
{
|
||||
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;
|
||||
|
||||
fd_set fds;
|
||||
|
@ -200,7 +213,14 @@ int main()
|
|||
}
|
||||
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));
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue