graphics settings

This commit is contained in:
boreddevnl 2026-03-12 21:57:26 +01:00
parent d19075750b
commit 93b59064c7
13 changed files with 431 additions and 8 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -12,6 +12,8 @@ static uint32_t g_bg_color = 0xFF696969;
extern void serial_write(const char *str);
static int g_color_mode = 0;
#define PATTERN_SIZE 128
static uint32_t g_bg_pattern[PATTERN_SIZE * PATTERN_SIZE];
static bool g_use_pattern = false;
@ -54,6 +56,30 @@ void graphics_init_fonts(void) {
}
}
void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode) {
if (!g_fb) return;
uint64_t rflags;
asm volatile("pushfq; pop %0; cli" : "=r"(rflags));
g_fb->width = width;
g_fb->height = height;
g_fb->bpp = bpp;
g_fb->pitch = width * (bpp / 8);
g_fb->address = fb_addr;
g_color_mode = color_mode;
// Clear back buffer
for (int i = 0; i < MAX_FB_WIDTH * MAX_FB_HEIGHT; i++) {
g_back_buffer[i] = 0;
}
// Clear dirty rect
g_dirty.active = false;
asm volatile("push %0; popfq" : : "r"(rflags));
}
void graphics_set_font(const char *path) {
ttf_font_t *new_font = font_manager_load(path, 15.0f);
if (new_font) {
@ -576,9 +602,67 @@ void graphics_flip_buffer(void) {
for (int i = 0; i < h; i++) {
int curr_y = y + i;
uint32_t *src_row = &g_back_buffer[curr_y * g_fb->width + x];
uint32_t *dst_row = (uint32_t *)((uint8_t *)g_fb->address + curr_y * g_fb->pitch) + x;
for (int j = 0; j < w; j++) {
dst_row[j] = src_row[j];
if (g_fb->bpp == 32) {
uint32_t *dst_row = (uint32_t *)((uint8_t *)g_fb->address + curr_y * g_fb->pitch) + x;
for (int j = 0; j < w; j++) {
dst_row[j] = src_row[j];
}
} else if (g_fb->bpp == 16) {
uint16_t *dst_row = (uint16_t *)((uint8_t *)g_fb->address + curr_y * g_fb->pitch) + x;
for (int j = 0; j < w; j++) {
uint32_t c = src_row[j];
uint16_t r = ((c >> 16) & 0xFF) >> 3;
uint16_t g = ((c >> 8) & 0xFF) >> 2;
uint16_t b = (c & 0xFF) >> 3;
dst_row[j] = (r << 11) | (g << 5) | b;
}
} else if (g_fb->bpp == 8) {
uint8_t *dst_row = (uint8_t *)((uint8_t *)g_fb->address + curr_y * g_fb->pitch) + x;
if (g_color_mode == 1) { // Grayscale
for (int j = 0; j < w; j++) {
uint32_t c = src_row[j];
uint8_t r = (c >> 16) & 0xFF;
uint8_t g = (c >> 8) & 0xFF;
uint8_t b = c & 0xFF;
dst_row[j] = (uint8_t)((r * 77 + g * 150 + b * 29) >> 8);
}
} else if (g_color_mode == 2) { // Monochrome
static const uint8_t bayer2[2][2] = {
{ 0, 128 },
{192, 64 }
};
for (int j = 0; j < w; j++) {
uint32_t c = src_row[j];
uint8_t r = (c >> 16) & 0xFF;
uint8_t g = (c >> 8) & 0xFF;
uint8_t b = c & 0xFF;
int gray = (r * 77 + g * 150 + b * 29) >> 8;
// Boost contrast by 2x to separate the dark UI colors:
// Background (~30) -> 60
// Panel (~40) -> 80
// With thresholds {0, 64, 128, 192}:
// BG > 0 (1/4 white), Panel > 64 (2/4 white - checkerboard)
// Text (~170) -> 255 (solid white)
gray = gray * 2;
if (gray > 255) gray = 255;
int sx = x + j;
uint8_t threshold = bayer2[curr_y & 1][sx & 1];
dst_row[j] = (gray > threshold) ? 255 : 0;
}
} else { // 256 Colors (Standard)
for (int j = 0; j < w; j++) {
uint32_t c = src_row[j];
uint8_t r = ((c >> 16) & 0xFF) >> 5;
uint8_t g = ((c >> 8) & 0xFF) >> 5;
uint8_t b = (c & 0xFF) >> 6;
dst_row[j] = (r << 5) | (g << 2) | b;
}
}
}
}
}

View file

@ -39,6 +39,7 @@ void draw_boredos_logo(int x, int y, int scale);
// Get screen dimensions
int get_screen_width(void);
int get_screen_height(void);
void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode);
// Dirty rectangle management
void graphics_mark_dirty(int x, int y, int w, int h);

View file

@ -1156,6 +1156,30 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
extern void mem_memcpy(void *dest, const void *src, size_t len);
mem_memcpy(user_buf, model, 49);
return 0;
} else if (cmd == 47) { // SYSTEM_CMD_SET_RESOLUTION
uint16_t req_w = (uint16_t)arg2;
uint16_t req_h = (uint16_t)arg3;
uint16_t req_bpp = (uint16_t)arg4;
int req_color_mode = (int)arg5;
extern bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer);
extern void graphics_update_resolution(int width, int height, int bpp, void* fb_addr, int color_mode);
extern void wm_refresh(void);
extern void vga_set_palette_grayscale(void);
extern void vga_set_palette_standard(void);
void *new_fb = NULL;
if (vga_set_mode(req_w, req_h, req_bpp, &new_fb)) {
if (req_color_mode == 1 || req_color_mode == 2) {
vga_set_palette_grayscale();
} else if (req_bpp <= 8) {
vga_set_palette_standard();
}
graphics_update_resolution(req_w, req_h, req_bpp, new_fb, req_color_mode);
wm_refresh();
return 0;
}
return -1;
}
return -1;
}

View file

@ -45,6 +45,7 @@ typedef struct registers_t registers_t;
#define SYSTEM_CMD_PROCESS_LIST 44
#define SYSTEM_CMD_GET_CPU_MODEL 45
#define SYSTEM_CMD_SLEEP 46
#define SYSTEM_CMD_SET_RESOLUTION 47
void syscall_init(void);
uint64_t syscall_handler_c(registers_t *regs);

View file

@ -9,6 +9,7 @@ extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_
// sys_gui uses syscall #3
#define SYS_GUI 3
#define GUI_CMD_GET_SCREEN_SIZE 17
ui_window_t ui_window_create(const char *title, int x, int y, int w, int h) {
uint64_t params[4] = { (uint64_t)x, (uint64_t)y, (uint64_t)w, (uint64_t)h };
@ -58,6 +59,10 @@ uint32_t ui_get_font_height(void) {
return (uint32_t)syscall3(SYS_GUI, GUI_CMD_GET_FONT_HEIGHT, 0, 0);
}
void ui_get_screen_size(uint64_t *out_w, uint64_t *out_h) {
syscall3(SYS_GUI, GUI_CMD_GET_SCREEN_SIZE, (uint64_t)out_w, (uint64_t)out_h);
}
void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale) {
uint64_t coords = ((uint64_t)x & 0xFFFFFFFF) | ((uint64_t)y << 32);
// Pack color into lower 32, scale (as uint32_t representation) into upper 32

View file

@ -58,6 +58,7 @@ void ui_mark_dirty(ui_window_t win, int x, int y, int w, int h);
void ui_draw_image(ui_window_t win, int x, int y, int w, int h, uint32_t *image_data);
uint32_t ui_get_string_width(const char *str);
uint32_t ui_get_font_height(void);
void ui_get_screen_size(uint64_t *out_w, uint64_t *out_h);
void ui_draw_string_bitmap(ui_window_t win, int x, int y, const char *str, uint32_t color);
void ui_draw_string_scaled(ui_window_t win, int x, int y, const char *str, uint32_t color, float scale);

View file

@ -29,14 +29,47 @@
#define VIEW_DESKTOP 3
#define VIEW_MOUSE 4
#define VIEW_FONTS 5
#define VIEW_DISPLAY 6
static int disp_sel_res = 2;
static int disp_sel_color = 0;
static int current_view = VIEW_MAIN;
static char rgb_r[4] = "";
static char rgb_g[4] = "";
static char rgb_b[4] = "";
static char custom_res_w[6] = "";
static char custom_res_h[6] = "";
static int focused_field = -1;
static int input_cursor = 0;
static int dyn_res_w[3];
static int dyn_res_h[3];
static char dyn_res_str[3][32];
static void init_dynamic_resolutions(void) {
uint64_t phys_w = 1920, phys_h = 1080;
ui_get_screen_size(&phys_w, &phys_h);
dyn_res_w[2] = (int)phys_w; dyn_res_h[2] = (int)phys_h;
dyn_res_w[1] = (int)((phys_w * 3) / 4); dyn_res_h[1] = (int)((phys_h * 3) / 4);
dyn_res_w[0] = (int)(phys_w / 2); dyn_res_h[0] = (int)(phys_h / 2);
for (int i = 0; i < 2; i++) {
dyn_res_w[i] &= ~1;
dyn_res_h[i] &= ~1;
}
for (int i = 0; i < 3; i++) {
char bw[16], bh[16];
itoa(dyn_res_w[i], bw);
itoa(dyn_res_h[i], bh);
strcpy(dyn_res_str[i], bw);
strcat(dyn_res_str[i], "x");
strcat(dyn_res_str[i], bh);
}
}
static char net_status[64] = "";
// Pattern buffers (128x128)
@ -248,6 +281,17 @@ static void control_panel_paint_main(ui_window_t win) {
ui_draw_string(win, offset_x + 14, offset_y + item_y + 10, "Aa", 0xFF6A9EF5);
ui_draw_string(win, offset_x + 60, offset_y + item_y + 15, "Fonts", COLOR_DARK_TEXT);
ui_draw_string(win, offset_x + 60, offset_y + item_y + 35, "Choose system font", COLOR_DKGRAY);
// Display
item_y += item_h + item_spacing;
ui_draw_rounded_rect_filled(win, offset_x, offset_y + item_y, win_w - 16, item_h, 8, COLOR_DARK_PANEL);
// Monitor icon
ui_draw_rect(win, offset_x + 14, offset_y + item_y + 12, 32, 22, 0xFF4A90E2);
ui_draw_rect(win, offset_x + 16, offset_y + item_y + 14, 28, 18, 0xFF87CEEB);
ui_draw_rect(win, offset_x + 26, offset_y + item_y + 34, 8, 4, 0xFFB0B0B0);
ui_draw_rect(win, offset_x + 22, offset_y + item_y + 38, 16, 2, 0xFFB0B0B0);
ui_draw_string(win, offset_x + 60, offset_y + item_y + 15, "Display", COLOR_DARK_TEXT);
ui_draw_string(win, offset_x + 60, offset_y + item_y + 35, "Screen resolution & color", COLOR_DKGRAY);
}
static void control_panel_paint_wallpaper(ui_window_t win) {
@ -507,6 +551,73 @@ static void control_panel_paint_fonts(ui_window_t win) {
}
}
static void control_panel_paint_display(ui_window_t win) {
int offset_x = 8;
int offset_y = 6;
int right_x = offset_x + 160;
ui_draw_rounded_rect_filled(win, offset_x, offset_y + 5, 80, 25, 6, COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 10, offset_y + 13, "< Back", COLOR_DARK_TEXT);
ui_draw_string(win, offset_x, offset_y + 40, "Resolution:", COLOR_DARK_TEXT);
int btn_y = offset_y + 60;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 0) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, "640x480", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 1) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, "800x600", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 2) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, dyn_res_str[0], COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 3) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, dyn_res_str[1], COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 4) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, dyn_res_str[2], COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 140, 30, 6, (disp_sel_res == 5) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 30, btn_y + 10, "Custom:", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 60, 25, 4, (focused_field == 3) ? 0xFF4A90E2 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 5, btn_y + 7, custom_res_w[0] ? custom_res_w : "W", (custom_res_w[0] || focused_field == 3) ? 0xFFFFFFFF : 0xFF888888);
ui_draw_string(win, offset_x + 65, btn_y + 7, "x", COLOR_DARK_TEXT);
ui_draw_rounded_rect_filled(win, offset_x + 80, btn_y, 60, 25, 4, (focused_field == 4) ? 0xFF4A90E2 : COLOR_DARK_PANEL);
ui_draw_string(win, offset_x + 85, btn_y + 7, custom_res_h[0] ? custom_res_h : "H", (custom_res_h[0] || focused_field == 4) ? 0xFFFFFFFF : 0xFF888888);
btn_y = offset_y + 60;
ui_draw_string(win, right_x, offset_y + 40, "Color Depth:", COLOR_DARK_TEXT);
ui_draw_rounded_rect_filled(win, right_x, btn_y, 140, 30, 6, (disp_sel_color == 0) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, right_x + 40, btn_y + 10, "32-bit", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, right_x, btn_y, 140, 30, 6, (disp_sel_color == 1) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, right_x + 40, btn_y + 10, "16-bit", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, right_x, btn_y, 140, 30, 6, (disp_sel_color == 2) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, right_x + 25, btn_y + 10, "256 Colors", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, right_x, btn_y, 140, 30, 6, (disp_sel_color == 3) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, right_x + 30, btn_y + 10, "Grayscale", COLOR_DARK_TEXT);
btn_y += 35;
ui_draw_rounded_rect_filled(win, right_x, btn_y, 140, 30, 6, (disp_sel_color == 4) ? 0xFF3D5A80 : COLOR_DARK_PANEL);
ui_draw_string(win, right_x + 25, btn_y + 10, "Monochrome", COLOR_DARK_TEXT);
btn_y = offset_y + 320;
ui_draw_rounded_rect_filled(win, offset_x, btn_y, 300, 35, 6, 0xFF4A90E2);
ui_draw_string(win, offset_x + 125, btn_y + 12, "Apply", 0xFFFFFFFF);
}
static void control_panel_paint(ui_window_t win) {
// Fill background
ui_draw_rect(win, 0, 0, 350, 500, COLOR_DARK_BG);
@ -523,6 +634,8 @@ static void control_panel_paint(ui_window_t win) {
control_panel_paint_mouse(win);
} else if (current_view == VIEW_FONTS) {
control_panel_paint_fonts(win);
} else if (current_view == VIEW_DISPLAY) {
control_panel_paint_display(win);
}
}
@ -544,6 +657,7 @@ static void fetch_kernel_state(void) {
desktop_max_cols = sys_system(7, 4, 0, 0, 0);
mouse_speed = sys_system(8 /*GET_MOUSE_SPEED*/, 0, 0, 0, 0);
init_dynamic_resolutions();
load_wallpapers();
}
@ -579,6 +693,10 @@ static void control_panel_handle_click(int x, int y) {
current_view = VIEW_FONTS;
if (font_count == 0) load_fonts();
}
item_y += item_h + item_spacing;
if (x >= offset_x && x < win_w - 8 && y >= item_y && y < item_y + item_h) {
current_view = VIEW_DISPLAY;
}
} else if (current_view == VIEW_WALLPAPER) {
int offset_x = 8;
int offset_y = 6;
@ -762,6 +880,73 @@ static void control_panel_handle_click(int x, int y) {
}
item_y += 40;
}
} else if (current_view == VIEW_DISPLAY) {
int offset_x = 8;
int offset_y = 6;
int right_x = offset_x + 160;
if (x >= offset_x && x < offset_x + 80 && y >= offset_y + 5 && y < offset_y + 30) {
current_view = VIEW_MAIN;
return;
}
int btn_y = offset_y + 60;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 0;
if (x >= right_x && x < right_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_color = 0;
btn_y += 35;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 1;
if (x >= right_x && x < right_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_color = 1;
btn_y += 35;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 2;
if (x >= right_x && x < right_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_color = 2;
btn_y += 35;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 3;
if (x >= right_x && x < right_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_color = 3;
btn_y += 35;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 4;
if (x >= right_x && x < right_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_color = 4;
btn_y += 35;
if (x >= offset_x && x < offset_x + 140 && y >= btn_y && y < btn_y + 30) disp_sel_res = 5;
// Custom Inputs
btn_y += 35;
if (x >= offset_x && x < offset_x + 60 && y >= btn_y && y < btn_y + 25) {
focused_field = 3; disp_sel_res = 5;
int len = 0; while (custom_res_w[len]) len++; input_cursor = len;
}
if (x >= offset_x + 80 && x < offset_x + 140 && y >= btn_y && y < btn_y + 25) {
focused_field = 4; disp_sel_res = 5;
int len = 0; while (custom_res_h[len]) len++; input_cursor = len;
}
btn_y = offset_y + 320;
if (x >= offset_x && x < offset_x + 300 && y >= btn_y && y < btn_y + 35) {
int w = 1024, h = 768;
if (disp_sel_res == 0) { w = 640; h = 480; }
else if (disp_sel_res == 1) { w = 800; h = 600; }
else if (disp_sel_res >= 2 && disp_sel_res <= 4) {
w = dyn_res_w[disp_sel_res - 2];
h = dyn_res_h[disp_sel_res - 2];
} else if (disp_sel_res == 5) {
extern int atoi(const char *str);
int cw = atoi(custom_res_w);
int ch = atoi(custom_res_h);
if (cw >= 320 && ch >= 200) { w = cw; h = ch; }
}
int bpp = 32, mode = 0;
if (disp_sel_color == 1) { bpp = 16; }
if (disp_sel_color == 2) { bpp = 8; mode = 0; }
if (disp_sel_color == 3) { bpp = 8; mode = 1; }
if (disp_sel_color == 4) { bpp = 8; mode = 2; }
sys_system(47 /*SET_RESOLUTION*/, w, h, bpp, mode);
}
}
}
@ -769,13 +954,15 @@ static void control_panel_handle_key(char c, bool pressed) {
if (!pressed) return;
if (focused_field < 0) return;
if (current_view == VIEW_WALLPAPER) {
if (current_view == VIEW_WALLPAPER || current_view == VIEW_DISPLAY) {
char *focused_buffer = NULL;
int max_len = 3;
if (focused_field == 0) focused_buffer = rgb_r;
else if (focused_field == 1) focused_buffer = rgb_g;
else if (focused_field == 2) focused_buffer = rgb_b;
if (focused_field == 0 && current_view == VIEW_WALLPAPER) focused_buffer = rgb_r;
else if (focused_field == 1 && current_view == VIEW_WALLPAPER) focused_buffer = rgb_g;
else if (focused_field == 2 && current_view == VIEW_WALLPAPER) focused_buffer = rgb_b;
else if (focused_field == 3 && current_view == VIEW_DISPLAY) { focused_buffer = custom_res_w; max_len = 5; }
else if (focused_field == 4 && current_view == VIEW_DISPLAY) { focused_buffer = custom_res_h; max_len = 5; }
else return;
if (c == '\b') {

84
src/kernel/vga.c Normal file
View file

@ -0,0 +1,84 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#include "vga.h"
#include "io.h"
#include "pci.h"
#include "platform.h"
extern void serial_write(const char *str);
extern void serial_write_num(uint32_t n);
static void vga_write_register(uint16_t index, uint16_t data) {
outw(VBE_DISPI_IOPORT_INDEX, index);
outw(VBE_DISPI_IOPORT_DATA, data);
}
bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer) {
// 1. Locate the BGA PCI device to get the physical framebuffer address
pci_device_t bga_dev;
// Standard VGA compatible controller is Class 0x03, Subclass 0x00
if (!pci_find_device_by_class(0x03, 0x00, &bga_dev)) {
serial_write("[VGA] Error: VGA compatible controller not found via PCI!\n");
return false;
}
// Read BAR0 (offset 0x10)
uint32_t bar0 = pci_read_config(bga_dev.bus, bga_dev.device, bga_dev.function, 0x10);
// physical address is bar0 with the lower 4 bits masked out
uint32_t phys_base = bar0 & 0xFFFFFFF0;
if (phys_base == 0) {
serial_write("[VGA] Error: Invalid BAR0 physical base.\n");
return false;
}
serial_write("[VGA] Found VGA Controller. LFB Phys Base: ");
serial_write_num(phys_base);
serial_write("\n");
// Map physical to virtual using p2v
void *vram_ptr = (void *)p2v(phys_base);
// 2. Disable BGA extensions first
vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED);
// 3. Set resolution and BPP
vga_write_register(VBE_DISPI_INDEX_XRES, width);
vga_write_register(VBE_DISPI_INDEX_YRES, height);
vga_write_register(VBE_DISPI_INDEX_BPP, bpp);
// 4. Re-enable BGA and Linear Framebuffer
vga_write_register(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
if (out_framebuffer) {
*out_framebuffer = vram_ptr;
}
return true;
}
void vga_set_palette_grayscale(void) {
outb(0x03C8, 0); // Palette index
for (int i = 0; i < 256; i++) {
// VGA palette uses 6 bits per channel (0-63)
uint8_t val = i >> 2;
outb(0x03C9, val); // R
outb(0x03C9, val); // G
outb(0x03C9, val); // B
}
}
void vga_set_palette_standard(void) {
outb(0x03C8, 0); // Palette index
for (int i = 0; i < 256; i++) {
// Standard 3:3:2 RGB mapping to 6-bit per channel
uint8_t r = (i >> 5) & 0x7;
uint8_t g = (i >> 2) & 0x7;
uint8_t b = i & 0x3;
outb(0x03C9, (r * 63) / 7);
outb(0x03C9, (g * 63) / 7);
outb(0x03C9, (b * 63) / 3);
}
}

36
src/kernel/vga.h Normal file
View file

@ -0,0 +1,36 @@
// Copyright (c) 2023-2026 Chris (boreddevnl)
// This software is released under the GNU General Public License v3.0. See LICENSE file for details.
// This header needs to maintain in any file it is present in, as per the GPL license terms.
#ifndef VGA_H
#define VGA_H
#include <stdint.h>
#include <stdbool.h>
#define VBE_DISPI_IOPORT_INDEX 0x01CE
#define VBE_DISPI_IOPORT_DATA 0x01CF
#define VBE_DISPI_INDEX_ID 0
#define VBE_DISPI_INDEX_XRES 1
#define VBE_DISPI_INDEX_YRES 2
#define VBE_DISPI_INDEX_BPP 3
#define VBE_DISPI_INDEX_ENABLE 4
#define VBE_DISPI_INDEX_BANK 5
#define VBE_DISPI_INDEX_VIRT_WIDTH 6
#define VBE_DISPI_INDEX_VIRT_HEIGHT 7
#define VBE_DISPI_INDEX_X_OFFSET 8
#define VBE_DISPI_INDEX_Y_OFFSET 9
#define VBE_DISPI_DISABLED 0x00
#define VBE_DISPI_ENABLED 0x01
#define VBE_DISPI_LFB_ENABLED 0x40
#define COLOR_MODE_NORMAL 0
#define COLOR_MODE_GRAYSCALE 1
#define COLOR_MODE_MONOCHROME 2
bool vga_set_mode(uint16_t width, uint16_t height, uint16_t bpp, void **out_framebuffer);
void vga_set_palette_grayscale(void);
void vga_set_palette_standard(void);
#endif