diff --git a/kernel/include/kernel/Device/FramebufferDevice.h b/kernel/include/kernel/Device/FramebufferDevice.h index d3bdf46e..0583450c 100644 --- a/kernel/include/kernel/Device/FramebufferDevice.h +++ b/kernel/include/kernel/Device/FramebufferDevice.h @@ -17,6 +17,10 @@ namespace Kernel void set_pixel(uint32_t x, uint32_t y, uint32_t rgb); + // positive rows -> empty pixels on bottom + // negative rows -> empty pixels on top + void scroll(int32_t rows, uint32_t rgb); + void sync_pixels_full(); void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count); void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height); diff --git a/kernel/include/kernel/Terminal/FramebufferTerminal.h b/kernel/include/kernel/Terminal/FramebufferTerminal.h index 299912d3..582fafa8 100644 --- a/kernel/include/kernel/Terminal/FramebufferTerminal.h +++ b/kernel/include/kernel/Terminal/FramebufferTerminal.h @@ -15,6 +15,7 @@ namespace Kernel virtual uint32_t height() const override { return m_framebuffer_device->height() / font().height(); } virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) override; + virtual bool scroll(Color) override; virtual void clear(Color) override; virtual void set_cursor_position(uint32_t, uint32_t) override; diff --git a/kernel/include/kernel/Terminal/TerminalDriver.h b/kernel/include/kernel/Terminal/TerminalDriver.h index f66609f6..a009f662 100644 --- a/kernel/include/kernel/Terminal/TerminalDriver.h +++ b/kernel/include/kernel/Terminal/TerminalDriver.h @@ -31,6 +31,7 @@ namespace Kernel virtual uint32_t height() const = 0; virtual void putchar_at(uint16_t, uint32_t, uint32_t, Color, Color) = 0; + virtual bool scroll(Color) { return false; } virtual void clear(Color) = 0; virtual void set_cursor_position(uint32_t, uint32_t) = 0; diff --git a/kernel/kernel/Device/FramebufferDevice.cpp b/kernel/kernel/Device/FramebufferDevice.cpp index 831d7365..b44a7fe1 100644 --- a/kernel/kernel/Device/FramebufferDevice.cpp +++ b/kernel/kernel/Device/FramebufferDevice.cpp @@ -135,6 +135,25 @@ namespace Kernel video_buffer_u8[(y * m_width + x) * (BANAN_FB_BPP / 8) + 3] = rgb >> 24; } + void FramebufferDevice::scroll(int32_t rows, uint32_t rgb) + { + if (rows == 0) + return; + rows = BAN::Math::clamp(rows, -m_height, m_height); + const uint32_t abs_rows = BAN::Math::abs(rows); + + auto* video_buffer_u8 = reinterpret_cast(m_video_buffer->vaddr()); + uint8_t* src = (rows < 0) ? video_buffer_u8 : &video_buffer_u8[(abs_rows * m_width) * (BANAN_FB_BPP / 8)]; + uint8_t* dst = (rows > 0) ? video_buffer_u8 : &video_buffer_u8[(abs_rows * m_width) * (BANAN_FB_BPP / 8)]; + memmove(dst, src, (m_height - abs_rows) * m_width * (BANAN_FB_BPP / 8)); + + uint32_t start_y = (rows < 0) ? 0 : m_height - abs_rows; + uint32_t stop_y = (rows < 0) ? abs_rows : m_height; + for (uint32_t y = start_y; y < stop_y; y++) + for (uint32_t x = 0; x < m_width; x++) + set_pixel(x, y, rgb); + } + void FramebufferDevice::sync_pixels_full() { auto* video_memory_u8 = reinterpret_cast(m_video_memory_vaddr); diff --git a/kernel/kernel/Terminal/FramebufferTerminal.cpp b/kernel/kernel/Terminal/FramebufferTerminal.cpp index db10f46f..fe1d4b47 100644 --- a/kernel/kernel/Terminal/FramebufferTerminal.cpp +++ b/kernel/kernel/Terminal/FramebufferTerminal.cpp @@ -33,6 +33,13 @@ namespace Kernel m_framebuffer_device->sync_pixels_rectangle(x, y, font().width(), font().height()); } + bool FramebufferTerminalDriver::scroll(Color color) + { + m_framebuffer_device->scroll(font().height(), color.rgb); + m_framebuffer_device->sync_pixels_full(); + return true; + } + void FramebufferTerminalDriver::clear(Color color) { for (uint32_t y = 0; y < m_framebuffer_device->height(); y++) diff --git a/kernel/kernel/Terminal/VirtualTTY.cpp b/kernel/kernel/Terminal/VirtualTTY.cpp index b4a49870..384f4d16 100644 --- a/kernel/kernel/Terminal/VirtualTTY.cpp +++ b/kernel/kernel/Terminal/VirtualTTY.cpp @@ -99,8 +99,8 @@ namespace Kernel render_from_buffer(last_x, last_y); if (m_show_cursor) m_terminal_driver->set_cursor_position(x, y); - last_x = m_column = x; - last_y = m_row = y; + last_x = x; + last_y = y; } void VirtualTTY::reset_ansi() @@ -410,10 +410,18 @@ namespace Kernel for (uint32_t x = 0; x < m_width; x++) m_buffer[(m_height - 1) * m_width + x] = { .foreground = m_foreground, .background = m_background, .codepoint = ' ' }; - // Render the whole buffer to the screen - for (uint32_t y = 0; y < m_height; y++) - for (uint32_t x = 0; x < m_width; x++) - render_from_buffer(x, y); + // hide cursor during scrolling + bool old_show_cursor = m_show_cursor; + m_show_cursor = false; + set_cursor_position(0, 0); + if (!m_terminal_driver->scroll(m_background)) + { + // No fast scrolling, render the whole buffer to the screen + for (uint32_t y = 0; y < m_height; y++) + for (uint32_t x = 0; x < m_width; x++) + render_from_buffer(x, y); + } + m_show_cursor = old_show_cursor; m_column = 0; m_row--;