/* Output to HDMI if enabled */ // this process may be slow if (get_output_target() & OUTPUT_HDMI) { if (tid >= 0) { terminal_putchar(tid, (char)c); } else { // No task context (early boot) - output directly to HDMI terminal_putc((char)c); } } /* Output to UART if enabled */ if (get_output_target() & OUTPUT_UART) { bsp_uart_putc(0, (char)c); }
// all the character drawing functions draw on buffer S directly // we don't want to our game drawing functions to be affected by character drawing voidhdmi_draw_pixel(int x, int y, uint16_t color) { if (x >= 0 && x < HDMI_WIDTH && y >= 0 && y < FRAMEBUF_S_NUM_ROWS) { // 不用切换,直接在 buffer S 上绘制 volatileuint16_t *hdmi_fb_ptr_S = (volatileuint16_t *)HDMI_FB_BASE_S; hdmi_fb_ptr_S[y * HDMI_WIDTH + x] = color; } }
有一个问题是,滚动到 framebufferS 的最后一行了怎么办?目前的思路是直接回到 HDMI_FB_BASE_S,但是这里面的东西是脏的,需要擦拭,还是避免不了需要等。这个问题很好办,因为我的 xos 支持并发,我只需要在 shell 中输入 hdmigc,就会有专门的程序去擦除已经滚动上去的 buffer。问题是擦完了怎么办,还要占着时间片?小问题,实现软件中断就好:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
intcmd_hdmi_buffer_gc(int argc, char *argv[]) { &display_start_row, display_start_row); while (1) { if (shell_gc_pointer < display_start_row || shell_gc_pointer > display_start_row) { // clear one line int pixcel_row_start = shell_gc_pointer * TERMINAL_FONT_SIZE; int pixcel_row_end = pixcel_row_start + TERMINAL_FONT_SIZE; hdmi_clear_line(pixcel_row_start, pixcel_row_end, current_bg_color); shell_gc_pointer = (shell_gc_pointer + 1) % TERMINAL_TOTAL_ROWS; } else { // by calling task_yield(), we can yield cpu to other tasks task_yield(); // by saving easy context, we can yield cpu to other tasks // there is a problem here, unsolved YET. // task_yield_simple(); } } return0;
这样,就不会让一个空任务白白浪费处理器。
图像显示
图像显示一定是要多 framebuffer 的(目前是双 buffer)。当显示 A 的时候,我们让 CPU 去绘制 B,绘制好了或者 A 显示结束了我们想切换了直接 swap() 就好,swap() 会将当前显示的 buffer 和绘制的 buffer 切换: