Skip to content

Commit 274ac36

Browse files
committed
Workerized (non-async) web player, using OPFS
This patch eliminates the need for asyncify and uses modern filesystem APIs instead of the deprecated, unmaintained BrowserFS. This is a WIP patch because it won't fully work until these two Emscripten PRs land and are released: emscripten-core/emscripten#23518 emscripten-core/emscripten#23021 The former fixes an offscreen canvas context recreation bug, and the latter adds an equivalent to BrowserFS's XHR filesystem (but without the hazardous running-XHR-on-the-main-thread problem). The biggest issue is that local storage of users who were using the old version of the webplayer will be gone when they switch to the new webplayer. I don't have a good story for converting the old BrowserFS IDBFS contents into the new OPFS filesystem (the move is worth doing because OPFS supports seeking and reading only bits of a file, and because BrowserFS is dead). I've kept around the old libretro webplayer under pkg/emscripten/libretro-classic, and with these make flags you can build a non-workerized RA that uses asyncify to sleep as before: make -f Makefile.emscripten libretro=$CORE HAVE_WORKER=0 HAVE_WASMFS=0 PTHREAD=0 HAVE_AL=1 I also moved the default directory for core content on emscripten to not be a subdirectory of the local filesystem mount, because it's confusing to have a subdirectory that's lazily fetched and not mirrored to the local storage. I think it won't impact existing users of the classic web player because they already have a retroarch.cfg in place.
1 parent 86c58da commit 274ac36

File tree

10 files changed

+846
-138
lines changed

10 files changed

+846
-138
lines changed

Makefile.emscripten

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,13 @@ _cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focu
9595
_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,\
9696
_cmd_cheat_get_size,_cmd_cheat_apply_cheats
9797

98+
EXPORTS = callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString
99+
98100
LIBS := -s USE_ZLIB=1
99101

100102
ifeq ($(HAVE_WASMFS), 1)
101-
LIBS += -s WASMFS -s FORCE_FILESYSTEM=1
103+
LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 -lfetchfs.js -lopfs.js
104+
EXPORTS += ,FETCHFS,OPFS
102105
endif
103106

104107
ifeq ($(HAVE_WORKER), 1)
@@ -132,7 +135,7 @@ endif
132135

133136

134137
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \
135-
-s EXPORTED_RUNTIME_METHODS=callMain,FS,PATH,ERRNO_CODES,stringToNewUTF8,UTF8ToString \
138+
-s EXPORTED_RUNTIME_METHODS=$(EXPORTS) \
136139
-s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \
137140
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
138141
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \

frontend/drivers/platform_emscripten.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,8 @@ static void frontend_emscripten_get_env(int *argc, char *argv[],
235235
"config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
236236
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], user_path,
237237
"content", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT]));
238-
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], user_path,
239-
"content/downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
238+
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], base_path,
239+
"downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
240240
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], user_path,
241241
"playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
242242
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG],

pkg/emscripten/libretro-classic/index.html

Lines changed: 204 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#! /usr/bin/env coffee
2+
3+
fs = require 'fs'
4+
path = require 'path'
5+
6+
symLinks = {}
7+
8+
rdSync = (dpath, tree, name) ->
9+
files = fs.readdirSync(dpath)
10+
for file in files
11+
# ignore non-essential directories / files
12+
continue if file in ['.git', 'node_modules', 'bower_components', 'build'] or file[0] is '.'
13+
fpath = dpath + '/' + file
14+
try
15+
# Avoid infinite loops.
16+
lstat = fs.lstatSync(fpath)
17+
if lstat.isSymbolicLink()
18+
symLinks[lstat.dev] ?= {}
19+
# Ignore if we've seen it before
20+
continue if symLinks[lstat.dev][lstat.ino]?
21+
symLinks[lstat.dev][lstat.ino] = 0
22+
23+
fstat = fs.statSync(fpath)
24+
if fstat.isDirectory()
25+
tree[file] = child = {}
26+
rdSync(fpath, child, file)
27+
else
28+
tree[file] = null
29+
catch e
30+
# Ignore and move on.
31+
return tree
32+
33+
fs_listing = rdSync(process.cwd(), {}, '/')
34+
console.log(JSON.stringify(fs_listing))
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* RetroArch Web Player
3+
*
4+
* This provides the basic styling for the RetroArch web player.
5+
*/
6+
7+
/**
8+
* Make sure the background of the player is black.
9+
* Also make sure line height is 0 so there's no extra space on the bottom.
10+
*/
11+
.webplayer-container {
12+
background-color: black;
13+
line-height: 0;
14+
}
15+
16+
/**
17+
* Webplayer Preview when not loaded.
18+
*/
19+
.webplayer-preview {
20+
margin: 0 auto;
21+
cursor: wait;
22+
opacity: 0.2;
23+
transition: all 0.8s;
24+
-webkit-animation: loading 0.8s ease-in-out infinite alternate;
25+
-moz-animation: loading 0.8s ease-in-out infinite alternate;
26+
animation: loading 0.8s ease-in-out infinite alternate;
27+
}
28+
.webplayer-preview.loaded {
29+
cursor: pointer;
30+
opacity: 1;
31+
-webkit-animation: loaded 0.8s ease-in-out;
32+
-moz-animation: loaded 0.8s ease-in-out;
33+
animation: loaded 0.8s ease-in-out;
34+
}
35+
@keyframes loaded {
36+
from {
37+
opacity: 0.2;
38+
}
39+
to {
40+
opacity: 1;
41+
}
42+
}
43+
@-moz-keyframes loaded {
44+
from {
45+
opacity: 0.2;
46+
}
47+
to {
48+
opacity: 1;
49+
}
50+
}
51+
@-webkit-keyframes loaded {
52+
from {
53+
opacity: 0.2;
54+
}
55+
to {
56+
opacity: 1;
57+
}
58+
}
59+
@keyframes loading{
60+
from {
61+
opacity: 0.2;
62+
}
63+
to {
64+
opacity: 0.35;
65+
}
66+
}
67+
@-moz-keyframes loading{
68+
from {
69+
opacity: 0.2;
70+
}
71+
to {
72+
opacity: 0.35;
73+
}
74+
}
75+
@-webkit-keyframes loading {
76+
from {
77+
opacity: 0.2;
78+
}
79+
to {
80+
opacity: 0.35;
81+
}
82+
}
83+
84+
/**
85+
* Disable the border around the player.
86+
*/
87+
canvas.webplayer {
88+
border: none;
89+
outline: none;
90+
}
91+
92+
textarea {
93+
font-family: monospace;
94+
font-size: 0.7em;
95+
height: 95%;
96+
width: 95%;
97+
border-style: none;
98+
border-color: transparent;
99+
overflow: auto;
100+
resize: none;
101+
}
102+
103+
/**
104+
* Toggle Top Navigation
105+
*/
106+
.toggleMenu {
107+
float: right;
108+
}
109+
.showMenu {
110+
position: absolute;
111+
right: 0;
112+
cursor: pointer;
113+
}
114+
#icnShowMenu {
115+
color: #565656 !important;
116+
}
117+
118+
.navbar {
119+
box-shadow: none;
120+
}

0 commit comments

Comments
 (0)