Compare commits
7 Commits
51bfe4252d
...
36d07065fb
Author | SHA1 | Date |
---|---|---|
Bananymous | 36d07065fb | |
Bananymous | f206e72447 | |
Bananymous | 58e45fb394 | |
Bananymous | 411f32c766 | |
Bananymous | e1b82e4e43 | |
Bananymous | df613775b6 | |
Bananymous | 5e8fdc997a |
|
@ -60,6 +60,7 @@ namespace Kernel
|
||||||
static void wait_until_processors_ready();
|
static void wait_until_processors_ready();
|
||||||
|
|
||||||
static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; }
|
static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; }
|
||||||
|
static bool get_should_print_cpu_load() { return s_should_print_cpu_load; }
|
||||||
|
|
||||||
static ProcessorID bsb_id() { return s_bsb_id; }
|
static ProcessorID bsb_id() { return s_bsb_id; }
|
||||||
static bool current_is_bsb() { return current_id() == bsb_id(); }
|
static bool current_is_bsb() { return current_id() == bsb_id(); }
|
||||||
|
|
|
@ -3,11 +3,14 @@
|
||||||
#include <kernel/Device/FramebufferDevice.h>
|
#include <kernel/Device/FramebufferDevice.h>
|
||||||
#include <kernel/FS/DevFS/FileSystem.h>
|
#include <kernel/FS/DevFS/FileSystem.h>
|
||||||
#include <kernel/Memory/Heap.h>
|
#include <kernel/Memory/Heap.h>
|
||||||
|
#include <kernel/Terminal/TerminalDriver.h>
|
||||||
|
|
||||||
#include <sys/framebuffer.h>
|
#include <sys/framebuffer.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
|
|
||||||
|
extern Kernel::TerminalDriver* g_terminal_driver;
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -250,16 +253,21 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
if (flags != MS_SYNC)
|
if (flags != MS_SYNC)
|
||||||
return BAN::Error::from_errno(ENOTSUP);
|
return BAN::Error::from_errno(ENOTSUP);
|
||||||
|
if (vaddr % (BANAN_FB_BPP / 8))
|
||||||
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
if (vaddr < m_vaddr)
|
if (auto rem = size % (BANAN_FB_BPP / 8))
|
||||||
vaddr = m_vaddr;
|
size += (BANAN_FB_BPP / 8) - rem;
|
||||||
if (vaddr + size > m_vaddr + m_size)
|
|
||||||
size = (vaddr - m_vaddr) + m_size;
|
|
||||||
|
|
||||||
m_framebuffer->sync_pixels_linear(
|
const vaddr_t start = BAN::Math::max(vaddr, m_vaddr);
|
||||||
(vaddr - m_vaddr) / (BANAN_FB_BPP / 8),
|
const size_t end = BAN::Math::min(vaddr + size, m_vaddr + m_size);
|
||||||
BAN::Math::div_round_up<uint32_t>((vaddr % (BANAN_FB_BPP / 8)) + size, (BANAN_FB_BPP / 8))
|
if (start < end)
|
||||||
);
|
{
|
||||||
|
do_msync(
|
||||||
|
(start - m_vaddr) / (BANAN_FB_BPP / 8),
|
||||||
|
(end - start) / (BANAN_FB_BPP / 8)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -300,6 +308,53 @@ namespace Kernel
|
||||||
, m_framebuffer(framebuffer)
|
, m_framebuffer(framebuffer)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
void do_msync(uint32_t first_pixel, uint32_t pixel_count)
|
||||||
|
{
|
||||||
|
if (!Processor::get_should_print_cpu_load())
|
||||||
|
return m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
|
||||||
|
|
||||||
|
const uint32_t fb_width = m_framebuffer->width();
|
||||||
|
|
||||||
|
const auto& font = g_terminal_driver->font();
|
||||||
|
|
||||||
|
const uint32_t x = first_pixel % fb_width;
|
||||||
|
const uint32_t y = first_pixel / fb_width;
|
||||||
|
|
||||||
|
const uint32_t load_w = 16 * font.width();
|
||||||
|
const uint32_t load_h = Processor::count() * font.height();
|
||||||
|
|
||||||
|
if (y >= load_h || x + pixel_count <= fb_width - load_w)
|
||||||
|
return m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
|
||||||
|
|
||||||
|
if (x >= fb_width - load_w && x + pixel_count <= fb_width)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (x < fb_width - load_w)
|
||||||
|
m_framebuffer->sync_pixels_linear(first_pixel, fb_width - load_w - x);
|
||||||
|
|
||||||
|
if (x + pixel_count > fb_width)
|
||||||
|
{
|
||||||
|
const uint32_t past_last_pixel = first_pixel + pixel_count;
|
||||||
|
|
||||||
|
first_pixel = (y + 1) * fb_width;
|
||||||
|
pixel_count = past_last_pixel - first_pixel;
|
||||||
|
|
||||||
|
const uint32_t cpu_load_end = load_h * fb_width;
|
||||||
|
|
||||||
|
while (pixel_count && first_pixel < cpu_load_end)
|
||||||
|
{
|
||||||
|
m_framebuffer->sync_pixels_linear(first_pixel, BAN::Math::min(pixel_count, fb_width - load_w));
|
||||||
|
|
||||||
|
const uint32_t advance = BAN::Math::min(pixel_count, fb_width);
|
||||||
|
pixel_count -= advance;
|
||||||
|
first_pixel += advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixel_count)
|
||||||
|
m_framebuffer->sync_pixels_linear(first_pixel, pixel_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BAN::RefPtr<FramebufferDevice> m_framebuffer;
|
BAN::RefPtr<FramebufferDevice> m_framebuffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -179,6 +179,8 @@ namespace Kernel
|
||||||
const pid_t tid = Thread::current_tid();
|
const pid_t tid = Thread::current_tid();
|
||||||
const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0;
|
const pid_t pid = (tid && Thread::current().has_process()) ? Process::current().pid() : 0;
|
||||||
|
|
||||||
|
const char* process_name = "";
|
||||||
|
|
||||||
if (tid)
|
if (tid)
|
||||||
{
|
{
|
||||||
auto& thread = Thread::current();
|
auto& thread = Thread::current();
|
||||||
|
@ -245,15 +247,22 @@ namespace Kernel
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Thread::current().has_process() && Process::current().is_userspace())
|
||||||
|
{
|
||||||
|
const char* const* argv = Process::current().userspace_info().argv;
|
||||||
|
if (argv && *argv)
|
||||||
|
process_name = *argv;
|
||||||
|
}
|
||||||
|
|
||||||
#if ARCH(x86_64)
|
#if ARCH(x86_64)
|
||||||
dwarnln(
|
dwarnln(
|
||||||
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}\r\n"
|
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}: {}\r\n"
|
||||||
"Register dump\r\n"
|
"Register dump\r\n"
|
||||||
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
|
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
|
||||||
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
|
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
|
||||||
"rip=0x{16H}, rflags=0x{16H}\r\n"
|
"rip=0x{16H}, rflags=0x{16H}\r\n"
|
||||||
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
|
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
|
||||||
Processor::current_id(), isr_exceptions[isr], error, pid, tid,
|
Processor::current_id(), isr_exceptions[isr], error, pid, tid, process_name,
|
||||||
regs->rax, regs->rbx, regs->rcx, regs->rdx,
|
regs->rax, regs->rbx, regs->rcx, regs->rdx,
|
||||||
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
|
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
|
||||||
interrupt_stack->ip, interrupt_stack->flags,
|
interrupt_stack->ip, interrupt_stack->flags,
|
||||||
|
@ -261,13 +270,13 @@ namespace Kernel
|
||||||
);
|
);
|
||||||
#elif ARCH(i686)
|
#elif ARCH(i686)
|
||||||
dwarnln(
|
dwarnln(
|
||||||
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}\r\n"
|
"CPU {}: {} (error code: 0x{8H}), pid {}, tid {}: {}\r\n"
|
||||||
"Register dump\r\n"
|
"Register dump\r\n"
|
||||||
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n"
|
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n"
|
||||||
"esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n"
|
"esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n"
|
||||||
"eip=0x{8H}, eflags=0x{8H}\r\n"
|
"eip=0x{8H}, eflags=0x{8H}\r\n"
|
||||||
"cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}",
|
"cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}",
|
||||||
Processor::current_id(), isr_exceptions[isr], error, pid, tid,
|
Processor::current_id(), isr_exceptions[isr], error, pid, tid, process_name,
|
||||||
regs->eax, regs->ebx, regs->ecx, regs->edx,
|
regs->eax, regs->ebx, regs->ecx, regs->edx,
|
||||||
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
|
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
|
||||||
interrupt_stack->ip, interrupt_stack->flags,
|
interrupt_stack->ip, interrupt_stack->flags,
|
||||||
|
|
|
@ -1682,12 +1682,9 @@ namespace Kernel
|
||||||
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)
|
if (flags != MS_SYNC && flags != MS_ASYNC && flags != MS_INVALIDATE)
|
||||||
return BAN::Error::from_errno(EINVAL);
|
return BAN::Error::from_errno(EINVAL);
|
||||||
|
|
||||||
vaddr_t vaddr = (vaddr_t)addr;
|
|
||||||
if (vaddr % PAGE_SIZE != 0)
|
|
||||||
return BAN::Error::from_errno(EINVAL);
|
|
||||||
|
|
||||||
LockGuard _(m_process_lock);
|
LockGuard _(m_process_lock);
|
||||||
|
|
||||||
|
const vaddr_t vaddr = reinterpret_cast<vaddr_t>(addr);
|
||||||
for (auto& mapped_region : m_mapped_regions)
|
for (auto& mapped_region : m_mapped_regions)
|
||||||
if (mapped_region->overlaps(vaddr, len))
|
if (mapped_region->overlaps(vaddr, len))
|
||||||
TRY(mapped_region->msync(vaddr, len, flags));
|
TRY(mapped_region->msync(vaddr, len, flags));
|
||||||
|
|
|
@ -80,3 +80,32 @@ struct Circle
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
uint32_t start { 0 };
|
||||||
|
uint32_t count { 0 };
|
||||||
|
|
||||||
|
bool is_continuous_with(const Range& range) const
|
||||||
|
{
|
||||||
|
return start <= range.start + range.count && range.start <= start + count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t distance_between(const Range& range) const
|
||||||
|
{
|
||||||
|
if (is_continuous_with(range))
|
||||||
|
return 0;
|
||||||
|
if (start < range.start)
|
||||||
|
return range.start - (start + count);
|
||||||
|
return start - (range.start + range.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge_with(const Range& range)
|
||||||
|
{
|
||||||
|
const uint32_t new_start = BAN::Math::min(start, range.start);
|
||||||
|
const uint32_t new_end = BAN::Math::max(start + count, range.start + range.count);
|
||||||
|
|
||||||
|
start = new_start;
|
||||||
|
count = new_end - new_start;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -20,7 +20,12 @@ WindowServer::WindowServer(Framebuffer& framebuffer, int32_t corner_radius)
|
||||||
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
, m_cursor({ framebuffer.width / 2, framebuffer.height / 2 })
|
||||||
, m_font(MUST(LibFont::Font::load("/usr/share/fonts/lat0-16.psfu"_sv)))
|
, 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));
|
BAN::Vector<LibImage::Image::Color> bitmap;
|
||||||
|
MUST(bitmap.resize(m_framebuffer.width * m_framebuffer.height, { 0x10, 0x10, 0x10, 0xFF }));
|
||||||
|
m_background_image = MUST(BAN::UniqPtr<LibImage::Image>::create(m_framebuffer.width, m_framebuffer.height, BAN::move(bitmap)));
|
||||||
|
|
||||||
|
MUST(m_pending_syncs.resize(m_framebuffer.height));
|
||||||
|
|
||||||
invalidate(m_framebuffer.area());
|
invalidate(m_framebuffer.area());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,6 +540,7 @@ void WindowServer::on_mouse_scroll(LibInput::MouseScrollEvent event)
|
||||||
|
|
||||||
void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
|
void WindowServer::set_focused_window(BAN::RefPtr<Window> window)
|
||||||
{
|
{
|
||||||
|
ASSERT(window->get_attributes().focusable);
|
||||||
if (m_focused_window == window)
|
if (m_focused_window == window)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -574,6 +580,9 @@ static uint32_t alpha_blend(uint32_t color_a, uint32_t color_b)
|
||||||
|
|
||||||
void WindowServer::invalidate(Rectangle area)
|
void WindowServer::invalidate(Rectangle area)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_background_image->width() == (uint64_t)m_framebuffer.width);
|
||||||
|
ASSERT(m_background_image->height() == (uint64_t)m_framebuffer.height);
|
||||||
|
|
||||||
const auto get_cursor_pixel =
|
const auto get_cursor_pixel =
|
||||||
[](int32_t rel_x, int32_t rel_y) -> BAN::Optional<uint32_t>
|
[](int32_t rel_x, int32_t rel_y) -> BAN::Optional<uint32_t>
|
||||||
{
|
{
|
||||||
|
@ -605,11 +614,28 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
return;
|
return;
|
||||||
area = focused_overlap.release_value();
|
area = focused_overlap.release_value();
|
||||||
|
|
||||||
|
const bool should_alpha_blend = m_focused_window->get_attributes().alpha_channel;
|
||||||
|
|
||||||
if (client_area == m_framebuffer.area())
|
if (client_area == m_framebuffer.area())
|
||||||
{
|
{
|
||||||
for (int32_t y = area.y; y < area.y + area.height; y++)
|
if (!should_alpha_blend)
|
||||||
for (int32_t x = area.x; x < area.x + area.width; x++)
|
{
|
||||||
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
|
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||||
|
for (int32_t x = area.x; x < area.x + area.width; x++)
|
||||||
|
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||||
|
{
|
||||||
|
for (int32_t x = area.x; x < area.x + area.width; x++)
|
||||||
|
{
|
||||||
|
const uint32_t src_pixel = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
|
||||||
|
const uint32_t bg_pixel = m_background_image->get_color(x, y).as_argb();
|
||||||
|
m_framebuffer.mmap[y * m_framebuffer.width + x] = alpha_blend(src_pixel, bg_pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
mark_pending_sync(area);
|
mark_pending_sync(area);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -630,7 +656,12 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
{
|
{
|
||||||
const int32_t src_x = BAN::Math::clamp<int32_t>(dst_x * m_focused_window->client_width() / m_framebuffer.width, 0, m_focused_window->client_width());
|
const int32_t src_x = BAN::Math::clamp<int32_t>(dst_x * m_focused_window->client_width() / m_framebuffer.width, 0, m_focused_window->client_width());
|
||||||
const int32_t src_y = BAN::Math::clamp<int32_t>(dst_y * m_focused_window->client_height() / m_framebuffer.height, 0, m_focused_window->client_height());
|
const int32_t src_y = BAN::Math::clamp<int32_t>(dst_y * m_focused_window->client_height() / m_framebuffer.height, 0, m_focused_window->client_height());
|
||||||
m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
|
|
||||||
|
const uint32_t src_pixel = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
|
||||||
|
const uint32_t bg_pixel = m_background_image->get_color(dst_x, dst_y).as_argb();
|
||||||
|
|
||||||
|
uint32_t& dst_pixel = m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x];
|
||||||
|
dst_pixel = should_alpha_blend ? alpha_blend(src_pixel, bg_pixel) : src_pixel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,20 +713,9 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
return;
|
return;
|
||||||
area = fb_overlap.release_value();
|
area = fb_overlap.release_value();
|
||||||
|
|
||||||
if (m_background_image)
|
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||||
{
|
for (int32_t x = area.x; x < area.x + area.width; x++)
|
||||||
ASSERT(m_background_image->width() == (uint64_t)m_framebuffer.width);
|
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_background_image->get_color(x, y).as_argb();
|
||||||
ASSERT(m_background_image->height() == (uint64_t)m_framebuffer.height);
|
|
||||||
for (int32_t y = area.y; y < area.y + area.height; y++)
|
|
||||||
for (int32_t x = area.x; x < area.x + area.width; x++)
|
|
||||||
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_background_image->get_color(x, y).as_argb();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int32_t y = area.y; y < area.y + area.height; y++)
|
|
||||||
for (int32_t x = area.x; x < area.x + area.width; x++)
|
|
||||||
m_framebuffer.mmap[y * m_framebuffer.width + x] = 0xFF101010;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this loop should be inverse order and terminate
|
// FIXME: this loop should be inverse order and terminate
|
||||||
// after window without alpha channel is found
|
// after window without alpha channel is found
|
||||||
|
@ -892,24 +912,71 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
mark_pending_sync(area);
|
mark_pending_sync(area);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowServer::mark_pending_sync(Rectangle area)
|
void WindowServer::RangeList::add_range(const Range& range)
|
||||||
{
|
{
|
||||||
// FIXME: this marks too many pages
|
if (range_count == 0)
|
||||||
|
|
||||||
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;
|
ranges[0] = range;
|
||||||
size_t byte = index / 8;
|
range_count++;
|
||||||
size_t bit = index % 8;
|
return;
|
||||||
//dprintln("{}/{}", byte, m_pages_to_sync_bitmap.size());
|
|
||||||
if (byte < m_pages_to_sync_bitmap.size())
|
|
||||||
m_pages_to_sync_bitmap[byte] |= 1 << bit;
|
|
||||||
mmap_addr += 4096;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t min_distance_value = SIZE_MAX;
|
||||||
|
size_t min_distance_index = 0;
|
||||||
|
for (size_t i = 0; i < range_count; i++)
|
||||||
|
{
|
||||||
|
if (ranges[i].is_continuous_with(range))
|
||||||
|
{
|
||||||
|
ranges[i].merge_with(range);
|
||||||
|
|
||||||
|
size_t last_continuous = i;
|
||||||
|
for (size_t j = i + 1; j < range_count; j++)
|
||||||
|
{
|
||||||
|
if (!ranges[i].is_continuous_with(ranges[j]))
|
||||||
|
break;
|
||||||
|
last_continuous = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_continuous != i)
|
||||||
|
{
|
||||||
|
ranges[i].merge_with(ranges[last_continuous]);
|
||||||
|
for (size_t j = 1; last_continuous + j < range_count; j++)
|
||||||
|
ranges[i + j] = ranges[last_continuous + j];
|
||||||
|
range_count -= last_continuous - i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto distance = ranges[i].distance_between(range);
|
||||||
|
if (distance < min_distance_value)
|
||||||
|
{
|
||||||
|
min_distance_value = distance;
|
||||||
|
min_distance_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range_count >= ranges.size())
|
||||||
|
{
|
||||||
|
ranges[min_distance_index].merge_with(range);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t insert_idx = 0;
|
||||||
|
for (; insert_idx < range_count; insert_idx++)
|
||||||
|
if (range.start < ranges[insert_idx].start)
|
||||||
|
break;
|
||||||
|
for (size_t i = range_count; i > insert_idx; i--)
|
||||||
|
ranges[i] = ranges[i - 1];
|
||||||
|
ranges[insert_idx] = range;
|
||||||
|
range_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::mark_pending_sync(Rectangle to_sync)
|
||||||
|
{
|
||||||
|
ASSERT(to_sync == to_sync.get_overlap(m_framebuffer.area()).value());
|
||||||
|
for (int32_t y_off = 0; y_off < to_sync.height; y_off++)
|
||||||
|
m_pending_syncs[to_sync.y + y_off].add_range({ static_cast<uint32_t>(to_sync.x), static_cast<uint32_t>(to_sync.width) });
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowServer::sync()
|
void WindowServer::sync()
|
||||||
|
@ -933,33 +1000,44 @@ void WindowServer::sync()
|
||||||
dir_y = -dir_y;
|
dir_y = -dir_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < m_pages_to_sync_bitmap.size() * 8; i++)
|
size_t range_start = 0;
|
||||||
|
size_t range_count = 0;
|
||||||
|
for (int32_t y = 0; y < m_framebuffer.height; y++)
|
||||||
{
|
{
|
||||||
size_t byte = i / 8;
|
auto& range_list = m_pending_syncs[y];
|
||||||
size_t bit = i % 8;
|
|
||||||
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t len = 1;
|
for (size_t i = 0; i < range_list.range_count; i++)
|
||||||
while (i + len < m_pages_to_sync_bitmap.size() * 8)
|
|
||||||
{
|
{
|
||||||
size_t byte = (i + len) / 8;
|
const size_t cur_start = y * m_framebuffer.width + range_list.ranges[i].start;
|
||||||
size_t bit = (i + len) % 8;
|
const size_t cur_count = range_list.ranges[i].count;
|
||||||
if (!(m_pages_to_sync_bitmap[byte] & (1 << bit)))
|
|
||||||
break;
|
if (range_count == 0)
|
||||||
len++;
|
{
|
||||||
|
range_start = cur_start;
|
||||||
|
range_count = cur_count;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const size_t distance = cur_start - (range_start + range_count);
|
||||||
|
|
||||||
|
// combine nearby ranges to reduce msync calls
|
||||||
|
// NOTE: value of 128 is an arbitary constant that *just* felt nice
|
||||||
|
if (distance <= 128)
|
||||||
|
range_count = (cur_start + cur_count) - range_start;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
msync(m_framebuffer.mmap + range_start, range_count * 4, MS_SYNC);
|
||||||
|
range_start = cur_start;
|
||||||
|
range_count = cur_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msync(
|
range_list.range_count = 0;
|
||||||
reinterpret_cast<uint8_t*>(m_framebuffer.mmap) + i * 4096,
|
|
||||||
len * 4096,
|
|
||||||
MS_SYNC
|
|
||||||
);
|
|
||||||
|
|
||||||
i += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(m_pages_to_sync_bitmap.data(), 0, m_pages_to_sync_bitmap.size());
|
if (range_count)
|
||||||
|
msync(m_framebuffer.mmap + range_start, range_count * 4, MS_SYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle WindowServer::cursor_area() const
|
Rectangle WindowServer::cursor_area() const
|
||||||
|
@ -1002,8 +1080,14 @@ void WindowServer::remove_client_fd(int fd)
|
||||||
if (window == m_focused_window)
|
if (window == m_focused_window)
|
||||||
{
|
{
|
||||||
m_focused_window = nullptr;
|
m_focused_window = nullptr;
|
||||||
if (!m_client_windows.empty())
|
for (size_t j = m_client_windows.size(); j > 0; j--)
|
||||||
set_focused_window(m_client_windows.back());
|
{
|
||||||
|
auto& client_window = m_client_windows[j - 1];
|
||||||
|
if (!client_window->get_attributes().focusable)
|
||||||
|
continue;
|
||||||
|
set_focused_window(client_window);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "Framebuffer.h"
|
#include "Framebuffer.h"
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
|
|
||||||
|
#include <BAN/Array.h>
|
||||||
#include <BAN/Function.h>
|
#include <BAN/Function.h>
|
||||||
#include <BAN/Iteration.h>
|
#include <BAN/Iteration.h>
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
@ -59,6 +60,14 @@ public:
|
||||||
private:
|
private:
|
||||||
void mark_pending_sync(Rectangle area);
|
void mark_pending_sync(Rectangle area);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct RangeList
|
||||||
|
{
|
||||||
|
size_t range_count { 0 };
|
||||||
|
BAN::Array<Range, 32> ranges;
|
||||||
|
void add_range(const Range& range);
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Framebuffer& m_framebuffer;
|
Framebuffer& m_framebuffer;
|
||||||
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||||
|
@ -67,7 +76,7 @@ private:
|
||||||
|
|
||||||
const int32_t m_corner_radius;
|
const int32_t m_corner_radius;
|
||||||
|
|
||||||
BAN::Vector<uint8_t> m_pages_to_sync_bitmap;
|
BAN::Vector<RangeList> m_pending_syncs;
|
||||||
|
|
||||||
BAN::UniqPtr<LibImage::Image> m_background_image;
|
BAN::UniqPtr<LibImage::Image> m_background_image;
|
||||||
|
|
||||||
|
|
|
@ -198,19 +198,23 @@ 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());
|
||||||
|
|
||||||
|
const auto get_current_us =
|
||||||
|
[]() -> uint64_t
|
||||||
|
{
|
||||||
|
timespec current_ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, ¤t_ts);
|
||||||
|
return (current_ts.tv_sec * 1'000'000) + (current_ts.tv_nsec / 1'000);
|
||||||
|
};
|
||||||
|
|
||||||
constexpr uint64_t sync_interval_us = 1'000'000 / 60;
|
constexpr uint64_t sync_interval_us = 1'000'000 / 60;
|
||||||
timespec last_sync { .tv_sec = 0, .tv_nsec = 0 };
|
uint64_t last_sync_us = 0;
|
||||||
while (!window_server.is_stopped())
|
while (!window_server.is_stopped())
|
||||||
{
|
{
|
||||||
timespec current_ts;
|
const auto current_us = get_current_us();
|
||||||
clock_gettime(CLOCK_MONOTONIC, ¤t_ts);
|
if (current_us - last_sync_us > sync_interval_us)
|
||||||
|
|
||||||
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();
|
window_server.sync();
|
||||||
us_since_last_sync = 0;
|
last_sync_us += sync_interval_us;
|
||||||
last_sync = current_ts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_fd = server_fd;
|
int max_fd = server_fd;
|
||||||
|
@ -230,10 +234,10 @@ 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));
|
||||||
|
|
||||||
timeval select_timeout {
|
timeval select_timeout {};
|
||||||
.tv_sec = 0,
|
if (auto current_us = get_current_us(); current_us - last_sync_us < sync_interval_us)
|
||||||
.tv_usec = static_cast<long>(sync_interval_us - us_since_last_sync)
|
select_timeout.tv_usec = sync_interval_us - (current_us - last_sync_us);
|
||||||
};
|
|
||||||
int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout);
|
int nselect = select(max_fd + 1, &fds, nullptr, nullptr, &select_timeout);
|
||||||
if (nselect == 0)
|
if (nselect == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in New Issue