mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-04 18:10:18 +00:00
Further implement framebuffer
This commit is contained in:
parent
85358a84ae
commit
8c56ee682e
@ -1,18 +1,22 @@
|
||||
use ref_thread_local::{ref_thread_local, refmanager::RefMut, RefThreadLocal};
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use wasmer_wasi::state::{WasiFile, WasiFs, ALL_RIGHTS, VIRTUAL_ROOT_FD};
|
||||
|
||||
use minifb::{Key, Scale, Window, WindowOptions};
|
||||
use minifb::{Key, KeyRepeat, MouseButton, Scale, Window, WindowOptions};
|
||||
|
||||
ref_thread_local! {
|
||||
pub(crate) static managed FRAMEBUFFER_STATE: FrameBufferState =
|
||||
FrameBufferState::new();
|
||||
mod util;
|
||||
|
||||
use util::*;
|
||||
|
||||
use std::cell::RefCell;
|
||||
std::thread_local! {
|
||||
pub(crate) static FRAMEBUFFER_STATE: RefCell<FrameBufferState> =
|
||||
RefCell::new(FrameBufferState::new()
|
||||
);
|
||||
}
|
||||
|
||||
fn get_fb_state<'a>() -> RefMut<'a, FrameBufferState> {
|
||||
FRAMEBUFFER_STATE.borrow_mut()
|
||||
}
|
||||
use std::borrow::BorrowMut;
|
||||
|
||||
pub const MAX_X: u32 = 8192;
|
||||
pub const MAX_Y: u32 = 4320;
|
||||
@ -36,9 +40,15 @@ pub(crate) struct FrameBufferState {
|
||||
pub front_buffer: bool,
|
||||
|
||||
pub window: Window,
|
||||
|
||||
pub last_mouse_pos: (u32, u32),
|
||||
pub inputs: VecDeque<InputEvent>,
|
||||
}
|
||||
|
||||
impl FrameBufferState {
|
||||
/// an arbitrary large number
|
||||
const MAX_INPUTS: usize = 128;
|
||||
|
||||
pub fn new() -> Self {
|
||||
let x = 100;
|
||||
let y = 200;
|
||||
@ -54,6 +64,8 @@ impl FrameBufferState {
|
||||
front_buffer: true,
|
||||
|
||||
window,
|
||||
last_mouse_pos: (0, 0),
|
||||
inputs: VecDeque::with_capacity(Self::MAX_INPUTS),
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +76,7 @@ impl FrameBufferState {
|
||||
y,
|
||||
WindowOptions {
|
||||
resize: true,
|
||||
scale: Scale::X1,
|
||||
scale: Scale::X4,
|
||||
..WindowOptions::default()
|
||||
},
|
||||
)
|
||||
@ -86,6 +98,56 @@ impl FrameBufferState {
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn push_input_event(&mut self, input_event: InputEvent) -> Option<()> {
|
||||
if self.inputs.len() >= Self::MAX_INPUTS {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.inputs.push_back(input_event);
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn fill_input_buffer(&mut self) -> Option<()> {
|
||||
let keys = self.window.get_keys_pressed(KeyRepeat::Yes)?;
|
||||
for key in keys {
|
||||
self.push_input_event(InputEvent::KeyPress(key))?;
|
||||
}
|
||||
|
||||
let mouse_position = self.window.get_mouse_pos(minifb::MouseMode::Clamp)?;
|
||||
if mouse_position.0 as u32 != self.last_mouse_pos.0
|
||||
|| mouse_position.1 as u32 != self.last_mouse_pos.1
|
||||
{
|
||||
self.last_mouse_pos = (mouse_position.0 as u32, mouse_position.1 as u32);
|
||||
self.push_input_event(InputEvent::MouseMoved(
|
||||
self.last_mouse_pos.0,
|
||||
self.last_mouse_pos.1,
|
||||
))?;
|
||||
}
|
||||
|
||||
if self.window.get_mouse_down(MouseButton::Left) {
|
||||
self.push_input_event(InputEvent::MouseEvent(
|
||||
mouse_position.0 as u32,
|
||||
mouse_position.1 as u32,
|
||||
MouseButton::Left,
|
||||
))?;
|
||||
}
|
||||
if self.window.get_mouse_down(MouseButton::Right) {
|
||||
self.push_input_event(InputEvent::MouseEvent(
|
||||
mouse_position.0 as u32,
|
||||
mouse_position.1 as u32,
|
||||
MouseButton::Right,
|
||||
))?;
|
||||
}
|
||||
if self.window.get_mouse_down(MouseButton::Middle) {
|
||||
self.push_input_event(InputEvent::MouseEvent(
|
||||
mouse_position.0 as u32,
|
||||
mouse_position.1 as u32,
|
||||
MouseButton::Middle,
|
||||
))?;
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn draw(&mut self) {
|
||||
self.window.update_with_buffer(if self.front_buffer {
|
||||
&self.data_1[..]
|
||||
@ -165,52 +227,70 @@ pub struct FrameBuffer {
|
||||
|
||||
impl Read for FrameBuffer {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let fb_state = get_fb_state();
|
||||
let cursor = self.cursor as usize;
|
||||
match self.fb_type {
|
||||
FrameBufferFileType::Buffer => {
|
||||
let mut bytes_copied = 0;
|
||||
FRAMEBUFFER_STATE.with(|fb| {
|
||||
let mut fb_state = fb.borrow_mut();
|
||||
match self.fb_type {
|
||||
FrameBufferFileType::Buffer => {
|
||||
let mut bytes_copied = 0;
|
||||
|
||||
for i in 0..buf.len() {
|
||||
if let Some(byte) = fb_state.get_byte(cursor + i) {
|
||||
buf[i] = byte;
|
||||
bytes_copied += 1;
|
||||
for i in 0..buf.len() {
|
||||
if let Some(byte) = fb_state.get_byte(cursor + i) {
|
||||
buf[i] = byte;
|
||||
bytes_copied += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.cursor += bytes_copied;
|
||||
Ok(bytes_copied as usize)
|
||||
}
|
||||
FrameBufferFileType::Resolution => {
|
||||
let resolution_data = format!("{}x{}", fb_state.x_size, fb_state.y_size);
|
||||
|
||||
let mut bytes = resolution_data.bytes().skip(cursor);
|
||||
let bytes_to_copy = std::cmp::min(buf.len(), bytes.clone().count());
|
||||
|
||||
for i in 0..bytes_to_copy {
|
||||
buf[i] = bytes.next().unwrap();
|
||||
}
|
||||
|
||||
self.cursor += bytes_to_copy as u32;
|
||||
Ok(bytes_to_copy)
|
||||
}
|
||||
|
||||
FrameBufferFileType::IndexDisplay => {
|
||||
if buf.len() == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
break;
|
||||
buf[0] = fb_state.front_buffer as u8 + b'0';
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
|
||||
self.cursor += bytes_copied;
|
||||
Ok(bytes_copied as usize)
|
||||
}
|
||||
FrameBufferFileType::Resolution => {
|
||||
let resolution_data = format!("{}x{}", fb_state.x_size, fb_state.y_size);
|
||||
FrameBufferFileType::Input => {
|
||||
let mut idx = 0;
|
||||
fb_state.fill_input_buffer();
|
||||
|
||||
let mut bytes = resolution_data.bytes().skip(cursor);
|
||||
let bytes_to_copy = std::cmp::min(buf.len(), bytes.clone().count());
|
||||
|
||||
for i in 0..bytes_to_copy {
|
||||
buf[i] = bytes.next().unwrap();
|
||||
}
|
||||
|
||||
self.cursor += bytes_to_copy as u32;
|
||||
Ok(bytes_to_copy)
|
||||
}
|
||||
|
||||
FrameBufferFileType::IndexDisplay => {
|
||||
if buf.len() == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
buf[0] = fb_state.front_buffer as u8 + b'0';
|
||||
Ok(1)
|
||||
while let Some(next_elem) = fb_state.inputs.front() {
|
||||
let remaining_length = buf.len() - idx;
|
||||
let (tag_byte, data, size) = bytes_for_input_event(*next_elem);
|
||||
if remaining_length > 1 + size {
|
||||
buf[idx] = tag_byte;
|
||||
for i in 0..size {
|
||||
buf[idx + 1 + i] = data[i];
|
||||
}
|
||||
idx += 1 + size;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
fb_state.inputs.pop_front().unwrap();
|
||||
}
|
||||
Ok(idx)
|
||||
}
|
||||
}
|
||||
|
||||
FrameBufferFileType::Input => {
|
||||
// do input
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> std::io::Result<usize> {
|
||||
@ -249,66 +329,70 @@ impl Seek for FrameBuffer {
|
||||
|
||||
impl Write for FrameBuffer {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let mut fb_state = get_fb_state();
|
||||
let cursor = self.cursor as usize;
|
||||
match self.fb_type {
|
||||
FrameBufferFileType::Buffer => {
|
||||
let mut bytes_copied = 0;
|
||||
FRAMEBUFFER_STATE.with(|fb| {
|
||||
let mut fb_state = fb.borrow_mut();
|
||||
match self.fb_type {
|
||||
FrameBufferFileType::Buffer => {
|
||||
let mut bytes_copied = 0;
|
||||
|
||||
for i in 0..buf.len() {
|
||||
if fb_state.set_byte(cursor + i, buf[i]).is_none() {
|
||||
// TODO: check if we should return an error here
|
||||
break;
|
||||
for i in 0..buf.len() {
|
||||
if fb_state.set_byte(cursor + i, buf[i]).is_none() {
|
||||
// TODO: check if we should return an error here
|
||||
break;
|
||||
}
|
||||
bytes_copied += 1;
|
||||
}
|
||||
bytes_copied += 1;
|
||||
}
|
||||
|
||||
self.cursor += bytes_copied;
|
||||
Ok(bytes_copied as usize)
|
||||
}
|
||||
FrameBufferFileType::Resolution => {
|
||||
let resolution_data = format!("{}x{}", fb_state.x_size, fb_state.y_size);
|
||||
let mut byte_vec: Vec<u8> = resolution_data.bytes().collect();
|
||||
let upper_limit = std::cmp::min(buf.len(), byte_vec.len() - cursor as usize);
|
||||
self.cursor += bytes_copied;
|
||||
Ok(bytes_copied as usize)
|
||||
}
|
||||
FrameBufferFileType::Resolution => {
|
||||
let resolution_data = format!("{}x{}", fb_state.x_size, fb_state.y_size);
|
||||
let mut byte_vec: Vec<u8> = resolution_data.bytes().collect();
|
||||
let upper_limit = std::cmp::min(buf.len(), byte_vec.len() - cursor as usize);
|
||||
|
||||
for i in 0..upper_limit {
|
||||
byte_vec[i] = buf[i];
|
||||
}
|
||||
|
||||
let mut parse_str = String::new();
|
||||
for b in byte_vec.iter() {
|
||||
parse_str.push(*b as char);
|
||||
}
|
||||
let result: Vec<&str> = parse_str.split('x').collect();
|
||||
if result.len() != 2 {
|
||||
return Ok(0);
|
||||
}
|
||||
if let Ok((n1, n2)) = result[0]
|
||||
.parse::<u32>()
|
||||
.and_then(|n1| result[1].parse::<u32>().map(|n2| (n1, n2)))
|
||||
{
|
||||
if fb_state.resize(n1, n2).is_some() {
|
||||
return Ok(upper_limit);
|
||||
for i in 0..upper_limit {
|
||||
byte_vec[i] = buf[i];
|
||||
}
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
FrameBufferFileType::IndexDisplay => {
|
||||
if buf.len() == 0 {
|
||||
let mut parse_str = String::new();
|
||||
for b in byte_vec.iter() {
|
||||
parse_str.push(*b as char);
|
||||
}
|
||||
let result: Vec<&str> = parse_str.split('x').collect();
|
||||
if result.len() != 2 {
|
||||
return Ok(0);
|
||||
}
|
||||
if let Ok((n1, n2)) = result[0]
|
||||
.parse::<u32>()
|
||||
.and_then(|n1| result[1].parse::<u32>().map(|n2| (n1, n2)))
|
||||
{
|
||||
if fb_state.resize(n1, n2).is_some() {
|
||||
return Ok(upper_limit);
|
||||
}
|
||||
}
|
||||
Ok(0)
|
||||
} else {
|
||||
match buf[0] {
|
||||
b'0' => fb_state.front_buffer = true,
|
||||
b'1' => fb_state.front_buffer = false,
|
||||
_ => (),
|
||||
}
|
||||
fb_state.draw();
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
FrameBufferFileType::IndexDisplay => {
|
||||
if buf.len() == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
match buf[0] {
|
||||
b'0' => fb_state.front_buffer = true,
|
||||
b'1' => fb_state.front_buffer = false,
|
||||
_ => (),
|
||||
}
|
||||
// TODO: probably remove this
|
||||
//fb_state.fill_input_buffer();
|
||||
fb_state.draw();
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
FrameBufferFileType::Input => Ok(0),
|
||||
}
|
||||
FrameBufferFileType::Input => Ok(0),
|
||||
}
|
||||
})
|
||||
}
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
|
@ -1 +1,181 @@
|
||||
// input encoding
|
||||
|
||||
pub const KEY_PRESS: u8 = 1;
|
||||
pub const MOUSE_MOVE: u8 = 2;
|
||||
pub const MOUSE_PRESS_LEFT: u8 = 4;
|
||||
pub const MOUSE_PRESS_RIGHT: u8 = 5;
|
||||
pub const MOUSE_PRESS_MIDDLE: u8 = 7;
|
||||
|
||||
use minifb::{Key, MouseButton};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum InputEvent {
|
||||
KeyPress(Key),
|
||||
MouseEvent(u32, u32, MouseButton),
|
||||
MouseMoved(u32, u32),
|
||||
}
|
||||
|
||||
/// Returns the tag as the first return value
|
||||
/// The data as the second return value
|
||||
/// and the amount of data to read from it as the third value
|
||||
pub fn bytes_for_input_event(input_event: InputEvent) -> (u8, [u8; 8], usize) {
|
||||
let mut data = [0u8; 8];
|
||||
match input_event {
|
||||
InputEvent::KeyPress(k) => {
|
||||
data[0] = map_key_to_bytes(k);
|
||||
(KEY_PRESS, data, 1)
|
||||
}
|
||||
InputEvent::MouseEvent(x, y, btn) => {
|
||||
let tag = match btn {
|
||||
MouseButton::Left => MOUSE_PRESS_LEFT,
|
||||
MouseButton::Right => MOUSE_PRESS_RIGHT,
|
||||
MouseButton::Middle => MOUSE_PRESS_MIDDLE,
|
||||
};
|
||||
dbg!(x);
|
||||
dbg!(y);
|
||||
let x_bytes = x.to_le_bytes();
|
||||
for i in 0..4 {
|
||||
data[i] = x_bytes[i];
|
||||
}
|
||||
let y_bytes = y.to_le_bytes();
|
||||
for i in 0..4 {
|
||||
data[i + 4] = y_bytes[i];
|
||||
}
|
||||
(tag, data, 8)
|
||||
}
|
||||
InputEvent::MouseMoved(x, y) => {
|
||||
let x_bytes = x.to_le_bytes();
|
||||
for i in 0..4 {
|
||||
data[i] = x_bytes[i];
|
||||
}
|
||||
let y_bytes = y.to_le_bytes();
|
||||
for i in 0..4 {
|
||||
data[i + 4] = y_bytes[i];
|
||||
}
|
||||
(MOUSE_MOVE, data, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_key_to_bytes(key: Key) -> u8 {
|
||||
match key {
|
||||
Key::Key0 => b'0',
|
||||
Key::Key1 => b'1',
|
||||
Key::Key2 => b'2',
|
||||
Key::Key3 => b'3',
|
||||
Key::Key4 => b'4',
|
||||
Key::Key5 => b'5',
|
||||
Key::Key6 => b'6',
|
||||
Key::Key7 => b'7',
|
||||
Key::Key8 => b'8',
|
||||
Key::Key9 => b'9',
|
||||
Key::A => b'A',
|
||||
Key::B => b'B',
|
||||
Key::C => b'C',
|
||||
Key::D => b'D',
|
||||
Key::E => b'E',
|
||||
Key::F => b'F',
|
||||
Key::G => b'G',
|
||||
Key::H => b'H',
|
||||
Key::I => b'I',
|
||||
Key::J => b'J',
|
||||
Key::K => b'K',
|
||||
Key::L => b'L',
|
||||
Key::M => b'M',
|
||||
Key::N => b'N',
|
||||
Key::O => b'O',
|
||||
Key::P => b'P',
|
||||
Key::Q => b'Q',
|
||||
Key::R => b'R',
|
||||
Key::S => b'S',
|
||||
Key::T => b'T',
|
||||
Key::U => b'U',
|
||||
Key::V => b'V',
|
||||
Key::W => b'W',
|
||||
Key::X => b'X',
|
||||
Key::Y => b'Y',
|
||||
Key::Z => b'Z',
|
||||
Key::F1 => 131,
|
||||
Key::F2 => 132,
|
||||
Key::F3 => 133,
|
||||
Key::F4 => 134,
|
||||
Key::F5 => 135,
|
||||
Key::F6 => 136,
|
||||
Key::F7 => 137,
|
||||
Key::F8 => 138,
|
||||
Key::F9 => 139,
|
||||
Key::F10 => 140,
|
||||
Key::F11 => 141,
|
||||
Key::F12 => 142,
|
||||
Key::F13 => 143,
|
||||
Key::F14 => 144,
|
||||
Key::F15 => 145,
|
||||
|
||||
Key::Down => 146,
|
||||
Key::Left => 147,
|
||||
Key::Right => 148,
|
||||
Key::Up => 149,
|
||||
Key::Apostrophe => b'\'',
|
||||
Key::Backquote => b'`',
|
||||
|
||||
Key::Backslash => b'\\',
|
||||
Key::Comma => b',',
|
||||
Key::Equal => b'=',
|
||||
Key::LeftBracket => b'[',
|
||||
Key::Minus => b'-',
|
||||
Key::Period => b'.',
|
||||
Key::RightBracket => b']',
|
||||
Key::Semicolon => b';',
|
||||
|
||||
Key::Slash => b'/',
|
||||
Key::Backspace => 128,
|
||||
Key::Delete => 127,
|
||||
Key::End => 150,
|
||||
Key::Enter => b'\n',
|
||||
|
||||
Key::Escape => 28,
|
||||
|
||||
Key::Home => 151,
|
||||
Key::Insert => 152,
|
||||
Key::Menu => 153,
|
||||
|
||||
Key::PageDown => 154,
|
||||
Key::PageUp => 155,
|
||||
|
||||
Key::Pause => 156,
|
||||
Key::Space => b' ',
|
||||
Key::Tab => b'\t',
|
||||
Key::NumLock => 157,
|
||||
Key::CapsLock => 158,
|
||||
Key::ScrollLock => 159,
|
||||
Key::LeftShift => 160,
|
||||
Key::RightShift => 161,
|
||||
Key::LeftCtrl => 162,
|
||||
Key::RightCtrl => 163,
|
||||
|
||||
Key::NumPad0 => 170,
|
||||
Key::NumPad1 => 171,
|
||||
Key::NumPad2 => 172,
|
||||
Key::NumPad3 => 173,
|
||||
Key::NumPad4 => 174,
|
||||
Key::NumPad5 => 175,
|
||||
Key::NumPad6 => 176,
|
||||
Key::NumPad7 => 177,
|
||||
Key::NumPad8 => 178,
|
||||
Key::NumPad9 => 179,
|
||||
Key::NumPadDot => 180,
|
||||
Key::NumPadSlash => 181,
|
||||
Key::NumPadAsterisk => 182,
|
||||
Key::NumPadMinus => 183,
|
||||
Key::NumPadPlus => 184,
|
||||
Key::NumPadEnter => 185,
|
||||
|
||||
Key::LeftAlt => 186,
|
||||
Key::RightAlt => 187,
|
||||
|
||||
Key::LeftSuper => 188,
|
||||
Key::RightSuper => 189,
|
||||
|
||||
_ => 255,
|
||||
}
|
||||
}
|
||||
|
@ -188,6 +188,10 @@ struct Run {
|
||||
#[structopt(flatten)]
|
||||
features: PrestandardFeatures,
|
||||
|
||||
#[cfg(feature = "experimental-framebuffer")]
|
||||
#[structopt(long = "enable-experimental-framebuffer")]
|
||||
enable_experimental_framebuffer: bool,
|
||||
|
||||
/// Application arguments
|
||||
#[structopt(name = "--", raw(multiple = "true"))]
|
||||
args: Vec<String>,
|
||||
@ -597,7 +601,13 @@ fn execute_wasm(options: &Run) -> Result<(), String> {
|
||||
options.pre_opened_directories.clone(),
|
||||
mapped_dirs,
|
||||
#[cfg(feature = "experimental-framebuffer")]
|
||||
Some(Box::new(wasmer_wasi_framebuffer::initialize)),
|
||||
{
|
||||
if options.enable_experimental_framebuffer {
|
||||
Some(Box::new(wasmer_wasi_framebuffer::initialize))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
#[cfg(not(feature = "experimental-framebuffer"))]
|
||||
None,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user