- Fix swapped command IDs: attach_backing was 0x0104 (FLUSH), resource_flush was 0x0106 (ATTACH_BACKING). Now correct. - Increase process stack from 4 pages (16 KB) to 16 pages (64 KB) to prevent stack overflow in display process. - Restructure display-qemu to avoid MockFramebuffer's 32 KB array inflating the VirtIO path's stack frame. - Wire snake app to render through display server via IPC instead of UART escape codes. Uses existing renderer.rs pixel renderer. - Init now delegates display endpoint to snake process.
92 lines
2.5 KiB
Rust
92 lines
2.5 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
|
|
extern crate userspace_rt;
|
|
|
|
use snake::game::{Direction, GameState, Snake};
|
|
use snake::renderer::{self, RenderCommand};
|
|
use types::bounded::CapSlot;
|
|
use types::display::{Color, Dimension, ScreenCoord};
|
|
use types::time::Ticks;
|
|
use userspace_rt::syscall;
|
|
use server_framework::Encode;
|
|
use display_server::protocol::DisplayRequest;
|
|
|
|
const INPUT_EP: CapSlot = CapSlot::const_new(0);
|
|
const DISPLAY_EP: CapSlot = CapSlot::const_new(1);
|
|
const TICK_DELAY: u64 = 2_000_000;
|
|
const MAX_RENDER_CMDS: usize = 140;
|
|
|
|
fn display_send(req: &DisplayRequest) {
|
|
let words = req.encode();
|
|
syscall::send(DISPLAY_EP, words[0], words[1], words[2], words[3]);
|
|
syscall::receive(DISPLAY_EP);
|
|
}
|
|
|
|
fn draw_rect(x: u16, y: u16, w: u16, h: u16, color: u32) {
|
|
display_send(&DisplayRequest::DrawRect {
|
|
x: ScreenCoord::new(x),
|
|
y: ScreenCoord::new(y),
|
|
w: Dimension::new(w),
|
|
h: Dimension::new(h),
|
|
color: Color::from_raw(color),
|
|
});
|
|
}
|
|
|
|
fn flush() {
|
|
display_send(&DisplayRequest::Flush);
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn main() {
|
|
let mut snake = Snake::new();
|
|
let mut commands = [RenderCommand { x: 0, y: 0, w: 0, h: 0, color: 0 }; MAX_RENDER_CMDS];
|
|
|
|
loop {
|
|
let count = renderer::render(&snake, &mut commands);
|
|
for i in 0..count {
|
|
let cmd = &commands[i];
|
|
draw_rect(cmd.x, cmd.y, cmd.w, cmd.h, cmd.color);
|
|
}
|
|
flush();
|
|
|
|
wait_tick();
|
|
handle_input(&mut snake);
|
|
snake.tick();
|
|
|
|
if snake.state() == GameState::GameOver {
|
|
let gw = renderer::grid_pixel_width();
|
|
let gh = renderer::grid_pixel_height();
|
|
draw_rect(gw / 2 - 60, gh / 2 - 12, 120, 24, 0xFF800000);
|
|
flush();
|
|
|
|
let end = Ticks::from_raw(syscall::get_time().raw() + 50_000_000);
|
|
while syscall::get_time().raw() < end.raw() { syscall::yield_now(); }
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn handle_input(snake: &mut Snake) {
|
|
let _ = syscall::send(INPUT_EP, 0, 0, 0, 0);
|
|
let (tag, kind, _, _) = syscall::receive(INPUT_EP);
|
|
|
|
if tag == 1 {
|
|
match kind {
|
|
0 => snake.set_direction(Direction::Up),
|
|
1 => snake.set_direction(Direction::Down),
|
|
2 => snake.set_direction(Direction::Left),
|
|
3 => snake.set_direction(Direction::Right),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn wait_tick() {
|
|
let start = syscall::get_time();
|
|
let deadline = Ticks::from_raw(start.raw() + TICK_DELAY);
|
|
while syscall::get_time().raw() < deadline.raw() {
|
|
syscall::yield_now();
|
|
}
|
|
}
|