limit the rendering rate to 60fps

This commit is contained in:
Jovi Hsu 2022-10-26 01:35:27 +00:00
parent 10e5ab5311
commit 8339b338e9
3 changed files with 54 additions and 33 deletions

View File

@ -15,6 +15,7 @@ wasm-bindgen = "0.2.63"
js-sys = "0.3"
x509-parser = "0.14.0"
rdp-rs = { path = "./rdp-rs", default-features = false }
wasm-timer = "0.2.5"
# websocket
ws_stream_wasm = { version = "^0.7", features = ["tokio_io"] }

View File

@ -1,22 +1,31 @@
use crate::input::{InputEvent, KeyEventType, MouseEventType};
use rdp::core::event::BitmapEvent;
use std::rc::Rc;
use std::{
cell::{Cell, RefCell},
rc::Rc,
};
use tokio::sync::mpsc;
use tracing::warn;
use wasm_bindgen::prelude::*;
use wasm_bindgen::{Clamped, JsCast};
use wasm_timer::Instant;
use web_sys::{
CanvasRenderingContext2d, HtmlButtonElement, HtmlCanvasElement, KeyboardEvent, MouseEvent,
};
const MILLIS_IN_SEC: u32 = 1000;
struct Canvas {
canvas: HtmlCanvasElement,
ctx: CanvasRenderingContext2d,
output: mpsc::Sender<InputEvent>,
refresh_interval: u32,
video_mem: RefCell<Vec<u8>>,
timer: Cell<Instant>,
resolution: Cell<(u32, u32)>,
}
impl Canvas {
fn new(sender: mpsc::Sender<InputEvent>) -> Self {
fn new(sender: mpsc::Sender<InputEvent>, refresh_rate: u16) -> Self {
let document = web_sys::window().unwrap().document().unwrap();
let canvas = document.get_element_by_id("rdp-canvas").unwrap();
let canvas: HtmlCanvasElement = canvas
@ -33,6 +42,10 @@ impl Canvas {
canvas,
ctx,
output: sender,
refresh_interval: MILLIS_IN_SEC / refresh_rate as u32,
video_mem: RefCell::new(Vec::new()),
timer: Cell::new(Instant::now()),
resolution: Cell::new((0, 0)),
}
}
@ -40,7 +53,11 @@ impl Canvas {
// set hight & width
self.canvas.set_height(height);
self.canvas.set_width(width);
self.video_mem
.borrow_mut()
.resize(height as usize * width as usize * 4, 0xff);
self.ctx.rect(0_f64, 0_f64, width as f64, height as f64);
self.resolution.set((width, height));
self.ctx.fill();
}
@ -225,6 +242,9 @@ impl Canvas {
.add_event_listener_with_callback("contextmenu", cb.as_ref().unchecked_ref())
.unwrap();
cb.forget();
// initilize the timer
self.timer.set(Instant::now());
}
fn draw(&self, bm: BitmapEvent) {
@ -235,45 +255,45 @@ impl Canvas {
let bitmap_width = bm.width as u32;
let bitmap_height = bm.height as u32;
let mut data = bm.decompress().unwrap();
let data = bm.decompress().unwrap();
let mut y = 0;
let mut x = 0;
let mut x;
// only update the vedio buffer
let mut video = self.video_mem.borrow_mut();
while y < bitmap_height {
x = 0;
let mut idx = (y as usize * bitmap_width as usize) * 4;
let mut d_idx = ((y + bitmap_dest_top) as usize * self.resolution.get().0 as usize
+ bitmap_dest_left as usize)
* 4;
while x < bitmap_width {
let idx = (y as usize * bitmap_width as usize + x as usize) * 4;
data.swap(idx, idx + 2);
data[idx + 3] = 255;
video[d_idx] = data[idx + 2];
video[d_idx + 1] = data[idx + 1];
video[d_idx + 2] = data[idx];
idx += 4;
d_idx += 4;
x += 1;
}
x = 0;
y += 1;
}
let data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(
Clamped(&data),
bitmap_width as u32,
bitmap_height as u32,
);
if data.is_err() {
warn!(
"renderring failed at ({}, {}), width {}, height {}",
bitmap_dest_left, bitmap_dest_top, bitmap_width, bitmap_height,
);
if self.timer.get().elapsed().as_millis() < self.refresh_interval as u128 {
// if the time elapsed has not exceeded the refresh_interval
// return to decrease the calling of render
return;
} else {
//
// trace!(
// "draw x:{}-{}, y:{}-{}",
// bitmap_dest_left,
// bitmap_dest_right,
// bitmap_dest_top,
// bitmap_dest_bottom
// );
self.timer.set(Instant::now());
}
let data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(
Clamped(&video),
self.resolution.get().0,
self.resolution.get().1,
);
let data = data.unwrap();
let _ = self
.ctx
.put_image_data(&data, bitmap_dest_left as f64, bitmap_dest_top as f64);
let _ = self.ctx.put_image_data(&data, 0_f64, 0_f64);
}
fn close(&self) {
@ -294,9 +314,9 @@ impl Clone for CanvasUtils {
}
impl CanvasUtils {
pub fn new(sender: mpsc::Sender<InputEvent>) -> Self {
pub fn new(sender: mpsc::Sender<InputEvent>, refresh_rate: u16) -> Self {
Self {
inner: Rc::new(Canvas::new(sender)),
inner: Rc::new(Canvas::new(sender, refresh_rate)),
}
}

View File

@ -94,7 +94,7 @@ impl Rdp {
let mut rdp_client = self.rdp_client.take().unwrap();
let (canvas_sender, mut rdp_reciver) = mpsc::channel(100);
let canvas = canvas::CanvasUtils::new(canvas_sender);
let canvas = canvas::CanvasUtils::new(canvas_sender, 60);
canvas.init(self.screen.0 as u32, self.screen.1 as u32);
'main: loop {
tokio::select! {