Kernel: VESA driver has now second buffer for fast scrolling

This allows us to not read from video memory, since it was very slow

I also implemented fast path for graphics clearing and scrolling if bpp is 32
This commit is contained in:
Bananymous 2022-12-20 14:01:04 +02:00
parent 5e2680cade
commit 3f7a61a4d2
6 changed files with 155 additions and 65 deletions

View File

@ -1,9 +1,13 @@
#include <kernel/kmalloc.h>
#include <kernel/multiboot.h> #include <kernel/multiboot.h>
#include <kernel/panic.h>
#include <kernel/Serial.h> #include <kernel/Serial.h>
#include <kernel/VESA.h> #include <kernel/VESA.h>
#include "font.h" #include "font.h"
#include <string.h>
#define MULTIBOOT_FLAGS_FRAMEBUFFER (1 << 12) #define MULTIBOOT_FLAGS_FRAMEBUFFER (1 << 12)
#define MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS 1 #define MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_TEXT 2 #define MULTIBOOT_FRAMEBUFFER_TYPE_TEXT 2
@ -14,6 +18,7 @@ extern const struct bitmap_font font;
namespace VESA namespace VESA
{ {
static void* s_buffer = nullptr;
static void* s_addr = nullptr; static void* s_addr = nullptr;
static uint8_t s_bpp = 0; static uint8_t s_bpp = 0;
static uint32_t s_pitch = 0; static uint32_t s_pitch = 0;
@ -23,11 +28,11 @@ namespace VESA
static void GraphicsPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg); static void GraphicsPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg);
static void GraphicsClear(Color color); static void GraphicsClear(Color color);
static void GraphicsScrollLine(uint32_t line); static void GraphicsScroll();
static void TextPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg); static void TextPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg);
static void TextClear(Color color); static void TextClear(Color color);
static void TextScrollLine(uint32_t line); static void TextScroll();
void PutEntryAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg) void PutEntryAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
{ {
@ -49,14 +54,12 @@ namespace VESA
return TextClear(color); return TextClear(color);
} }
void ScrollLine(uint32_t line) void Scroll()
{ {
if (line == 0 || line >= s_height)
return;
if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS) if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS)
return GraphicsScrollLine(line); return GraphicsScroll();
if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT) if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_TEXT)
return TextScrollLine(line); return TextScroll();
} }
uint32_t GetTerminalWidth() uint32_t GetTerminalWidth()
@ -77,7 +80,7 @@ namespace VESA
return 0; return 0;
} }
bool Initialize() bool PreInitialize()
{ {
if (!(s_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER)) if (!(s_multiboot_info->flags & MULTIBOOT_FLAGS_FRAMEBUFFER))
return false; return false;
@ -114,6 +117,18 @@ namespace VESA
return false; return false;
} }
void Initialize()
{
if (s_mode == MULTIBOOT_FRAMEBUFFER_TYPE_GRAPHICS)
{
s_buffer = kmalloc_eternal(s_height * s_pitch);
if (s_buffer == nullptr)
kprintln("Could not allocate a buffer for VESA");
else
memcpy(s_buffer, s_addr, s_height * s_pitch);
}
}
@ -138,29 +153,37 @@ namespace VESA
0x00'FF'FF'FF, 0x00'FF'FF'FF,
}; };
static void GraphicsSetPixel(uint32_t* address, uint32_t color) static void GraphicsSetPixel(uint32_t offset, uint32_t color)
{ {
switch (s_bpp) uint32_t* address = (uint32_t*)((uint32_t)s_addr + offset);
{
case 24:
*address = (*address & 0xFF000000) | (color & 0x00FFFFFF);
break;
case 32:
*address = color;
break;
}
}
static uint32_t GraphicsGetPixel(uint32_t* address) if (s_buffer)
{
switch (s_bpp)
{ {
case 24: uint32_t* buffer = (uint32_t*)((uint32_t)s_buffer + offset);
return *address & 0x00FFFFFF; switch (s_bpp)
case 32: {
return *address; case 24:
*buffer = (*buffer & 0xFF000000) | (color & 0x00FFFFFF);
*address = *buffer;
break;
case 32:
*buffer = color;
*address = color;
break;
}
}
else
{
switch (s_bpp)
{
case 24:
*address = (*address & 0xFF000000) | (color & 0x00FFFFFF);
break;
case 32:
*address = color;
break;
}
} }
return 0;
} }
static void GraphicsPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg) static void GraphicsPutCharAt(uint16_t ch, uint32_t x, uint32_t y, Color fg, Color bg)
@ -184,58 +207,90 @@ namespace VESA
uint32_t fx = x * font.Width; uint32_t fx = x * font.Width;
uint32_t fy = y * font.Height; uint32_t fy = y * font.Height;
uint32_t row_addr = (uint32_t)s_addr + (fy * s_pitch) + (fx * (s_bpp / 8)); uint32_t row_offset = (fy * s_pitch) + (fx * (s_bpp / 8));
for (uint32_t gy = 0; gy < font.Height; gy++) for (uint32_t gy = 0; gy < font.Height; gy++)
{ {
if (fy + gy >= s_height) break; if (fy + gy >= s_height) break;
uint32_t pixel_addr = row_addr; uint32_t pixel_offset = row_offset;
for (uint32_t gx = 0; gx < font.Width; gx++) for (uint32_t gx = 0; gx < font.Width; gx++)
{ {
if (fx + gx >= s_width) break; if (fx + gx >= s_width) break;
GraphicsSetPixel((uint32_t*)pixel_addr, (glyph[gy] & (1 << (font.Width - gx - 1))) ? u32_fg : u32_bg); GraphicsSetPixel(pixel_offset, (glyph[gy] & (1 << (font.Width - gx - 1))) ? u32_fg : u32_bg);
pixel_addr += s_bpp / 8; pixel_offset += s_bpp / 8;
} }
row_addr += s_pitch; row_offset += s_pitch;
} }
} }
static void GraphicsClear(Color color) static void GraphicsClear(Color color)
{ {
uint32_t u32_color = s_graphics_colors[(uint8_t)color]; uint32_t u32_color = s_graphics_colors[(uint8_t)color];
uint32_t row_addr = (uint32_t)s_addr;
if (s_bpp == 32)
{
uint32_t bytes_per_row = s_pitch / (s_bpp / 8);
for (uint32_t y = 0; y < s_height; y++)
for (uint32_t x = 0; x < s_width; x++)
((uint32_t*)s_addr)[y * bytes_per_row + x] = u32_color;
if (s_buffer)
for (uint32_t y = 0; y < s_height; y++)
for (uint32_t x = 0; x < s_width; x++)
((uint32_t*)s_buffer)[y * bytes_per_row + x] = u32_color;
return;
}
uint32_t row_offset = 0;
for (uint32_t y = 0; y < s_height; y++) for (uint32_t y = 0; y < s_height; y++)
{ {
uint32_t pixel_addr = row_addr; uint32_t pixel_offset = row_offset;
for (uint32_t x = 0; x < s_width; x++) for (uint32_t x = 0; x < s_width; x++)
{ {
GraphicsSetPixel((uint32_t*)pixel_addr, u32_color); GraphicsSetPixel(pixel_offset, u32_color);
pixel_addr += s_bpp / 8; pixel_offset += s_bpp / 8;
} }
row_addr += s_pitch; row_offset += s_pitch;
} }
} }
static void GraphicsScrollLine(uint32_t line) static void GraphicsScroll()
{ {
if (line >= s_height / font.Height) if (s_bpp == 32)
return;
uint32_t row_out = (uint32_t)s_addr + (line - 1) * font.Height * s_pitch;
uint32_t row_in = (uint32_t)s_addr + (line - 0) * font.Height * s_pitch;
for (uint32_t y = 0; y < font.Height; y++)
{ {
uint32_t pixel_out = row_out; uint32_t bytes_per_row = s_pitch / (s_bpp / 8);
uint32_t pixel_in = row_in; for (uint32_t y = 0; y < s_height - font.Height; y++)
for (uint32_t x = 0; x < s_width; x++)
{ {
GraphicsSetPixel((uint32_t*)pixel_out, GraphicsGetPixel((uint32_t*)pixel_in)); for (uint32_t x = 0; x < s_width; x++)
pixel_out += s_bpp / 8; {
pixel_in += s_bpp / 8; if (s_buffer)
{
((uint32_t*)s_buffer)[y * bytes_per_row + x] = ((uint32_t*)s_buffer)[(y + font.Height) * bytes_per_row + x];
((uint32_t*)s_addr )[y * bytes_per_row + x] = ((uint32_t*)s_buffer)[(y + font.Height) * bytes_per_row + x];
}
else
{
((uint32_t*)s_addr )[y * bytes_per_row + x] = ((uint32_t*)s_addr )[(y + font.Height) * bytes_per_row + x];
}
}
} }
row_out += s_pitch; return;
row_in += s_pitch; }
uint32_t row_offset_out = 0;
uint32_t row_offset_in = font.Height * s_pitch;
for (uint32_t y = 0; y < s_height - 1; y++)
{
if (s_buffer)
{
memcpy((void*)((uint32_t)s_buffer + row_offset_out), (void*)((uint32_t)s_buffer + row_offset_in), s_width * s_bpp);
memcpy((void*)((uint32_t)s_addr + row_offset_out), (void*)((uint32_t)s_buffer + row_offset_in), s_width * s_bpp);
}
else
{
memcpy((void*)((uint32_t)s_addr + row_offset_out), (void*)((uint32_t)s_addr + row_offset_in), s_width * s_bpp);
}
row_offset_out += s_pitch;
row_offset_in += s_pitch;
} }
} }
@ -266,13 +321,16 @@ namespace VESA
TextPutCharAt(' ', x, y, Color::BRIGHT_WHITE, color); TextPutCharAt(' ', x, y, Color::BRIGHT_WHITE, color);
} }
static void TextScrollLine(uint32_t line) static void TextScroll()
{ {
for (uint32_t x = 0; x < s_width; x++) for (uint32_t y = 1; y < s_height; y++)
{ {
uint32_t index1 = (line - 0) * s_width + x; for (uint32_t x = 0; x < s_width; x++)
uint32_t index2 = (line - 1) * s_width + x; {
((uint16_t*)s_addr)[index2] = ((uint16_t*)s_addr)[index1]; uint32_t index1 = (y - 0) * s_width + x;
uint32_t index2 = (y - 1) * s_width + x;
((uint16_t*)s_addr)[index2] = ((uint16_t*)s_addr)[index1];
}
} }
} }

View File

@ -325,8 +325,7 @@ namespace TTY
while (terminal_row >= terminal_height) while (terminal_row >= terminal_height)
{ {
for (size_t line = 1; line < terminal_height; line++) VESA::Scroll();
VESA::ScrollLine(line);
clear_line(terminal_height - 1); clear_line(terminal_height - 1);
terminal_col = 0; terminal_col = 0;

View File

@ -25,10 +25,11 @@ namespace VESA
BRIGHT_WHITE = 15, BRIGHT_WHITE = 15,
}; };
bool Initialize(); bool PreInitialize();
void Initialize();
void PutEntryAt(uint16_t, uint32_t, uint32_t, Color, Color); void PutEntryAt(uint16_t, uint32_t, uint32_t, Color, Color);
void Clear(Color); void Clear(Color);
void ScrollLine(uint32_t line); void Scroll();
uint32_t GetTerminalWidth(); uint32_t GetTerminalWidth();
uint32_t GetTerminalHeight(); uint32_t GetTerminalHeight();

View File

@ -5,6 +5,7 @@
void kmalloc_initialize(); void kmalloc_initialize();
void kmalloc_dump_nodes(); void kmalloc_dump_nodes();
void* kmalloc_eternal(size_t);
void* kmalloc(size_t); void* kmalloc(size_t);
void kfree(void*); void kfree(void*);

View File

@ -52,7 +52,7 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic)
s_multiboot_info = mbi; s_multiboot_info = mbi;
if (!VESA::Initialize()) if (!VESA::PreInitialize())
{ {
dprintln("Could not initialize VESA"); dprintln("Could not initialize VESA");
return; return;
@ -61,6 +61,7 @@ extern "C" void kernel_main(multiboot_info_t* mbi, uint32_t magic)
kmalloc_initialize(); kmalloc_initialize();
VESA::Initialize();
ParsedCommandLine cmdline; ParsedCommandLine cmdline;
if (mbi->flags & 0x02) if (mbi->flags & 0x02)

View File

@ -7,6 +7,10 @@
#define MB (1 << 20) #define MB (1 << 20)
/*
#### KMALLOC ################
*/
struct kmalloc_node struct kmalloc_node
{ {
uint8_t* addr = nullptr; uint8_t* addr = nullptr;
@ -25,6 +29,17 @@ static uint8_t* const s_kmalloc_end = s_kmalloc_base + s_kmalloc_size;
static size_t s_kmalloc_available = 0; static size_t s_kmalloc_available = 0;
static size_t s_kmalloc_allocated = 0; static size_t s_kmalloc_allocated = 0;
/*
#### KMALLOC ETERNAL ########
*/
static uint8_t* s_kmalloc_eternal_ptr = nullptr;
static uint8_t* const s_kmalloc_eternal_base = s_kmalloc_end;
static constexpr size_t s_kmalloc_eternal_size = 2 * MB;
static uint8_t* const s_kmalloc_eternal_end = s_kmalloc_eternal_base + s_kmalloc_eternal_size;
/*
#############################
*/
void kmalloc_initialize() void kmalloc_initialize()
{ {
@ -39,7 +54,7 @@ void kmalloc_initialize()
if (mmmt->type == 1) if (mmmt->type == 1)
{ {
if (mmmt->base_addr <= (uint64_t)s_kmalloc_base && (uint64_t)s_kmalloc_end <= mmmt->base_addr + mmmt->length) if (mmmt->base_addr <= (uint64_t)s_kmalloc_base && (uint64_t)s_kmalloc_eternal_end <= mmmt->base_addr + mmmt->length)
{ {
dprintln("Total usable RAM: {} MB", (float)mmmt->length / MB); dprintln("Total usable RAM: {} MB", (float)mmmt->length / MB);
valid = true; valid = true;
@ -51,7 +66,7 @@ void kmalloc_initialize()
} }
if (!valid) if (!valid)
Kernel::panic("Kmalloc: Could not find 1 MB of memory"); Kernel::panic("Kmalloc: Could not find {} MB of memory", (double)(s_kmalloc_eternal_end - s_kmalloc_base));
s_kmalloc_node_count = 1; s_kmalloc_node_count = 1;
s_kmalloc_node_head = (kmalloc_node*)s_kmalloc_node_base; s_kmalloc_node_head = (kmalloc_node*)s_kmalloc_node_base;
@ -63,6 +78,8 @@ void kmalloc_initialize()
head.addr = s_kmalloc_base; head.addr = s_kmalloc_base;
head.size = s_kmalloc_size; head.size = s_kmalloc_size;
head.free = true; head.free = true;
s_kmalloc_eternal_ptr = s_kmalloc_eternal_base;
} }
void kmalloc_dump_nodes() void kmalloc_dump_nodes()
@ -77,6 +94,19 @@ void kmalloc_dump_nodes()
} }
} }
void* kmalloc_eternal(size_t size)
{
if (s_kmalloc_eternal_ptr + size > s_kmalloc_eternal_end)
{
dprintln("\e[33mKmalloc eternal: Could not allocate {} bytes\e[0m", size);
return nullptr;
}
void* result = (void*)s_kmalloc_eternal_ptr;
s_kmalloc_eternal_ptr += size;
return result;
}
void* kmalloc(size_t size) void* kmalloc(size_t size)
{ {
// Search for node with free memory and big enough size // Search for node with free memory and big enough size