mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
emscripten friendly sdl loop
This commit is contained in:
@@ -258,6 +258,8 @@ If running under Firefox and you hit "out of memory" on dev console, close the e
|
|||||||
|
|
||||||
To run the binary (after building) you should be fine with `node ./eden-cli.js`. For obvious reasons no Qt frontend is available on WASM, support for Vulkan is done charily via [llvmpipe2wasm](https://github.com/Devsh-Graphics-Programming/llvmpipe2wasm).
|
To run the binary (after building) you should be fine with `node ./eden-cli.js`. For obvious reasons no Qt frontend is available on WASM, support for Vulkan is done charily via [llvmpipe2wasm](https://github.com/Devsh-Graphics-Programming/llvmpipe2wasm).
|
||||||
|
|
||||||
|
If you run into the error "acorn.js can't be found" check [this associated issue](https://github.com/emscripten-core/emscripten/issues/13368), the fix in short is `npm --global install acorn`. On FreeBSD you could run `npm` under root, or you could do the sane thing and do `sudo chown -R $USER /usr/local/lib/node_modules/ /usr/local/bin/` (remember to restore permissions afterwards!) unless you wish to run `npm` under root which is generally a bad idea.
|
||||||
|
|
||||||
2026-06-09: As of writing, no Dynarmic-based JIT is possible on this target, full interpreted emulation is the only reasonable option. While there is some efforts on making a JIT like [here](https://github.com/wingo/wasm-jit) or [here](https://wingolog.org/archives/2022/08/18/just-in-time-code-generation-within-webassembly), the result is so latency expensive we're better off using an interpreter instead.
|
2026-06-09: As of writing, no Dynarmic-based JIT is possible on this target, full interpreted emulation is the only reasonable option. While there is some efforts on making a JIT like [here](https://github.com/wingo/wasm-jit) or [here](https://wingolog.org/archives/2022/08/18/just-in-time-code-generation-within-webassembly), the result is so latency expensive we're better off using an interpreter instead.
|
||||||
|
|
||||||
## Windows
|
## Windows
|
||||||
|
|||||||
@@ -77,12 +77,13 @@ if (NOT MSVC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (PLATFORM_EMSCRIPTEN)
|
if (PLATFORM_EMSCRIPTEN)
|
||||||
# 10GB is required... yikes!
|
# 10GB is required at max... yikes!
|
||||||
target_link_options(yuzu-cmd PRIVATE
|
target_link_options(yuzu-cmd PRIVATE
|
||||||
-sALLOW_MEMORY_GROWTH=1
|
-sALLOW_MEMORY_GROWTH=1
|
||||||
|
-sINITIAL_MEMORY=33554432
|
||||||
-sMAXIMUM_MEMORY=10737418240
|
-sMAXIMUM_MEMORY=10737418240
|
||||||
-sGLOBAL_BASE=16777216
|
-sGLOBAL_BASE=16777216
|
||||||
-sEXPORTED_RUNTIME_METHODS="['FS']"
|
-sEXPORTED_RUNTIME_METHODS=['FS']
|
||||||
-sPTHREAD_POOL_SIZE_STRICT=0
|
-sPTHREAD_POOL_SIZE_STRICT=0
|
||||||
-sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency)
|
-sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
Regular → Executable
+61
-38
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/local/env node
|
#!/usr/bin/env node
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -21,51 +21,61 @@ const server = createServer((req, res) => {
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>eden-cli</title>
|
<title>eden-cli</title>
|
||||||
|
</head>
|
||||||
|
<body style="margin:0;padding:0;background-color:black;font-family:Monospace,Tahoma,Arial;">
|
||||||
<script>
|
<script>
|
||||||
var Module = {}; // MUST be global otherwise wasm does wawawawa
|
var Module = { //do not prepend var
|
||||||
function finished_body() {
|
mainScriptUrlOrBlob: 'eden-cli.js',
|
||||||
Module = { //do not prepend var
|
print: (e) => {
|
||||||
print: (e) => {
|
e = e.replace('[1;31m', '<span style="color:red;font-weight:bold;">');
|
||||||
e = e.replace('[1;31m', '<span style="color:red;font-weight:bold;">');
|
e = e.replace('[0;37m', '<span style="color:white;font-weight:bold;">');
|
||||||
e = e.replace('[0;37m', '<span style="color:white;font-weight:bold;">');
|
e = e.replace('[1;35m', '<span style="color:pink;font-weight:bold;">');
|
||||||
e = e.replace('[1;35m', '<span style="color:pink;font-weight:bold;">');
|
e = e.replace('[1;33m', '<span style="color:yellow;font-weight:bold;">');
|
||||||
e = e.replace('[1;33m', '<span style="color:yellow;font-weight:bold;">');
|
e = e.replace('[0m', '</span>');
|
||||||
e = e.replace('[0m', '</span>');
|
tty_stdout.innerHTML += \`\${e}</br>\`;
|
||||||
tty_stdout.innerHTML += e + '</br>';
|
},
|
||||||
},
|
printErr: (e) => {
|
||||||
printErr: (e) => {
|
tty_stdout.innerHTML += \`<span style="color:red">\${e}</span></br>\`;
|
||||||
tty_stdout.innerHTML += '<span style="color:red">' + e + '</span></br>';
|
},
|
||||||
},
|
// not a wasm func but idc
|
||||||
// not a wasm func but idc
|
printInternal: (e) => {
|
||||||
printInternal: (e) => {
|
tty_stdout.innerHTML += \`<span style="color:pink">Internal WASM: \${e}</span></br>\`;
|
||||||
tty_stdout.innerHTML += '<span style="color:pink">Internal WASM: ' + e + '</span></br>';
|
},
|
||||||
},
|
onRuntimeInitialized: () => { Module.printInternal("runtime ok"); },
|
||||||
onRuntimeInitialized: () => { Module.printInternal("runtime ok"); },
|
setStatus: (e) => { Module.printInternal(e); },
|
||||||
setStatus: (e) => { Module.printInternal(e); },
|
monitorRunDependencies: (e) => { Module.printInternal("monitor deps: " + e); },
|
||||||
monitorRunDependencies: (e) => { Module.printInternal("monitor deps: " + e); },
|
__wasm_call_ctors: () => { Module.printInternal("ctors beep"); },
|
||||||
__wasm_call_ctors: () => { Module.printInternal("ctors beep"); },
|
};
|
||||||
};
|
var tty_stdout = document.createElement('div');
|
||||||
|
document.body.appendChild(tty_stdout);
|
||||||
|
Module.arguments = ['game.nro'];
|
||||||
|
|
||||||
var tty_stdout = document.createElement('div');
|
var gameNroFileBuffer = {};
|
||||||
document.body.appendChild(tty_stdout);
|
|
||||||
Module.printInternal("loading from ${build_dir}/eden-cli.js");
|
|
||||||
|
|
||||||
Module.arguments = ['game.nro'];
|
Module.printInternal("Atomics: " + window.Atomics);
|
||||||
|
Module.printInternal("SharedArrayBuffer: " + window.SharedArrayBuffer);
|
||||||
|
Module.printInternal("trying to load script (if it hangs here check console)");
|
||||||
|
|
||||||
|
fetch('game.nro').then((resp) => {
|
||||||
|
if (!resp.ok)
|
||||||
|
throw Error(\`\${resp.status}\`);
|
||||||
|
return resp.arrayBuffer();
|
||||||
|
}).then((buffer) => {
|
||||||
|
gameNroFileBuffer = buffer;
|
||||||
|
Module.printInternal("buffer: " + gameNroFileBuffer);
|
||||||
|
|
||||||
|
// load the thingy AFTER loading the nro
|
||||||
|
Module.printInternal(\`loading from ${build_dir}\${Module.mainScriptUrlOrBlob}\`);
|
||||||
var script = document.createElement('script');
|
var script = document.createElement('script');
|
||||||
script.src = '/eden-cli.js';
|
script.src = '/eden-cli.js';
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
Module.printInternal("Atomics: " + window.Atomics);
|
// copy just most relevant :)
|
||||||
Module.printInternal("SharedArrayBuffer: " + window.SharedArrayBuffer);
|
console.log(Module);
|
||||||
Module.printInternal("trying to load script (if it hangs here check console)");
|
Module.FS.writeFile('/game.nro', new DataView(gameNroFileBuffer));
|
||||||
|
|
||||||
Module.FS.writeFile('/game.nro', [1,2,3]);
|
|
||||||
};
|
};
|
||||||
document.head.appendChild(script);
|
document.head.appendChild(script);
|
||||||
}
|
}).catch(Module.printErr);
|
||||||
</script>
|
</script>
|
||||||
</head>
|
|
||||||
<body style="margin:0;padding:0;background-color:black;font-family:Monospace,Tahoma,Arial;" onload="finished_body();">
|
|
||||||
</body>
|
</body>
|
||||||
</html>`);
|
</html>`);
|
||||||
} else if (req.url === '/eden-cli.js') {
|
} else if (req.url === '/eden-cli.js') {
|
||||||
@@ -86,12 +96,25 @@ function finished_body() {
|
|||||||
});
|
});
|
||||||
res.end(content, 'utf-8');
|
res.end(content, 'utf-8');
|
||||||
});
|
});
|
||||||
|
} else if (req.url === '/game.nro') {
|
||||||
|
readFile(nro_file, (err, content) => {
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'application/wasm',
|
||||||
|
'Cross-Origin-Opener-Policy': 'same-origin',
|
||||||
|
'Cross-Origin-Embedder-Policy': 'require-corp'
|
||||||
|
});
|
||||||
|
res.end(content, 'utf-8');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.writeHead(404, {});
|
||||||
|
res.end('', 'utf-8');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const build_dir = process.argv[2];
|
const build_dir = process.argv[2];
|
||||||
if (build_dir === undefined) {
|
const nro_file = process.argv[3];
|
||||||
console.log(`Usage: ${process.argv[0]} ${process.argv[1]} [build directory]`);
|
if (typeof build_dir == "undefined" || typeof nro_file == "undefined") {
|
||||||
|
console.log(`Usage: ${process.argv[0]} ${process.argv[1]} [build directory] [NRO file]`);
|
||||||
} else {
|
} else {
|
||||||
server.listen(2210, () => {
|
server.listen(2210, () => {
|
||||||
console.log(`${process.argv[0]} ${process.argv[1]} http://localhost:2210`);
|
console.log(`${process.argv[0]} ${process.argv[1]} http://localhost:2210`);
|
||||||
|
|||||||
Reference in New Issue
Block a user