@@ -8,9 +8,6 @@ TARGET := $(LIBRETRO)_libretro.js
88endif
99endif
1010
11- EOPT = USE_ZLIB=1 # Emscripten specific options
12- EOPTS = $(addprefix -s $(EMPTY), $(EOPT)) # Add '-s ' to each option
13-
1411OS = Emscripten
1512OBJ :=
1613DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN -DEMSCRIPTEN -DNO_CANVAS_RESIZE
@@ -20,7 +17,7 @@ HAVE_PATCH = 1
2017HAVE_DSP_FILTER = 1
2118HAVE_VIDEO_FILTER = 1
2219HAVE_OVERLAY = 1
23- HAVE_NETWORKING = 1
20+ HAVE_NETWORKING ? = 1
2421HAVE_LIBRETRODB = 1
2522HAVE_COMPRESSION = 1
2623HAVE_UPDATE_ASSETS = 1
@@ -32,10 +29,10 @@ HAVE_AUDIOMIXER = 1
3229HAVE_CC_RESAMPLER = 1
3330HAVE_EGL ?= 0
3431HAVE_OPENGLES = 1
35- HAVE_RJPEG = 0
36- HAVE_RPNG = 1
32+ HAVE_RJPEG = 0
33+ HAVE_RPNG = 1
3734HAVE_EMSCRIPTEN = 1
38- HAVE_MENU = 1
35+ HAVE_MENU ? = 1
3936HAVE_GFX_WIDGETS = 1
4037HAVE_RGUI = 1
4138HAVE_SDL = 0
@@ -47,37 +44,63 @@ HAVE_STATIC_AUDIO_FILTERS = 1
4744HAVE_STB_FONT = 1
4845HAVE_CONFIGFILE = 1
4946HAVE_COMMAND = 1
50- HAVE_STDIN_CMD = 1
47+ HAVE_STDIN_CMD ? = 1
5148HAVE_CHEATS = 1
5249HAVE_IBXM = 1
5350HAVE_CORE_INFO_CACHE = 1
5451HAVE_7ZIP = 1
5552HAVE_BSV_MOVIE = 1
56- HAVE_AL = 1
5753HAVE_CHD ?= 0
5854HAVE_NETPLAYDISCOVERY ?= 0
55+
56+ HAVE_AL ?= 1
57+
58+ # enables pthreads, requires special headers on the web server:
59+ # see https://web.dev/articles/coop-coep
5960HAVE_THREADS ?= 0
6061
62+ # requires HAVE_THREADS
63+ HAVE_AUDIOWORKLET ?= 0
64+
6165# WARNING -- READ BEFORE ENABLING
6266# The rwebaudio driver is known to have several audio bugs, such as
6367# minor crackling, or the entire page freezing/crashing.
6468# It works perfectly on chrome, but even firefox has really bad audio quality.
6569# I should also note, the driver on iOS is completely broken (crashes the page).
6670# You have been warned.
67- HAVE_RWEBAUDIO = 0
71+ HAVE_RWEBAUDIO ?= 0
72+
73+ # whether the browser thread is allowed to block to wait for audio to play,
74+ # may lead to the issues mentioned above.
75+ # currently this variable is only used by audioworklet;
76+ # rwebaudio will always busywait and openal will never busywait.
77+ ALLOW_AUDIO_BUSYWAIT ?= 0
78+
79+ # minimal asyncify; better performance than full asyncify,
80+ # but sleeping on the main thread is only possible in some places.
81+ MIN_ASYNC ?= 0
82+
83+ # runs RetroArch on a pthread instead of the browser thread; requires HAVE_THREADS
84+ PROXY_TO_PTHREAD ?= 0
85+
86+ # recommended FS when using HAVE_THREADS
87+ HAVE_WASMFS ?= 0
88+
89+ # enables OPFS (origin private file system) and FETCHFS, requires PROXY_TO_PTHREAD
90+ HAVE_EXTRA_WASMFS ?= 0
91+
92+ # enable javascript filesystem tracking, incompatible with HAVE_WASMFS
93+ FS_DEBUG ?= 0
6894
6995# help diagnose GL problems (can cause issues in normal operation)
7096GL_DEBUG ?= 0
7197
72- # enable javascript filesystem tracking
73- FS_DEBUG = 0
98+ # does nothing on its own, but automatically selected by some other options
99+ WASM_WORKERS = 0
74100
75101HAVE_OPENGLES ?= 1
76102HAVE_OPENGLES3 ?= 0
77103
78- HAVE_WASMFS ?= 0
79- PROXY_TO_PTHREAD ?= 0
80-
81104ASYNC ?= 0
82105LTO ?= 0
83106PTHREAD_POOL_SIZE ?= 4
@@ -102,26 +125,32 @@ OBJDIR := obj-emscripten
102125EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_take_screenshot,\
103126_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\
104127_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,\
105- _cmd_cheat_get_size,_cmd_cheat_apply_cheats,_update_canvas_dimensions,_update_window_hidden,_update_power_state,_update_memory_usage,\
106- EmscriptenSendCommand,EmscriptenReceiveCommandReply
128+ _cmd_cheat_get_size,_cmd_cheat_apply_cheats,EmscriptenSendCommand,EmscriptenReceiveCommandReply
107129
108130EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,EmscriptenSendCommand,EmscriptenReceiveCommandReply
109131
110- LIBS := -s USE_ZLIB=1
132+ LIBS := -s USE_ZLIB=1
133+ CFLAGS := -s USE_ZLIB=1
111134
112- ifeq ($(HAVE_WASMFS), 1)
113- LIBS += -s WASMFS -s FORCE_FILESYSTEM=1 -lfetchfs.js -lopfs.js
114- DEFINES += -DHAVE_WASMFS
135+ ifeq ($(HAVE_EXTRA_WASMFS), 1)
136+ LIBS += -lfetchfs.js -lopfs.js
137+ DEFINES += -DHAVE_EXTRA_WASMFS
138+ override HAVE_WASMFS = 1
115139 ifeq ($(PROXY_TO_PTHREAD), 0)
116- $(error ERROR: WASMFS requires PROXY_TO_PTHREAD)
140+ $(error ERROR: HAVE_EXTRA_WASMFS requires PROXY_TO_PTHREAD)
117141 endif
118142endif
119143
144+ ifeq ($(HAVE_WASMFS), 1)
145+ LIBS += -s WASMFS -s FORCE_FILESYSTEM=1
146+ endif
147+
120148# note: real PROXY_TO_PTHREAD is not used here; we do the pthread management ourselves
121149ifeq ($(PROXY_TO_PTHREAD), 1)
122150 LIBS += -s OFFSCREENCANVAS_SUPPORT
123151 DEFINES += -DPROXY_TO_PTHREAD -DEMSCRIPTEN_STACK_SIZE=$(STACK_SIZE)
124152 override HAVE_THREADS = 1
153+ override WASM_WORKERS = 1
125154 # use the default stack size for the browser thread; the RetroArch thread will be created with the specified stack size
126155 override STACK_SIZE = 4194304
127156else ifeq ($(HAVE_AL), 1)
@@ -165,6 +194,40 @@ ifeq ($(HAVE_RWEBAUDIO), 1)
165194 DEFINES += -DHAVE_RWEBAUDIO
166195endif
167196
197+ ifeq ($(HAVE_AUDIOWORKLET), 1)
198+ LDFLAGS += -s AUDIO_WORKLET=1
199+ DEFINES += -DHAVE_AUDIOWORKLET
200+ override WASM_WORKERS = 1
201+ ifeq ($(HAVE_THREADS), 0)
202+ $(error ERROR: AUDIOWORKLET requires HAVE_THREADS)
203+ endif
204+ ifeq ($(PROXY_TO_PTHREAD), 1)
205+ else ifeq ($(ASYNC), 1)
206+ else
207+ DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_BLOCK
208+ ifeq ($(MIN_ASYNC), 1)
209+ DEFINES += -DEMSCRIPTEN_AUDIO_ASYNC_BLOCK
210+ else
211+ DEFINES += -DEMSCRIPTEN_AUDIO_FAKE_BLOCK
212+ endif
213+ ifneq ($(ALLOW_AUDIO_BUSYWAIT), 1)
214+ DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
215+ endif
216+ endif
217+ endif
218+
219+ ifeq ($(ALLOW_AUDIO_BUSYWAIT), 1)
220+ DEFINES += -DEMSCRIPTEN_AUDIO_BUSYWAIT
221+ endif
222+
223+ # explanation of some of these defines:
224+ # EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK: audio blocking occurs in the main loop instead of in the audio driver functions.
225+ # EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK: along with above, enables external blocking in the write function.
226+ # ALLOW_AUDIO_BUSYWAIT: write function will busywait. init function may still use an external block.
227+ # EMSCRIPTEN_AUDIO_ASYNC_BLOCK: external block uses emscripten_sleep (requires MIN_ASYNC).
228+ # EMSCRIPTEN_AUDIO_FAKE_BLOCK: external block uses main loop timing (doesn't require asyncify).
229+ # when building with either PROXY_TO_PTHREAD or ASYNC (full asyncify), none of the above are required.
230+
168231ifeq ($(HAVE_AL), 1)
169232 LDFLAGS += -lopenal
170233 DEFINES += -DHAVE_AL
@@ -175,11 +238,21 @@ ifeq ($(HAVE_THREADS), 1)
175238 CFLAGS += -pthread -s SHARED_MEMORY
176239endif
177240
241+ ifeq ($(WASM_WORKERS), 1)
242+ LDFLAGS += -s WASM_WORKERS=2
243+ endif
244+
178245ifeq ($(ASYNC), 1)
179- DEFINES += -DEMSCRIPTEN_ASYNCIFY
246+ DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_FULL_ASYNCIFY
180247 LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192
181248 ifeq ($(DEBUG), 1)
182- LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
249+ #LDFLAGS += -s ASYNCIFY_DEBUG=1 # broken?
250+ endif
251+ else ifeq ($(MIN_ASYNC), 1)
252+ DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_MIN_ASYNCIFY
253+ LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 -s ASYNCIFY_IGNORE_INDIRECT=1 -s ASYNCIFY_ADD='dynCall_*,emscripten_mainloop' -s ASYNCIFY_REMOVE='threaded_worker'
254+ ifeq ($(DEBUG), 1)
255+ LDFLAGS += -s ASYNCIFY_ADVISE #-s ASYNCIFY_DEBUG=1
183256 endif
184257endif
185258
@@ -202,7 +275,7 @@ ifneq ($(V), 1)
202275endif
203276
204277ifeq ($(DEBUG), 1)
205- LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
278+ LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=2 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
206279 # -O0 in cflags gives "too many locals" errors
207280 CFLAGS += -O1 -g -gsource-map
208281else
@@ -223,19 +296,25 @@ all: $(TARGET)
223296$(libretro_new) : $(libretro)
224297 mv -f $(libretro) $(libretro_new)
225298
299+ # until emscripten adds something like WASM_WORKERS=2 but for audio worklets, DIY.
226300$(TARGET): $(RARCH_OBJ) $(libretro_new)
227301 @$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
228302 $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
303+ @if [ "$(HAVE_AUDIOWORKLET)" = 1 ]; then\
304+ tr -d '\n' < "$${TARGET%%\.js}.aw.js" | sed -e "s/[\/&]/\\\\&/g" -e "s/'/\\\\\\\\&/g" > _audioworklet.js;\
305+ sed -i "s/\"$${TARGET%%\.js}\.aw\.js\"/URL.createObjectURL(new Blob(['$$(cat _audioworklet.js)'],{type:'text\/javascript'}))/" "$@";\
306+ rm "$${TARGET%%\.js}.aw.js" _audioworklet.js;\
307+ fi
229308
230309$(OBJDIR)/%.o: %.c
231310 @mkdir -p $(dir $@)
232311 @$(if $(Q), $(shell echo echo CC $<),)
233- $(Q)$(CC) $(CFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
312+ $(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
234313
235314$(OBJDIR)/%.o: %.cpp
236315 @mkdir -p $(dir $@)
237316 @$(if $(Q), $(shell echo echo CXX $<),)
238- $(Q)$(CXX) $(CXXFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
317+ $(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
239318
240319clean:
241320 rm -rf $(OBJDIR)
0 commit comments