Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threaded emscripten fixes #17614

Merged
merged 5 commits into from
Feb 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile.emscripten
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ OBJDIR := obj-emscripten
EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_take_screenshot,\
_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\
_cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\
_cmd_cheat_get_size,_cmd_cheat_apply_cheats
_cmd_cheat_get_size,_cmd_cheat_apply_cheats,EmscriptenSendCommand,EmscriptenReceiveCommandReply

EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,GL
EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,GL,EmscriptenSendCommand,EmscriptenReceiveCommandReply

LIBS := -s USE_ZLIB=1 -lbrowser.js

Expand Down
57 changes: 56 additions & 1 deletion command.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ command_t* command_stdin_new(void)
command_t *cmd;
command_stdin_t *stdincmd;

#ifndef _WIN32
#if !(defined(_WIN32) || defined(EMSCRIPTEN))
#ifdef HAVE_NETWORKING
if (!socket_nonblock(STDIN_FILENO))
return NULL;
Expand All @@ -363,6 +363,61 @@ command_t* command_stdin_new(void)
}
#endif

#if defined(EMSCRIPTEN)
void PlatformEmscriptenCommandReply(const char *, size_t);
int PlatformEmscriptenCommandRead(char **, size_t);
typedef struct
{
char command_buf[CMD_BUF_SIZE];
} command_emscripten_t;

static void emscripten_command_reply(command_t *_cmd,
const char *s, size_t len)
{
PlatformEmscriptenCommandReply(s, len);
}

static void emscripten_command_free(command_t *handle)
{
free(handle->userptr);
free(handle);
}

static void command_emscripten_poll(command_t *handle)
{
command_emscripten_t *emscriptencmd = (command_emscripten_t*)handle->userptr;
ptrdiff_t msg_len = PlatformEmscriptenCommandRead((char **)(&emscriptencmd->command_buf), CMD_BUF_SIZE);
if (msg_len == 0)
return;
command_parse_msg(handle, emscriptencmd->command_buf);
}

command_t* command_emscripten_new(void)
{
command_t *cmd;
command_emscripten_t *emscriptencmd;

cmd = (command_t*)calloc(1, sizeof(command_t));
emscriptencmd = (command_emscripten_t*)calloc(1, sizeof(command_emscripten_t));

if (!cmd)
return NULL;
if (!emscriptencmd)
{
free(cmd);
return NULL;
}
cmd->userptr = emscriptencmd;
cmd->poll = command_emscripten_poll;
cmd->replier = emscripten_command_reply;
cmd->destroy = emscripten_command_free;

return cmd;
}
#endif



bool command_get_config_param(command_t *cmd, const char* arg)
{
size_t _len;
Expand Down
11 changes: 10 additions & 1 deletion command.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,11 +329,20 @@ struct rarch_state;
bool command_event(enum event_command action, void *data);

/* Constructors for the supported drivers */
#ifdef HAVE_NETWORK_CMD
command_t* command_network_new(uint16_t port);
bool command_network_send(const char *cmd_);
#endif
#ifdef HAVE_STDIN_CMD
command_t* command_stdin_new(void);
#endif
#ifdef LAKKA
command_t* command_uds_new(void);
#endif
#ifdef EMSCRIPTEN
command_t* command_emscripten_new(void);
#endif

bool command_network_send(const char *cmd_);

void command_event_set_mixer_volume(
settings_t *settings,
Expand Down
13 changes: 12 additions & 1 deletion emscripten/library_platform_emscripten.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ var LibraryPlatformEmscripten = {
RPE.powerState.dischargeTime = Number.isFinite(e.target.dischargingTime) ? e.target.dischargingTime : 0x7FFFFFFF;
RPE.powerState.level = e.target.level;
RPE.powerState.charging = e.target.charging;
}
},
command_queue:[],
command_reply_queue:[],
},

PlatformEmscriptenPowerStateInit: function() {
Expand Down Expand Up @@ -49,6 +51,15 @@ var LibraryPlatformEmscripten = {
PlatformEmscriptenGetFreeMem: function() {
if (!performance.memory) return 0;
return (performance.memory.jsHeapSizeLimit || 0) - (performance.memory.usedJSHeapSize || 0);
},

$EmscriptenSendCommand__deps:["PlatformEmscriptenCommandRaiseFlag"],
$EmscriptenSendCommand: function(str) {
RPE.command_queue.push(str);
_PlatformEmscriptenCommandRaiseFlag();
},
$EmscriptenReceiveCommandReply: function() {
return RPE.command_reply_queue.shift();
}
};

Expand Down
61 changes: 52 additions & 9 deletions frontend/drivers/platform_emscripten.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,33 @@ bool PlatformEmscriptenPowerStateGetCharging(void);
uint64_t PlatformEmscriptenGetTotalMem(void);
uint64_t PlatformEmscriptenGetFreeMem(void);

void PlatformEmscriptenCommandReply(const char *msg, size_t len) {
MAIN_THREAD_EM_ASM({
var message = UTF8ToString($0,$1);
RPE.command_reply_queue.push(message);
}, msg, len);
}
static bool command_flag = false;
size_t PlatformEmscriptenCommandRead(char **into, size_t max_len) {
if(!command_flag) { return 0; }
return MAIN_THREAD_EM_ASM_INT({
var next_command = RPE.command_queue.shift();
var length = lengthBytesUTF8(next_command);
if(length > $2) {
console.error("[CMD] Command too long, skipping",next_command);
return 0;
}
stringToUTF8(next_command, $1, $2);
if(RPE.command_queue.length == 0) {
setValue($0, 0, 'i8');
}
return length;
}, &command_flag, into, max_len);
}
void PlatformEmscriptenCommandRaiseFlag() {
command_flag = true;
}

/* begin exported functions */

/* saves and states */
Expand Down Expand Up @@ -350,32 +377,46 @@ void PlatformEmscriptenMountFilesystems(void *info) {
*/
int max_line_len = 1024;
printf("[FetchFS] read fetch manifest from %s\n",fetch_manifest);
FILE *file = fopen(fetch_manifest, O_RDONLY);
FILE *file = fopen(fetch_manifest, "r");
if(!file) {
printf("[FetchFS] missing manifest file\n");
abort();
}
char *line = calloc(sizeof(char), max_line_len);
size_t len = 0;
size_t len = max_line_len;
while (getline(&line, &len, file) != -1) {
char *path = strstr(line, " ");
backend_t fetch;
int fd;
if (!path) {
printf("Manifest file has invalid line %s\n",line);
return;
if(len <= 2 || !path) {
printf("[FetchFS] Manifest file has invalid line %s\n",line);
continue;
}
*path = '\0';
path += 1;
printf("Fetch %s from %s\n", path, line);
path[strcspn(path, "\r\n")] = '\0';
printf("[FetchFS] Fetch %s from %s\n", path, line);
{
char *parent = strdup(path);
path_parent_dir(parent, strlen(parent));
if(!path_mkdir(parent)) {
printf("mkdir error %d\n",errno);
printf("[FetchFS] mkdir error %d\n",errno);
abort();
}
free(parent);
}
fetch = wasmfs_create_fetch_backend(line, 8*1024*1024);
fetch = wasmfs_create_fetch_backend(line, 16*1024*1024);
if(!fetch) {
printf("[FetchFS] couldn't create fetch backend\n");
abort();
}
fd = wasmfs_create_file(path, 0777, fetch);
if(!fd) {
printf("[FetchFS] couldn't create fetch file\n");
abort();
}
close(fd);
len = max_line_len;
}
fclose(file);
free(line);
Expand Down Expand Up @@ -433,7 +474,9 @@ void emscripten_bootup_mainloop(void *argptr) {
int main(int argc, char *argv[])
{
args_t *args = calloc(sizeof(args_t), 1);

args->argc = argc;
args->argv = argv;

PlatformEmscriptenWatchCanvasSize();
PlatformEmscriptenPowerStateInit();

Expand Down
6 changes: 5 additions & 1 deletion input/input_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -5104,10 +5104,14 @@ void input_driver_init_command(input_driver_state_t *input_st,
}
#endif

#ifdef HAVE_LAKKA
#if defined(HAVE_LAKKA)
if (!(input_st->command[2] = command_uds_new()))
RARCH_ERR("Failed to initialize the UDS command interface.\n");
#elif defined(EMSCRIPTEN)
if (!(input_st->command[2] = command_emscripten_new()))
RARCH_ERR("Failed to initialize the emscripten command interface.\n");
#endif

}

void input_driver_deinit_command(input_driver_state_t *input_st)
Expand Down
61 changes: 6 additions & 55 deletions pkg/emscripten/libretro-thread/libretro.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,64 +14,15 @@ var Module = {
noImageDecoding: true,
noAudioDecoding: true,

encoder: new TextEncoder(),
message_queue: [],
message_out: [],
message_accum: "",

retroArchSend: function(msg) {
let bytes = this.encoder.encode(msg + "\n");
this.message_queue.push([bytes, 0]);
},
retroArchRecv: function() {
let out = this.message_out.shift();
if (out == null && this.message_accum != "") {
out = this.message_accum;
this.message_accum = "";
}
return out;
},
retroArchSend: function(msg) {
this.EmscriptenSendCommand(msg);
},
retroArchRecv: function() {
return this.EmscriptenReceiveCommandReply();
},
preRun: [
function(module) {
Module.ENV['OPFS'] = "/home/web_user/retroarch";
},
function(module) {
function stdin() {
// Return ASCII code of character, or null if no input
while (module.message_queue.length > 0) {
var msg = module.message_queue[0][0];
var index = module.message_queue[0][1];
if (index >= msg.length) {
module.message_queue.shift();
} else {
module.message_queue[0][1] = index + 1;
// assumption: msg is a uint8array
return msg[index];
}
}
return null;
}

function stdout(c) {
if (c == null) {
// flush
if (module.message_accum != "") {
module.message_out.push(module.message_accum);
module.message_accum = "";
}
} else {
let s = String.fromCharCode(c);
if (s == "\n") {
if (module.message_accum != "") {
module.message_out.push(module.message_accum);
module.message_accum = "";
}
} else {
module.message_accum = module.message_accum + s;
}
}
}
module.FS.init(stdin, stdout);
}
],
postRun: [],
Expand Down
2 changes: 1 addition & 1 deletion pkg/emscripten/libretro-thread/libretro.worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ onmessage = async (msg) => {
}
postMessage({command:"loaded_bundle", time:resp.headers.get("last-modified")});
} else if(msg.data.command == "upload_file") {
await writeFile("/home/web_user/retroarch/userdata/content/"+msg.data.name, new Uint8Array(msg.data.data));
await writeFile("userdata/content/"+msg.data.name, new Uint8Array(msg.data.data));
postMessage({command:"uploaded_file",name:msg.data.name});
}
}
Loading