diff --git a/Kernel/Graphics/BochsGraphicsAdapter.cpp b/Kernel/Graphics/BochsGraphicsAdapter.cpp index b6695216e8..534a665765 100644 --- a/Kernel/Graphics/BochsGraphicsAdapter.cpp +++ b/Kernel/Graphics/BochsGraphicsAdapter.cpp @@ -53,11 +53,11 @@ UNMAP_AFTER_INIT BochsGraphicsAdapter::BochsGraphicsAdapter(PCI::Address pci_add : PCI::DeviceController(pci_address) , m_mmio_registers(PCI::get_BAR2(pci_address) & 0xfffffff0) { - set_safe_resolution(); // We assume safe resolutio is 1024x768x32 m_framebuffer_console = Graphics::FramebufferConsole::initialize(PhysicalAddress(PCI::get_BAR0(pci_address) & 0xfffffff0), 1024, 768, 1024 * sizeof(u32)); // FIXME: This is a very wrong way to do this... GraphicsManagement::the().m_console = m_framebuffer_console; + set_safe_resolution(); } UNMAP_AFTER_INIT void BochsGraphicsAdapter::initialize_framebuffer_devices() @@ -76,6 +76,7 @@ GraphicsDevice::Type BochsGraphicsAdapter::type() const void BochsGraphicsAdapter::set_safe_resolution() { + VERIFY(m_framebuffer_console); set_resolution(1024, 768); } @@ -105,6 +106,7 @@ bool BochsGraphicsAdapter::try_to_set_resolution(size_t width, size_t height) bool BochsGraphicsAdapter::set_resolution(size_t width, size_t height) { + VERIFY(m_framebuffer_console); if (Checked::multiplication_would_overflow(width, height, sizeof(u32))) return false; @@ -112,6 +114,7 @@ bool BochsGraphicsAdapter::set_resolution(size_t width, size_t height) return false; dbgln("BochsGraphicsAdapter: resolution set to {}x{}", width, height); + m_framebuffer_console->set_resolution(width, height, width * sizeof(u32)); return true; } diff --git a/Kernel/Graphics/Console/Console.h b/Kernel/Graphics/Console/Console.h index c391dc32fb..448f1c7df6 100644 --- a/Kernel/Graphics/Console/Console.h +++ b/Kernel/Graphics/Console/Console.h @@ -74,8 +74,8 @@ protected: Atomic m_enabled; Color m_default_foreground_color { Color::White }; Color m_default_background_color { Color::Black }; - const size_t m_width; - const size_t m_height; + size_t m_width; + size_t m_height; mutable size_t m_x { 0 }; mutable size_t m_y { 0 }; }; diff --git a/Kernel/Graphics/Console/FramebufferConsole.cpp b/Kernel/Graphics/Console/FramebufferConsole.cpp index 8ae2e3122e..5c960913c9 100644 --- a/Kernel/Graphics/Console/FramebufferConsole.cpp +++ b/Kernel/Graphics/Console/FramebufferConsole.cpp @@ -5,6 +5,7 @@ */ #include +#include namespace Kernel::Graphics { @@ -204,17 +205,28 @@ NonnullRefPtr FramebufferConsole::initialize(PhysicalAddress return adopt_ref(*new FramebufferConsole(framebuffer_address, width, height, pitch)); } -FramebufferConsole::FramebufferConsole(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch) - : Console(width, height) - , m_framebuffer_address(framebuffer_address) - , m_pitch(pitch) +void FramebufferConsole::set_resolution(size_t width, size_t height, size_t pitch) { + m_width = width; + m_height = height; + m_pitch = pitch; + dbgln("Framebuffer Console: taking {} bytes", page_round_up(pitch * height)); m_framebuffer_region = MM.allocate_kernel_region(m_framebuffer_address, page_round_up(pitch * height), "Framebuffer Console", Region::Access::Read | Region::Access::Write, Region::Cacheable::Yes); VERIFY(m_framebuffer_region); // Just to start cleanly, we clean the entire framebuffer memset(m_framebuffer_region->vaddr().as_ptr(), 0, pitch * height); + + ConsoleManagement::the().resolution_was_changed(); +} + +FramebufferConsole::FramebufferConsole(PhysicalAddress framebuffer_address, size_t width, size_t height, size_t pitch) + : Console(width, height) + , m_framebuffer_address(framebuffer_address) + , m_pitch(pitch) +{ + set_resolution(width, height, pitch); } size_t FramebufferConsole::bytes_per_base_glyph() const diff --git a/Kernel/Graphics/Console/FramebufferConsole.h b/Kernel/Graphics/Console/FramebufferConsole.h index 48574768b7..7e141cef9a 100644 --- a/Kernel/Graphics/Console/FramebufferConsole.h +++ b/Kernel/Graphics/Console/FramebufferConsole.h @@ -16,6 +16,8 @@ class FramebufferConsole final : public Console { public: static NonnullRefPtr initialize(PhysicalAddress, size_t width, size_t height, size_t pitch); + void set_resolution(size_t width, size_t height, size_t pitch); + virtual size_t bytes_per_base_glyph() const override; virtual size_t chars_per_line() const override; diff --git a/Kernel/Graphics/FramebufferDevice.cpp b/Kernel/Graphics/FramebufferDevice.cpp index aebc9f5b49..1daf3f287e 100644 --- a/Kernel/Graphics/FramebufferDevice.cpp +++ b/Kernel/Graphics/FramebufferDevice.cpp @@ -30,16 +30,16 @@ KResultOr FramebufferDevice::mmap(Process& process, FileDescription&, c if (range.size() != page_round_up(framebuffer_size_in_bytes())) return EOVERFLOW; - // FIXME: We rely on the fact that only the WindowServer will mmap the framebuffer - // and only once when starting to work with it. If other program wants to do so, we need to fix this. - VERIFY(!m_userspace_framebuffer_region); - VERIFY(!m_userspace_real_framebuffer_vmobject); - auto vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, page_round_up(framebuffer_size_in_bytes())); if (!vmobject) return ENOMEM; m_userspace_real_framebuffer_vmobject = vmobject; + m_real_framebuffer_vmobject = AnonymousVMObject::create_for_physical_range(m_framebuffer_address, page_round_up(framebuffer_size_in_bytes())); + m_swapped_framebuffer_vmobject = AnonymousVMObject::create_with_size(page_round_up(framebuffer_size_in_bytes()), AllocationStrategy::AllocateNow); + m_real_framebuffer_region = MM.allocate_kernel_region_with_vmobject(*m_real_framebuffer_vmobject, page_round_up(framebuffer_size_in_bytes()), "Framebuffer", Region::Access::Read | Region::Access::Write); + m_swapped_framebuffer_region = MM.allocate_kernel_region_with_vmobject(*m_swapped_framebuffer_vmobject, page_round_up(framebuffer_size_in_bytes()), "Framebuffer Swap (Blank)", Region::Access::Read | Region::Access::Write); + auto result = process.space().allocate_region_with_vmobject( range, vmobject.release_nonnull(), diff --git a/Kernel/TTY/ConsoleManagement.cpp b/Kernel/TTY/ConsoleManagement.cpp index ea1d2c0de0..b06278b9d8 100644 --- a/Kernel/TTY/ConsoleManagement.cpp +++ b/Kernel/TTY/ConsoleManagement.cpp @@ -15,6 +15,13 @@ namespace Kernel { static AK::Singleton s_the; +void ConsoleManagement::resolution_was_changed() +{ + for (auto& console : m_consoles) { + console.refresh_after_resolution_change(); + } +} + bool ConsoleManagement::is_initialized() { if (!s_the.is_initialized()) diff --git a/Kernel/TTY/ConsoleManagement.h b/Kernel/TTY/ConsoleManagement.h index eb05156a37..7e466eb23d 100644 --- a/Kernel/TTY/ConsoleManagement.h +++ b/Kernel/TTY/ConsoleManagement.h @@ -26,6 +26,8 @@ public: void switch_to(unsigned); void initialize(); + void resolution_was_changed(); + void switch_to_debug() { switch_to(1); } NonnullRefPtr first_tty() const { return m_consoles[0]; } diff --git a/Kernel/TTY/VirtualConsole.cpp b/Kernel/TTY/VirtualConsole.cpp index e664544b4c..90edbc93a4 100644 --- a/Kernel/TTY/VirtualConsole.cpp +++ b/Kernel/TTY/VirtualConsole.cpp @@ -134,12 +134,54 @@ UNMAP_AFTER_INIT void VirtualConsole::initialize() // Add the lines, so we also ensure they will be flushed now for (size_t row = 0; row < rows(); row++) { - m_lines.append({ true }); + m_lines.append({ true, 0 }); } clear(); VERIFY(m_cells); } +void VirtualConsole::refresh_after_resolution_change() +{ + auto old_rows_count = rows(); + auto old_columns_count = columns(); + set_size(GraphicsManagement::the().console()->max_column(), GraphicsManagement::the().console()->max_row()); + m_console_impl.set_size(GraphicsManagement::the().console()->max_column(), GraphicsManagement::the().console()->max_row()); + + // Note: From now on, columns() and rows() are updated with the new settings. + + auto size = GraphicsManagement::the().console()->max_column() * GraphicsManagement::the().console()->max_row() * sizeof(Cell) * 2; + auto new_cells = MM.allocate_kernel_region(page_round_up(size), "Virtual Console Cells", Region::Access::Read | Region::Access::Write, AllocationStrategy::AllocateNow); + + if (rows() < old_rows_count) { + m_lines.shrink(rows()); + } else { + for (size_t row = 0; row < (size_t)(rows() - old_rows_count); row++) { + m_lines.append({ true, 0 }); + } + } + + // Note: A potential loss of displayed data occur when resolution width shrinks. + if (columns() < old_columns_count) { + for (size_t row = 0; row < rows(); row++) { + auto& line = m_lines[row]; + memcpy(new_cells->vaddr().offset((row)*columns() * sizeof(Cell)).as_ptr(), m_cells->vaddr().offset((row) * (old_columns_count) * sizeof(Cell)).as_ptr(), columns() * sizeof(Cell)); + line.dirty = true; + } + } else { + // Handle Growth of resolution + for (size_t row = 0; row < rows(); row++) { + auto& line = m_lines[row]; + memcpy(new_cells->vaddr().offset((row)*columns() * sizeof(Cell)).as_ptr(), m_cells->vaddr().offset((row) * (old_columns_count) * sizeof(Cell)).as_ptr(), old_columns_count * sizeof(Cell)); + line.dirty = true; + } + } + + // Update the new cells Region + m_cells = move(new_cells); + m_console_impl.m_need_full_flush = true; + flush_dirty_lines(); +} + UNMAP_AFTER_INIT VirtualConsole::VirtualConsole(const unsigned index) : TTY(4, index) , m_index(index) @@ -409,6 +451,10 @@ void VirtualConsole::put_character_at(unsigned row, unsigned column, u32 code_po cell.ch = code_point; cell.attribute.flags |= VT::Attribute::Flags::Touched; line.dirty = true; + // FIXME: Maybe we should consider to change length after printing a special char in a column + if (code_point <= 20) + return; + line.length = max(line.length, column); } void VirtualConsole::invalidate_cursor(size_t row) diff --git a/Kernel/TTY/VirtualConsole.h b/Kernel/TTY/VirtualConsole.h index be1db45329..d0c1c7175b 100644 --- a/Kernel/TTY/VirtualConsole.h +++ b/Kernel/TTY/VirtualConsole.h @@ -60,6 +60,7 @@ class VirtualConsole final : public TTY public: struct Line { bool dirty; + size_t length; }; struct Cell { @@ -80,6 +81,8 @@ public: size_t index() const { return m_index; } + void refresh_after_resolution_change(); + bool is_graphical() { return m_graphical; } void set_graphical(bool graphical);