mirror of
https://github.com/exoticorn/microw8.git
synced 2026-11-13 23:17:19 +01:00
optimize hline function, update wasmtime
This commit is contained in:
1 parent
e0450c9039
commit
caeaa82787
12 files changed
+845
-656
No files matched your search
+1
-4
@@ -14,9 +14,6 @@ use anyhow::Result;
|
||||
|
||||
pub trait Runtime {
|
||||
fn is_open(&self) -> bool;
|
||||
fn set_timeout(&mut self, _timeout: u32) {
|
||||
eprintln!("Warning: runtime doesn't support timeout");
|
||||
}
|
||||
fn load(&mut self, module_data: &[u8]) -> Result<()>;
|
||||
fn run_frame(&mut self) -> Result<()>;
|
||||
}
|
||||
}
|
||||
+2
-5
@@ -52,6 +52,7 @@ fn main() -> Result<()> {
|
||||
#[cfg(any(feature = "native", feature = "browser"))]
|
||||
fn run(mut args: Arguments) -> Result<()> {
|
||||
let watch_mode = args.contains(["-w", "--watch"]);
|
||||
#[allow(unused)]
|
||||
let timeout: Option<u32> = args.opt_value_from_str(["-t", "--timeout"])?;
|
||||
|
||||
let mut config = Config::default();
|
||||
@@ -92,7 +93,7 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
unimplemented!();
|
||||
#[cfg(feature = "native")]
|
||||
{
|
||||
let mut microw8 = MicroW8::new()?;
|
||||
let mut microw8 = MicroW8::new(timeout)?;
|
||||
if disable_audio {
|
||||
microw8.disable_audio();
|
||||
}
|
||||
@@ -105,10 +106,6 @@ fn run(mut args: Arguments) -> Result<()> {
|
||||
Box::new(RunWebServer::new())
|
||||
};
|
||||
|
||||
if let Some(timeout) = timeout {
|
||||
runtime.set_timeout(timeout);
|
||||
}
|
||||
|
||||
let mut first_run = true;
|
||||
|
||||
while runtime.is_open() {
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>body,canvas,html{background-color:#202024;margin:0;padding:0}body,html{height:100%}body{display:grid;grid-template-rows:1fr}#screen{align-self:center;border:4px solid #303040;image-rendering:pixelated;justify-self:center}#message{background-color:rgba(0,0,0,.4);color:#c64;font:700 12pt sans-serif;padding:8px;position:absolute;width:calc(100% - 16px);z-index:2}@media (min-width:648px) and (min-height:488px){#screen{height:480px;width:640px}}@media (min-width:968px) and (min-height:728px){#screen{height:720px;width:960px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}class t extends AudioWorkletNode{constructor(e){super(e,"apu",{outputChannelCount:[2]})}}let A=(...e)=>new Uint8Array(...e),s=(...e)=>new Uint32Array(...e);let a=function(a,B={}){B.setMessage||(B.setMessage=(e,t)=>{t&&console.log("error: "+t)});let n,r,o,i,l,d,u,g,D=a.getContext("2d"),c=D.createImageData(320,240),F=B.devkitMode,f=0,C=null==B.keyboardElement?a:B.keyboardElement;if(C){let e=e=>{let t,A="keydown"==e.type;switch(e.code){case"ArrowUp":t=1;break;case"ArrowDown":t=2;break;case"ArrowLeft":t=4;break;case"ArrowRight":t=8;break;case"KeyZ":t=16;break;case"KeyX":t=32;break;case"KeyA":t=64;break;case"KeyS":t=128;break;case"KeyR":A&&E(r,!0);break;case"F9":A&&a.toBlob((e=>{Q(e,".png")})),e.preventDefault();break;case"F10":A&&function(){if(l)return l.stop(),l=null,u.disconnect(g),u=null,void(g=null);let e=a.captureStream();g=o.createMediaStreamDestination(),u=i,i.connect(g),e.addTrack(g.stream.getAudioTracks()[0]),l=new MediaRecorder(e,{mimeType:"video/webm",videoBitsPerSecond:25e6});let t=[];l.ondataavailable=e=>{t.push(e.data)};let A=B.timerElement;A&&(A.hidden=!1,A.innerText="00:00");function s(){if(d){if(A){let e=Math.floor((Date.now()-d)/1e3);A.innerText=Math.floor(e/60).toString().padStart(2,"0")+":"+(e%60).toString().padStart(2,"0")}setTimeout(s,1e3)}}l.onstop=()=>{A&&(A.hidden=!0),Q(new Blob(t,{type:"video/webm"}),".webm")},l.start(),d=Date.now(),setTimeout(s,1e3)}(),e.preventDefault()}A?f|=t:f&=~t};C.onkeydown=e,C.onkeyup=e}async function E(l,d){n&&(n(),n=null),o=new AudioContext({sampleRate:44100});let u=!0,g=new AbortController;n=()=>{o.close(),u=!1,g.abort()};let C=l.byteLength;if(B.setMessage(C),0==C)return;await o.audioWorklet.addModule(e("data:application/javascript,let%20e%3D%28...e%29%3D%3Enew%20Uint8Array%28...e%29%3Bclass%20s%20extends%20AudioWorkletProcessor%7Bconstructor%28%29%7Bsuper%28%29%2Cthis.sampleIndex%3D0%2Cthis.currentTime%3D0%2Cthis.isFirstMessage%3D%210%2Cthis.pendingUpdates%3D%5B%5D%2Cthis.port.onmessage%3De%3D%3E%7Bthis.memory%3F%28this.isFirstMessage%26%26%28this.currentTime%2B%3D%28e.data.t-this.currentTime%29%2F8%2Cthis.isFirstMessage%3D%211%29%2Cthis.pendingUpdates.push%28e.data%29%29%3Athis.load%28e.data%5B0%5D%2Ce.data%5B1%5D%29%7D%7Dasync%20load%28e%2Cs%29%7Blet%20t%3Dnew%20WebAssembly.Memory%28%7Binitial%3A4%2Cmaximum%3A4%7D%29%2Ci%3D%7Benv%3A%7Bmemory%3At%7D%7D%3Bfor%28let%20e%20of%5B%22acos%22%2C%22asin%22%2C%22atan%22%2C%22atan2%22%2C%22cos%22%2C%22exp%22%2C%22log%22%2C%22sin%22%2C%22tan%22%2C%22pow%22%5D%29i.env%5Be%5D%3DMath%5Be%5D%3Bfor%28let%20e%3D9%3Be%3C64%3B%2B%2Be%29i.env%5B%22reserved%22%2Be%5D%3D%28%29%3D%3E%7B%7D%3Blet%20r%3D%22%22%3Bi.env.logChar%3De%3D%3E%7B10%3D%3De%3F%28console.log%28r%29%2Cr%3D%22%22%29%3Ar%2B%3DString.fromCharCode%28e%29%7D%3Bfor%28let%20e%3D0%3Be%3C16%3B%2B%2Be%29i.env%5B%22g_reserved%22%2Be%5D%3D0%3Blet%20n%3Dasync%20e%3D%3E%28await%20WebAssembly.instantiate%28e%2Ci%29%29.instance%2Ca%3Dawait%20n%28e%29%3Bfor%28let%20e%20in%20a.exports%29i.env%5Be%5D%3Da.exports%5Be%5D%3Blet%20o%3Dawait%20n%28s%29%3Bthis.memory%3Dt%2Cthis.snd%3Do.exports.snd%7C%7Ca.exports.gesSnd%2Cthis.port.postMessage%282%29%7Dprocess%28s%2Ct%2Ci%29%7Bif%28this.isFirstMessage%3D%210%2Cthis.snd%29%7Bfor%28%3Bthis.pendingUpdates.length%3E0%26%26this.pendingUpdates%5B0%5D.t%3C%3Dthis.currentTime%3B%29e%28this.memory.buffer%2C80%2C32%29.set%28e%28this.pendingUpdates.shift%28%29.r%29%29%3Bnew%20Uint32Array%28this.memory.buffer%29%5B16%5D%3Dthis.currentTime%3Blet%20s%3Dt%5B0%5D%2Ci%3Dthis.sampleIndex%2Cr%3Ds%5B0%5D.length%3Bfor%28let%20e%3D0%3Be%3Cr%3B%2B%2Be%29s%5B0%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%2Cs%5B1%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%3Bthis.sampleIndex%3D4294967295%26i%2Cthis.currentTime%2B%3Dr%2F44.1%7Dreturn%210%7D%7DregisterProcessor%28%22apu%22%2Cs%29%3B")),i=new t(o);let Q,m=0,I=new Promise((e=>Q=e)),b=e=>{m|=e,3==m&&Q&&(Q(!0),Q=null)},h=()=>{"suspended"==o.state?(B.startButton&&(B.startButton.style="",a.style="display:none"),(B.startButton||a).onclick=()=>{o.resume()}):(B.startButton&&(B.startButton.style="display:none",a.style=""),b(1))};o.onstatechange=h,h(),r=l;let w=window.location.pathname;if(C<=1024&&!d){let e="";for(let t of A(l))e+=String.fromCharCode(t);w+="#"Line truncated
|
||||
<!doctype html><html><head><meta charset="utf8"><title>uw8-run</title><style>html,body,canvas{background-color:#202024;margin:0;padding:0}html{height:100%}body{height:100%;grid-template-rows:1fr;display:grid}#screen{image-rendering:pixelated;border:4px solid #303040;place-self:center}#message{width:calc(100% - 16px);color:#c64;z-index:2;background-color:#0006;padding:8px;font:700 12pt sans-serif;position:absolute}@media (min-width:648px) and (min-height:488px){#screen{width:640px;height:480px}}@media (min-width:968px) and (min-height:728px){#screen{width:960px;height:720px}}</style></head><body> <canvas id="screen" width="320" height="240" tabindex="1"> </canvas> <div id="message"></div> </body><script type="module">function e(e){return e&&e.__esModule?e.default:e}class t extends AudioWorkletNode{constructor(e){super(e,"apu",{outputChannelCount:[2]})}}let A=(...e)=>new Uint8Array(...e),a=(...e)=>new Uint32Array(...e);let s=function(s,B={}){B.setMessage||(B.setMessage=(e,t)=>{t&&console.log("error: "+t)});let n,r,o,i,l,F,d,g,C=s.getContext("2d"),u=C.createImageData(320,240),D=B.devkitMode,c=0,f=null==B.keyboardElement?s:B.keyboardElement;if(f){let e=e=>{let t,A="keydown"==e.type;switch(e.code){case"ArrowUp":t=1;break;case"ArrowDown":t=2;break;case"ArrowLeft":t=4;break;case"ArrowRight":t=8;break;case"KeyZ":t=16;break;case"KeyX":t=32;break;case"KeyA":t=64;break;case"KeyS":t=128;break;case"KeyR":A&&w(r,!0);break;case"F9":A&&s.toBlob((e=>{I(e,".png")})),e.preventDefault();break;case"F10":A&&function(){if(l)return l.stop(),l=null,d.disconnect(g),d=null,void(g=null);let e=s.captureStream();g=o.createMediaStreamDestination(),d=i,i.connect(g),e.addTrack(g.stream.getAudioTracks()[0]),l=new MediaRecorder(e,{mimeType:"video/webm",videoBitsPerSecond:25e6});let t=[];l.ondataavailable=e=>{t.push(e.data)};let A=B.timerElement;A&&(A.hidden=!1,A.innerText="00:00");function a(){if(F){if(A){let e=Math.floor((Date.now()-F)/1e3);A.innerText=Math.floor(e/60).toString().padStart(2,"0")+":"+(e%60).toString().padStart(2,"0")}setTimeout(a,1e3)}}l.onstop=()=>{A&&(A.hidden=!0),I(new Blob(t,{type:"video/webm"}),".webm")},l.start(),F=Date.now(),setTimeout(a,1e3)}(),e.preventDefault()}A?c|=t:c&=~t};f.onkeydown=e,f.onkeyup=e}async function w(l,F){n&&(n(),n=null),o=new AudioContext({sampleRate:44100});let d=!0,g=new AbortController;n=()=>{o.close(),d=!1,g.abort()};let f=l.byteLength;if(B.setMessage(f),0==f)return;await o.audioWorklet.addModule(e("data:application/javascript,let%20e%3D%28...e%29%3D%3Enew%20Uint8Array%28...e%29%3Bclass%20s%20extends%20AudioWorkletProcessor%7Bconstructor%28%29%7Bsuper%28%29%2Cthis.sampleIndex%3D0%2Cthis.currentTime%3D0%2Cthis.isFirstMessage%3D%210%2Cthis.pendingUpdates%3D%5B%5D%2Cthis.port.onmessage%3De%3D%3E%7Bthis.memory%3F%28this.isFirstMessage%26%26%28this.currentTime%2B%3D%28e.data.t-this.currentTime%29%2F8%2Cthis.isFirstMessage%3D%211%29%2Cthis.pendingUpdates.push%28e.data%29%29%3Athis.load%28e.data%5B0%5D%2Ce.data%5B1%5D%29%7D%7Dasync%20load%28e%2Cs%29%7Blet%20t%3Dnew%20WebAssembly.Memory%28%7Binitial%3A4%2Cmaximum%3A4%7D%29%2Ci%3D%7Benv%3A%7Bmemory%3At%7D%7D%3Bfor%28let%20e%20of%5B%22acos%22%2C%22asin%22%2C%22atan%22%2C%22atan2%22%2C%22cos%22%2C%22exp%22%2C%22log%22%2C%22sin%22%2C%22tan%22%2C%22pow%22%5D%29i.env%5Be%5D%3DMath%5Be%5D%3Bfor%28let%20e%3D9%3Be%3C64%3B%2B%2Be%29i.env%5B%22reserved%22%2Be%5D%3D%28%29%3D%3E%7B%7D%3Blet%20r%3D%22%22%3Bi.env.logChar%3De%3D%3E%7B10%3D%3De%3F%28console.log%28r%29%2Cr%3D%22%22%29%3Ar%2B%3DString.fromCharCode%28e%29%7D%3Bfor%28let%20e%3D0%3Be%3C16%3B%2B%2Be%29i.env%5B%22g_reserved%22%2Be%5D%3D0%3Blet%20n%3Dasync%20e%3D%3E%28await%20WebAssembly.instantiate%28e%2Ci%29%29.instance%2Ca%3Dawait%20n%28e%29%3Bfor%28let%20e%20in%20a.exports%29i.env%5Be%5D%3Da.exports%5Be%5D%3Blet%20o%3Dawait%20n%28s%29%3Bthis.memory%3Dt%2Cthis.snd%3Do.exports.snd%7C%7Ca.exports.gesSnd%2Cthis.port.postMessage%282%29%7Dprocess%28s%2Ct%2Ci%29%7Bif%28this.isFirstMessage%3D%210%2Cthis.snd%29%7Bfor%28%3Bthis.pendingUpdates.length%3E0%26%26this.pendingUpdates%5B0%5D.t%3C%3Dthis.currentTime%3B%29e%28this.memory.buffer%2C80%2C32%29.set%28e%28this.pendingUpdates.shift%28%29.r%29%29%3Bnew%20Uint32Array%28this.memory.buffer%29%5B16%5D%3Dthis.currentTime%3Blet%20s%3Dt%5B0%5D%2Ci%3Dthis.sampleIndex%2Cr%3Ds%5B0%5D.length%3Bfor%28let%20e%3D0%3Be%3Cr%3B%2B%2Be%29s%5B0%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%2Cs%5B1%5D%5Be%5D%3Dthis.snd%28i%2B%2B%29%3Bthis.sampleIndex%3D4294967295%26i%2Cthis.currentTime%2B%3Dr%2F44.1%7Dreturn%210%7D%7DregisterProcessor%28%22apu%22%2Cs%29%3B")),i=new t(o);let I,h=0,Q=new Promise((e=>I=e)),m=e=>{h|=e,3==h&&I&&(I(!0),I=null)},M=()=>{"suspended"==o.state?(B.startButton&&(B.startButton.style="",s.style="display:none"),(B.startButton||s).onclick=()=>{o.resume()}):(B.startButton&&(B.startButton.style="display:none",s.style=""),m(1))};o.onstatechange=M,M(),r=l;let E=window.location.pathname;if(f<=1024&&!F){let e="";for(let t of A(l))e+=String.fromCharCode(t);E+="#"+btoa(e),E!=window.locLine truncated
|
||||
+19
-28
@@ -52,17 +52,23 @@ impl Drop for UW8Instance {
|
||||
}
|
||||
|
||||
struct UW8WatchDog {
|
||||
interupt: wasmtime::InterruptHandle,
|
||||
timeout: u32,
|
||||
engine: Engine,
|
||||
stop: bool,
|
||||
}
|
||||
|
||||
impl MicroW8 {
|
||||
pub fn new() -> Result<MicroW8> {
|
||||
pub fn new(timeout: Option<u32>) -> Result<MicroW8> {
|
||||
#[cfg(target_os = "windows")]
|
||||
unsafe { winapi::um::timeapi::timeBeginPeriod(1); }
|
||||
unsafe {
|
||||
winapi::um::timeapi::timeBeginPeriod(1);
|
||||
}
|
||||
|
||||
let engine = wasmtime::Engine::new(wasmtime::Config::new().interruptable(true))?;
|
||||
let mut config = wasmtime::Config::new();
|
||||
config.cranelift_opt_level(wasmtime::OptLevel::Speed);
|
||||
if timeout.is_some() {
|
||||
config.epoch_interruption(true);
|
||||
}
|
||||
let engine = wasmtime::Engine::new(&config)?;
|
||||
|
||||
let loader_module =
|
||||
wasmtime::Module::new(&engine, include_bytes!("../platform/bin/loader.wasm"))?;
|
||||
@@ -81,7 +87,7 @@ impl MicroW8 {
|
||||
window,
|
||||
window_buffer: vec![0u32; 320 * 240],
|
||||
instance: None,
|
||||
timeout: 30,
|
||||
timeout: timeout.unwrap_or(0),
|
||||
disable_audio: false,
|
||||
})
|
||||
}
|
||||
@@ -103,14 +109,11 @@ impl super::Runtime for MicroW8 {
|
||||
self.window.is_open() && !self.window.is_key_down(Key::Escape)
|
||||
}
|
||||
|
||||
fn set_timeout(&mut self, timeout: u32) {
|
||||
self.timeout = timeout;
|
||||
}
|
||||
|
||||
fn load(&mut self, module_data: &[u8]) -> Result<()> {
|
||||
self.reset();
|
||||
|
||||
let mut store = wasmtime::Store::new(&self.engine, ());
|
||||
store.set_epoch_deadline(60);
|
||||
|
||||
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
|
||||
|
||||
@@ -136,8 +139,7 @@ impl super::Runtime for MicroW8 {
|
||||
let platform_instance = instantiate_platform(&mut linker, &mut store, &platform_module)?;
|
||||
|
||||
let watchdog = Arc::new(Mutex::new(UW8WatchDog {
|
||||
interupt: store.interrupt_handle()?,
|
||||
timeout: self.timeout,
|
||||
engine: self.engine.clone(),
|
||||
stop: false,
|
||||
}));
|
||||
|
||||
@@ -145,16 +147,11 @@ impl super::Runtime for MicroW8 {
|
||||
let watchdog = watchdog.clone();
|
||||
thread::spawn(move || loop {
|
||||
thread::sleep(Duration::from_millis(17));
|
||||
if let Ok(mut watchdog) = watchdog.lock() {
|
||||
if let Ok(watchdog) = watchdog.lock() {
|
||||
if watchdog.stop {
|
||||
break;
|
||||
}
|
||||
if watchdog.timeout > 0 {
|
||||
watchdog.timeout -= 1;
|
||||
if watchdog.timeout == 0 {
|
||||
watchdog.interupt.interrupt();
|
||||
}
|
||||
}
|
||||
watchdog.engine.increment_epoch();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
@@ -162,9 +159,6 @@ impl super::Runtime for MicroW8 {
|
||||
}
|
||||
|
||||
let instance = linker.instantiate(&mut store, &module)?;
|
||||
if let Ok(mut watchdog) = watchdog.lock() {
|
||||
watchdog.timeout = 0;
|
||||
}
|
||||
let end_frame = platform_instance.get_typed_func::<(), (), _>(&mut store, "endFrame")?;
|
||||
let update = instance.get_typed_func::<(), (), _>(&mut store, "upd").ok();
|
||||
|
||||
@@ -232,15 +226,10 @@ impl super::Runtime for MicroW8 {
|
||||
mem[68..72].copy_from_slice(&gamepad.to_le_bytes());
|
||||
}
|
||||
|
||||
if let Ok(mut watchdog) = instance.watchdog.lock() {
|
||||
watchdog.timeout = self.timeout;
|
||||
}
|
||||
instance.store.set_epoch_deadline(self.timeout as u64);
|
||||
if let Some(ref update) = instance.update {
|
||||
result = update.call(&mut instance.store, ());
|
||||
}
|
||||
if let Ok(mut watchdog) = instance.watchdog.lock() {
|
||||
watchdog.timeout = 0;
|
||||
}
|
||||
instance.end_frame.call(&mut instance.store, ())?;
|
||||
|
||||
let memory = instance.memory.data(&instance.store);
|
||||
@@ -357,6 +346,7 @@ fn init_sound(
|
||||
module: &wasmtime::Module,
|
||||
) -> Result<Uw8Sound> {
|
||||
let mut store = wasmtime::Store::new(engine, ());
|
||||
store.set_epoch_deadline(60);
|
||||
|
||||
let memory = wasmtime::Memory::new(&mut store, MemoryType::new(4, Some(4)))?;
|
||||
|
||||
@@ -450,6 +440,7 @@ fn init_sound(
|
||||
}
|
||||
|
||||
while !outer_buffer.is_empty() {
|
||||
store.set_epoch_deadline(30);
|
||||
while pending_updates
|
||||
.first()
|
||||
.into_iter()
|
||||
|
||||
Reference in new issue
Block a user