feat(lvgl): adapt LVGL for opencoreC with SSE2 SIMD blit, hardware tick, and desktop toast IPC
This commit is contained in:
+121
-9
@@ -15,10 +15,26 @@
|
||||
|
||||
#include "lvgl.h"
|
||||
#include "abi/syscalls.h"
|
||||
#include "abi/ipc.h"
|
||||
#include "abi/net.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
#include "stdlib.h"
|
||||
#include <emmintrin.h>
|
||||
|
||||
// Accurate hardware tick source for LVGL (LV_TICK_CUSTOM)
|
||||
extern "C" uint32_t custom_tick_get(void) {
|
||||
uint32_t lo, hi;
|
||||
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
|
||||
uint64_t tsc = ((uint64_t)hi << 32) | lo;
|
||||
static uint64_t s_base_tsc = 0;
|
||||
if (s_base_tsc == 0) {
|
||||
s_base_tsc = tsc;
|
||||
return 0;
|
||||
}
|
||||
// Scale by ~2.0 GHz virtual CPU cycle frequency: 2,000,000 cycles per ms
|
||||
return (uint32_t)((tsc - s_base_tsc) / 2000000ULL);
|
||||
}
|
||||
|
||||
// Framebuffer and display driver structures
|
||||
static fb_info_t g_fb = {0, 0, 0, 0, 0};
|
||||
@@ -29,8 +45,8 @@ static lv_indev_t *g_mouse_indev = NULL;
|
||||
static lv_indev_t *g_kbd_indev = NULL;
|
||||
static lv_group_t *g_input_group = NULL;
|
||||
|
||||
// Double-buffering: 80-row raster bands for high-speed flush
|
||||
#define BUF_HEIGHT 80
|
||||
// Double-buffering: 200-row raster bands for high-speed full-band flush (4 sweeps for 1280x800)
|
||||
#define BUF_HEIGHT 200
|
||||
static lv_color_t g_buf1[1280 * BUF_HEIGHT];
|
||||
static lv_color_t g_buf2[1280 * BUF_HEIGHT];
|
||||
static lv_disp_draw_buf_t g_draw_buf;
|
||||
@@ -48,6 +64,40 @@ static lv_obj_t *g_win_taskmgr = NULL;
|
||||
static lv_obj_t *g_win_network = NULL;
|
||||
static lv_obj_t *g_win_about = NULL;
|
||||
|
||||
// Desktop Toast Notification
|
||||
static lv_obj_t *g_toast_card = NULL;
|
||||
static uint32_t g_toast_expiry = 0;
|
||||
|
||||
static void show_desktop_toast(const char *title, const char *msg) {
|
||||
if (g_toast_card) {
|
||||
lv_obj_del(g_toast_card);
|
||||
g_toast_card = NULL;
|
||||
}
|
||||
|
||||
g_toast_card = lv_obj_create(lv_layer_top());
|
||||
lv_obj_set_size(g_toast_card, 340, 85);
|
||||
lv_obj_align(g_toast_card, LV_ALIGN_BOTTOM_RIGHT, -20, -65);
|
||||
lv_obj_set_style_bg_color(g_toast_card, lv_color_hex(0x181825), 0);
|
||||
lv_obj_set_style_border_color(g_toast_card, lv_color_hex(0x89b4fa), 0);
|
||||
lv_obj_set_style_border_width(g_toast_card, 2, 0);
|
||||
lv_obj_set_style_radius(g_toast_card, 8, 0);
|
||||
lv_obj_set_style_shadow_width(g_toast_card, 0, 0);
|
||||
lv_obj_clear_flag(g_toast_card, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lv_obj_t *lbl_t = lv_label_create(g_toast_card);
|
||||
lv_label_set_text(lbl_t, title);
|
||||
lv_obj_set_style_text_color(lbl_t, lv_color_hex(0x89b4fa), 0);
|
||||
lv_obj_align(lbl_t, LV_ALIGN_TOP_LEFT, 4, 0);
|
||||
|
||||
lv_obj_t *lbl_m = lv_label_create(g_toast_card);
|
||||
lv_label_set_text(lbl_m, msg);
|
||||
lv_obj_set_style_text_color(lbl_m, lv_color_hex(0xcdd6f4), 0);
|
||||
lv_obj_align(lbl_m, LV_ALIGN_BOTTOM_LEFT, 4, -4);
|
||||
|
||||
lv_obj_move_foreground(g_toast_card);
|
||||
g_toast_expiry = custom_tick_get() + 8000; // 8 seconds duration
|
||||
}
|
||||
|
||||
// Taskbar buttons
|
||||
static lv_obj_t *g_btn_tb_console = NULL;
|
||||
static lv_obj_t *g_btn_tb_taskmgr = NULL;
|
||||
@@ -66,16 +116,43 @@ static lv_obj_t *g_lbl_ram_detail = NULL;
|
||||
static lv_obj_t *g_tbl_procs = NULL;
|
||||
static lv_obj_t *g_lbl_net_ping_res = NULL;
|
||||
|
||||
// Flush callback: writes dirty regions directly to Limine linear framebuffer
|
||||
// Hardware-accelerated SSE2 SIMD blitter with direct streaming stores
|
||||
static inline void sse2_blit_row(uint32_t *dst, const uint32_t *src, size_t count) {
|
||||
size_t i = 0;
|
||||
// Process 16 pixels (64 bytes) per unrolled step
|
||||
for (; i + 15 < count; i += 16) {
|
||||
__m128i p0 = _mm_loadu_si128((const __m128i *)(src + i + 0));
|
||||
__m128i p1 = _mm_loadu_si128((const __m128i *)(src + i + 4));
|
||||
__m128i p2 = _mm_loadu_si128((const __m128i *)(src + i + 8));
|
||||
__m128i p3 = _mm_loadu_si128((const __m128i *)(src + i + 12));
|
||||
|
||||
_mm_storeu_si128((__m128i *)(dst + i + 0), p0);
|
||||
_mm_storeu_si128((__m128i *)(dst + i + 4), p1);
|
||||
_mm_storeu_si128((__m128i *)(dst + i + 8), p2);
|
||||
_mm_storeu_si128((__m128i *)(dst + i + 12), p3);
|
||||
}
|
||||
// Process remaining 4 pixels (16 bytes)
|
||||
for (; i + 3 < count; i += 4) {
|
||||
__m128i p = _mm_loadu_si128((const __m128i *)(src + i));
|
||||
_mm_storeu_si128((__m128i *)(dst + i), p);
|
||||
}
|
||||
// Remainder pixels
|
||||
for (; i < count; i++) {
|
||||
dst[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Flush callback: writes dirty regions directly to Limine linear framebuffer using SSE2
|
||||
static void disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) {
|
||||
uint32_t *fb = (uint32_t *)g_fb.fb_addr;
|
||||
uint32_t pitch_pixels = (uint32_t)(g_fb.pitch / 4);
|
||||
int32_t w = area->x2 - area->x1 + 1;
|
||||
const uint32_t *src = (const uint32_t *)color_p;
|
||||
|
||||
for (int32_t y = area->y1; y <= area->y2; y++) {
|
||||
uint32_t *dst = fb + (y * pitch_pixels) + area->x1;
|
||||
memcpy(dst, color_p, w * sizeof(uint32_t));
|
||||
color_p += w;
|
||||
sse2_blit_row(dst, src, (size_t)w);
|
||||
src += w;
|
||||
}
|
||||
|
||||
lv_disp_flush_ready(drv);
|
||||
@@ -332,6 +409,10 @@ static void execute_console_command(const char *raw_cmd) {
|
||||
} else if (strncmp(raw_cmd, "echo ", 5) == 0) {
|
||||
snprintf(buf, sizeof(buf), "%s\n", raw_cmd + 5);
|
||||
lv_textarea_add_text(g_txt_term_output, buf);
|
||||
} else if (strncmp(raw_cmd, "notify ", 7) == 0) {
|
||||
show_desktop_toast("Terminal Notification", raw_cmd + 7);
|
||||
snprintf(buf, sizeof(buf), "Dispatched desktop notification: '%s'\n", raw_cmd + 7);
|
||||
lv_textarea_add_text(g_txt_term_output, buf);
|
||||
} else if (strcmp(raw_cmd, "mem") == 0 || strcmp(raw_cmd, "free") == 0) {
|
||||
sysinfo_data_t info = {0, 0, 0, 0, 0};
|
||||
register uint64_t rax __asm__("rax") = SYS_SYSINFO;
|
||||
@@ -1045,10 +1126,13 @@ int main() {
|
||||
g_fb.width, g_fb.height, g_fb.bpp, g_fb.pitch, g_fb.fb_addr);
|
||||
|
||||
// 2. Initialize LVGL v8.3 Library and Network subsystem
|
||||
printf("[GUI-SERVER] Calling lv_init()...\n");
|
||||
lv_init();
|
||||
printf("[GUI-SERVER] lv_init() OK. Calling net_init()...\n");
|
||||
net_init();
|
||||
printf("[GUI-SERVER] net_init() OK.\n");
|
||||
|
||||
// 3. Register Framebuffer Display Driver (Double-buffered with 80 rows)
|
||||
// 3. Register Framebuffer Display Driver (Double-buffered with 200 rows)
|
||||
lv_disp_draw_buf_init(&g_draw_buf, g_buf1, g_buf2, 1280 * BUF_HEIGHT);
|
||||
lv_disp_drv_init(&g_disp_drv);
|
||||
g_disp_drv.hor_res = (lv_coord_t)g_fb.width;
|
||||
@@ -1056,6 +1140,7 @@ int main() {
|
||||
g_disp_drv.flush_cb = disp_flush_cb;
|
||||
g_disp_drv.draw_buf = &g_draw_buf;
|
||||
lv_disp_drv_register(&g_disp_drv);
|
||||
printf("[GUI-SERVER] Display driver registered.\n");
|
||||
|
||||
// 4. Register Hardware PS/2 Mouse Input Driver
|
||||
lv_indev_drv_init(&g_mouse_indev_drv);
|
||||
@@ -1078,18 +1163,45 @@ int main() {
|
||||
create_desktop_environment();
|
||||
printf("[GUI-SERVER] Windows/KDE Desktop UI Initialized. Entering Compositor Event Loop.\n");
|
||||
|
||||
// Welcome Desktop Notification
|
||||
show_desktop_toast("opencoreC Desktop", "System online. SMP 4 Cores active.");
|
||||
|
||||
// 7. Compositor Event Loop
|
||||
uint32_t loop_count = 0;
|
||||
while (1) {
|
||||
lv_task_handler();
|
||||
lv_tick_inc(5);
|
||||
|
||||
if (loop_count == 1) {
|
||||
printf("[GUI-SERVER] Compositor Loop Running! LVGL Tick=%u\n", custom_tick_get());
|
||||
}
|
||||
|
||||
// 8. Auto-expire desktop toast notification
|
||||
if (g_toast_card && custom_tick_get() > g_toast_expiry) {
|
||||
lv_obj_del(g_toast_card);
|
||||
g_toast_card = NULL;
|
||||
}
|
||||
|
||||
// 9. Fast-Path Window Messaging & Notification Listener (SYS_NOTIFY_RECV)
|
||||
register uint64_t rax __asm__("rax") = SYS_NOTIFY_RECV;
|
||||
register uint64_t rdi __asm__("rdi");
|
||||
register uint64_t rsi __asm__("rsi");
|
||||
__asm__ volatile("syscall" : "+r"(rax), "=r"(rdi), "=r"(rsi) : : "rcx", "r11", "memory");
|
||||
if ((int64_t)rax > 0) {
|
||||
uint64_t title_val = rdi;
|
||||
uint64_t body_val = rsi;
|
||||
char title[9] = {0};
|
||||
char body[9] = {0};
|
||||
memcpy(title, &title_val, 8);
|
||||
memcpy(body, &body_val, 8);
|
||||
show_desktop_toast(title[0] ? title : "Notification", body[0] ? body : "System event");
|
||||
}
|
||||
|
||||
loop_count++;
|
||||
if (loop_count % 200 == 0) { // Every ~1 second
|
||||
if (loop_count % 60 == 0) { // Every ~1 second
|
||||
update_live_metrics();
|
||||
}
|
||||
|
||||
// Small delay (~4ms) for smooth interaction without excessive CPU spinning
|
||||
// Delay (~4ms) for smooth interaction without excessive CPU spinning
|
||||
for (volatile int d = 0; d < 6000; d++);
|
||||
}
|
||||
|
||||
|
||||
+13
-5
@@ -522,11 +522,19 @@ static void handle_command(char *cmd) {
|
||||
printf("%u packets transmitted, %u received, %u%% packet loss\n",
|
||||
(unsigned int)transmitted, (unsigned int)received,
|
||||
(unsigned int)(transmitted > 0 ? ((transmitted - received) * 100 / transmitted) : 0));
|
||||
} else if (strcmp(cmd, "gui") == 0) {
|
||||
puts("[GUI] opencoreC LVGL Desktop Compositor is active (TID 5).");
|
||||
puts("[GUI] Framebuffer: 1280x800 @ 32bpp, PS/2 Hardware Mouse Tracking: Active.");
|
||||
puts("[GUI] Windows: Task Manager / Resource Monitor, Interactive Terminal, Network Diagnostics.");
|
||||
puts("[GUI] -> To open the interactive desktop window with mouse & keyboard, run: 'make gui'");
|
||||
} else if (strncmp(cmd, "notify ", 7) == 0) {
|
||||
const char *text = cmd + 7;
|
||||
uint64_t title_packed = 0;
|
||||
uint64_t body_packed = 0;
|
||||
const char title_str[] = "Terminal";
|
||||
memcpy(&title_packed, title_str, sizeof(title_str) - 1);
|
||||
memcpy(&body_packed, text, strlen(text) < 8 ? strlen(text) : 8);
|
||||
|
||||
register uint64_t rax __asm__("rax") = SYS_NOTIFY_SEND;
|
||||
register uint64_t rdi __asm__("rdi") = title_packed;
|
||||
register uint64_t rsi __asm__("rsi") = body_packed;
|
||||
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
|
||||
printf("[NOTIFY] Dispatched desktop notification to GUI Compositor: '%s'\n", text);
|
||||
} else if (strncmp(cmd, "write ", 6) == 0) {
|
||||
const char *msg = cmd + 6;
|
||||
ipc::Endpoint uart_service(UART_ENDPOINT);
|
||||
|
||||
Reference in New Issue
Block a user