BigOS/kernel/fbcon.c
2023-01-09 21:16:04 +08:00

219 lines
5.5 KiB
C

#include "bga.h"
#include "console.h"
#include "const.h"
#include "global.h"
#include "keyboard.h"
#include "memman.h"
#include "proc.h"
#include "protect.h"
#include "proto.h"
#include "serialport.h"
#include "spinlock.h"
#include "stdio.h"
#include "string.h"
#include "tty.h"
#include "type.h"
#include "x86.h"
#include "yieldlock.h"
static int cur_col = 0;
static int cur_row = 0;
static int _fnt_char_width = 0;
static int _fnt_char_height = 0;
static int _scr_max_rows = 0;
static int _scr_max_cols = 0;
static int _fbbufsize = 0;
static int _fbwidth = 0;
static int _fbheight = 0;
static int _fbpixels_per_row = 0;
static int _fbscale = 1;
static int cursor_blink = 0;
static uint32_t _basecolor = 0x0;
static uintptr_t _fb_paddr = 0;
static uint32_t* _fb = NULL;
static uint32_t* cur_fb = NULL;
static volatile int framecnt = 0;
static char* textbuf;
volatile u32 buflock;
#define UNIT_CHAR_H (_fnt_char_height * _fbscale)
#define UNIT_CHAR_W (_fnt_char_width * _fbscale)
#define INDEX(row, col, mx) ((row) * (mx) + (col))
#include "font8x8.h"
static void fast_copy(void* dst, void* src, int len);
static void fbcon_draw_raw(int row, int col, char ch) {
for (int x = 0; x < UNIT_CHAR_H; x++) {
for (int y = 0; y < UNIT_CHAR_W; y++) {
uint32_t ind = (col * UNIT_CHAR_W + x) + ((row * UNIT_CHAR_H + y) * _fbpixels_per_row);
uint32_t clr = _basecolor;
if (font8x8_basic[ch & 0x7f][y / _fbscale] &
(1 << (x / _fbscale))) {
clr ^= 0xffffffff;
}
cur_fb[ind] = clr;
}
}
}
static void draw_cursor() {
fbcon_draw_raw(cur_row, cur_col, 0);
}
static void draw_cursor_clear() {
fbcon_draw_raw(cur_row, cur_col, 1);
}
static void fbcon_scroll() {
int lineoffset = _fbwidth * _fnt_char_height * _fbscale;
fast_copy( (void*)cur_fb,
(void*)cur_fb + lineoffset,
_fbbufsize - lineoffset);
memset((void*)cur_fb + _fbbufsize - lineoffset, 0, lineoffset);
}
static void textbuf_scroll() {
memcpy((void*) textbuf, (void*)textbuf + _scr_max_cols, (_scr_max_rows-1)*_scr_max_cols);
memset((void*)textbuf + (_scr_max_rows-1)*_scr_max_cols, ' ', _scr_max_cols);
}
static void fbcon_putchar(char ch) {
switch (ch)
{
case '\n':
cur_row ++;
cur_col = 0;
if (cur_row >= _scr_max_rows) {
textbuf_scroll();
cur_row --;
}
break;
case '\r':
cur_col = 0;
break;
case '\b':
if (cur_col == 0) {
if (cur_row) cur_row --;
cur_col = _scr_max_cols - 1;
}
else {
cur_col --;
}
break;
default:
textbuf[INDEX(cur_row, cur_col, _scr_max_cols)] = ch;
cur_col ++;
if (cur_col >= _scr_max_cols) {
cur_col = 0;
cur_row ++;
}
if (cur_row >= _scr_max_rows) {
textbuf_scroll();
cur_row --;
}
break;
}
}
int screen_setup() {
cur_col = 0;
cur_row = 0;
_fnt_char_width = 8;
_fnt_char_height = 8;
_fb = (uint32_t*)bga_ioctl(BGA_GET_BUFFER, 0);
_fb_paddr = bga_ioctl(BGA_GET_BUFFER, 0);
_fbwidth = bga_ioctl(BGA_GET_WIDTH, 0);
_fbheight = bga_ioctl(BGA_GET_HEIGHT, 0);
_fbpixels_per_row = _fbwidth;
_fbbufsize = _fbwidth * _fbheight * 4;
_fbscale = 2;
cur_fb = _fb;
_scr_max_cols = _fbwidth / _fnt_char_width / _fbscale;
_scr_max_rows = _fbheight / _fnt_char_height / _fbscale;
kprintf("bufsz = %p, maxsize(%d, %d)\n", _fbbufsize, _scr_max_rows, _scr_max_cols);
_basecolor = 0;
cursor_blink = 1;
framecnt = 0;
textbuf = (char*)malloc(_scr_max_cols * _scr_max_rows);
memset(textbuf, ' ', _scr_max_cols * _scr_max_rows);
return 0;
}
static void do_fbcon_write(char* buf, int nr) {
disable_int();
while (nr--) {
fbcon_putchar(*buf++);
}
enable_int();
}
void fbcon_tty_write(NTTY* tty, char ch) {
do_fbcon_write(&ch, 1);
}
static void blink_ctrl() {
if (framecnt < 10) {
framecnt ++;
// kprintf("frame %d\n", framecnt);
}
else {
framecnt = 0;
cursor_blink = ! cursor_blink;
// kprintf("should change\n");
}
}
static void fast_copy(void* dst, void* src, int len) {
// assume all address align, 32 bytes a time
uint32_t* _src = src;
uint32_t* _dst = dst;
int i;
for (i = 0; i < len / 4; i += 8) {
_dst[i + 0] = _src[i + 0];
_dst[i + 1] = _src[i + 1];
_dst[i + 2] = _src[i + 2];
_dst[i + 3] = _src[i + 3];
_dst[i + 4] = _src[i + 4];
_dst[i + 5] = _src[i + 5];
_dst[i + 6] = _src[i + 6];
_dst[i + 7] = _src[i + 7];
}
}
static void textbuf_render() {
for (int row = 0; row < _scr_max_rows; ++ row) {
for (int col = 0; col < _scr_max_cols; ++ col) {
fbcon_draw_raw(row, col, textbuf[INDEX(row, col, _scr_max_cols)]);
}
}
}
void task_tty() {
// main rountine for drawing framebuffered console
screen_setup();
mmap((u32)_fb, _fb_paddr, _fbwidth * _fbheight * 4 * 2);
buflock = 0;
// fbcon_write(text1, strlen(text1));
int cur_buf = 0, last_buf = 1;
while (1) {
// fast_copy((void*)_fb + cur_buf * _fbbufsize, (void*)_fb + last_buf * _fbbufsize, _fbbufsize);
draw_cursor_clear();
while (xchg(&buflock, 1) == 1)
yield();
textbuf_render();
xchg(&buflock, 0);
blink_ctrl();
if (cursor_blink)
draw_cursor();
bga_ioctl(BGA_SWAP_BUFFERS, cur_buf);
last_buf = cur_buf;
cur_buf = !cur_buf;
cur_fb = (void*)_fb + cur_buf * _fbbufsize;
sleep(5); // to no need to refresh that fast
}
}