diff --git a/.gitignore b/.gitignore
index 60c69dd615..71db6addba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -132,3 +132,10 @@ obj-unix/
/pkg/msvc/msvc-2010/Release Cg/*.pdb
retroarch.cfg
Makefile.local
+
+# Emscripten artifacts
+
+retroarch.js
+retroarch.js.mem
+*.bc
+*.wasm
diff --git a/Makefile.emscripten b/Makefile.emscripten
index 0334d2edf3..4ac23c1bf6 100644
--- a/Makefile.emscripten
+++ b/Makefile.emscripten
@@ -21,13 +21,15 @@ HAVE_SDL = 0
HAVE_SDL2 = 0
HAVE_ZLIB = 1
WANT_ZLIB = 1
+HAVE_SHADERPIPELINE = 1
HAVE_STATIC_VIDEO_FILTERS = 1
HAVE_STATIC_AUDIO_FILTERS = 1
MEMORY = 536870912
-# XXX: setting this to 1/2 currently crashes Firefox nightly
PRECISE_F32 = 2
+OBJDIR := obj-emscripten
+
ifneq ($(NATIVE_ZLIB),)
WANT_ZLIB = 0
endif
@@ -65,7 +67,7 @@ ifeq ($(DEBUG), 1)
LDFLAGS += -O0 -g
CFLAGS += -O0 -g
else
- LDFLAGS += -O2
+ LDFLAGS += -O2 -s WASM=1
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
LDFLAGS += -s PRECISE_F32=$(PRECISE_F32)
ifeq ($(LTO), 1)
@@ -74,48 +76,29 @@ else
CFLAGS += -O2
endif
-CFLAGS += -DHAVE_RPNG -Wall -Wno-unused-result -Wno-unused-variable -I. -Ilibretro-common/include -std=gnu99 -s USE_ZLIB=1 \
+CFLAGS += -DHAVE_RPNG -Wall -I. -Ilibretro-common/include -std=gnu99 -s USE_ZLIB=1 \
-s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_take_screenshot']"
+RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
+
all: $(TARGET)
-$(TARGET): $(OBJ)
+$(TARGET): $(RARCH_OBJ)
@$(if $(Q), $(shell echo echo LD $@),)
- $(Q)$(LD) -o $@ $(OBJ) $(libretro) $(LIBS) $(LDFLAGS)
+ $(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro) $(LIBS) $(LDFLAGS)
-%.o: %.c
+$(OBJDIR)/%.o: %.c
+ @mkdir -p $(dir $@)
@$(if $(Q), $(shell echo echo CC $<),)
$(Q)$(CC) $(CFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
-%.o: %.cpp
+$(OBJDIR)/%.o: %.cpp
+ @mkdir -p $(dir $@)
@$(if $(Q), $(shell echo echo CXX $<),)
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
clean:
- rm -f *.o
- rm -f deps/libz/*.o
- rm -f frontend/*.o
- rm -f menu/*.o
- rm -f menu/disp/*.o
- rm -f audio/*.o
- rm -f compat/*.o
- rm -f compat/rxml/*.o
- rm -f conf/*.o
- rm -f gfx/scaler/*.o
- rm -f gfx/*.o
- rm -f gfx/d3d/*.o
- rm -f gfx/drivers_context/*.o
- rm -f gfx/math/*.o
- rm -f gfx/drivers_font/*.o
- rm -f gfx/drivers_font_renderer/*.o
- rm -f gfx/py_state/*.o
- rm -f gfx/rpng/*.o
- rm -f gfx/glsym/*.o
- rm -f record/*.o
- rm -f input/*.o
- rm -f tools/*.o
- rm -f libretro-common/*/*.o
+ rm -rf $(OBJDIR)
rm -f $(TARGET)
- rm -f *.d
.PHONY: all clean
diff --git a/configuration.c b/configuration.c
index 9e7eacc246..6a70465a0c 100644
--- a/configuration.c
+++ b/configuration.c
@@ -224,6 +224,7 @@ enum joypad_driver_enum
JOYPAD_DOS,
JOYPAD_HID,
JOYPAD_QNX,
+ JOYPAD_RWEBPAD,
JOYPAD_NULL
};
@@ -454,6 +455,8 @@ static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_DOS;
static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_HID;
#elif defined(__QNX__)
static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_QNX;
+#elif defined(EMSCRIPTEN)
+static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_RWEBPAD;
#else
static enum joypad_driver_enum JOYPAD_DEFAULT_DRIVER = JOYPAD_NULL;
#endif
@@ -783,9 +786,9 @@ const char *config_get_default_input(void)
case INPUT_COCOA:
return "cocoa";
case INPUT_QNX:
- return "qnx_input";
+ return "qnx_input";
case INPUT_RWEBINPUT:
- return "rwebinput";
+ return "rwebinput";
case INPUT_DOS:
return "dos";
case INPUT_NULL:
@@ -846,6 +849,8 @@ const char *config_get_default_joypad(void)
return "hid";
case JOYPAD_QNX:
return "qnx";
+ case JOYPAD_RWEBPAD:
+ return "rwebpad";
case JOYPAD_DOS:
return "dos";
case JOYPAD_NULL:
diff --git a/emscripten/library_rwebaudio.js b/emscripten/library_rwebaudio.js
index fd85d607a0..03b70a8340 100644
--- a/emscripten/library_rwebaudio.js
+++ b/emscripten/library_rwebaudio.js
@@ -23,13 +23,14 @@ var LibraryRWebAudio = {
getCurrentPerfTime: function() {
if (RA.startTime) return (window['performance']['now']() - RA.startTime) / 1000;
- else throw 'getCurrentPerfTime() called before start time set';
+ else return 0;
},
process: function(queueBuffers) {
var currentTime = RA.getCurrentPerfTime();
for (var i = 0; i < RA.bufIndex; i++) {
- if (RA.buffers[i].endTime < currentTime) {
+ if (RA.buffers[i].endTime !== 0 && RA.buffers[i].endTime < currentTime) {
+ RA.buffers[i].endTime = 0;
var buf = RA.buffers.splice(i, 1);
RA.buffers[RA.numBuffers - 1] = buf[0];
i--;
@@ -40,8 +41,8 @@ var LibraryRWebAudio = {
fillBuffer: function(buf, samples) {
var count = 0;
- var leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0);
- var rightBuffer = RA.buffers[RA.bufIndex].getChannelData(1);
+ const leftBuffer = RA.buffers[RA.bufIndex].getChannelData(0);
+ const rightBuffer = RA.buffers[RA.bufIndex].getChannelData(1);
while (samples && RA.bufOffset !== RA.BUFFER_SIZE) {
leftBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8', 'float') }}};
rightBuffer[RA.bufOffset] = {{{ makeGetValue('buf', 'count * 8 + 4', 'float') }}};
@@ -73,7 +74,7 @@ var LibraryRWebAudio = {
block: function() {
do {
RA.process();
- } while (RA.bufIndex === RA.numBuffers - 1);
+ } while (RA.bufIndex === RA.numBuffers);
}
},
@@ -87,7 +88,10 @@ var LibraryRWebAudio = {
RA.numBuffers = ((latency * RA.context.sampleRate) / (1000 * RA.BUFFER_SIZE))|0;
if (RA.numBuffers < 2) RA.numBuffers = 2;
- for (var i = 0; i < RA.numBuffers; i++) RA.buffers[i] = RA.context.createBuffer(2, RA.BUFFER_SIZE, RA.context.sampleRate);
+ for (var i = 0; i < RA.numBuffers; i++) {
+ RA.buffers[i] = RA.context.createBuffer(2, RA.BUFFER_SIZE, RA.context.sampleRate);
+ RA.buffers[i].endTime = 0
+ }
RA.nonblock = false;
RA.startTime = 0;
@@ -97,7 +101,7 @@ var LibraryRWebAudio = {
Module["pauseMainLoop"]();
return 1;
},
-
+
RWebAudioSampleRate: function() {
return RA.context.sampleRate;
},
@@ -108,16 +112,17 @@ var LibraryRWebAudio = {
var count = 0;
while (samples) {
+ if (RA.bufIndex === RA.numBuffers) {
+ if (RA.nonblock) break;
+ else RA.block();
+ }
+
var fill = RA.fillBuffer(buf, samples);
samples -= fill;
count += fill;
buf += fill * 8;
if (RA.bufOffset === RA.BUFFER_SIZE) {
- if (RA.bufIndex === RA.numBuffers - 1) {
- if (RA.nonblock) break;
- else RA.block();
- }
RA.queueAudio();
}
}
@@ -142,16 +147,21 @@ var LibraryRWebAudio = {
RWebAudioFree: function() {
RA.bufIndex = 0;
RA.bufOffset = 0;
- return;
},
RWebAudioBufferSize: function() {
- return RA.numBuffers * RA.BUFFER_SIZE + RA.BUFFER_SIZE;
+ return RA.numBuffers * RA.BUFFER_SIZE * 8;
},
RWebAudioWriteAvail: function() {
RA.process();
return ((RA.numBuffers - RA.bufIndex) * RA.BUFFER_SIZE - RA.bufOffset) * 8;
+ },
+
+ RWebAudioRecalibrateTime: function() {
+ if (RA.startTime) {
+ RA.startTime = window['performance']['now']() - RA.context.currentTime * 1000;
+ }
}
};
diff --git a/frontend/drivers/platform_emscripten.c b/frontend/drivers/platform_emscripten.c
index 838f3e365e..4671638609 100644
--- a/frontend/drivers/platform_emscripten.c
+++ b/frontend/drivers/platform_emscripten.c
@@ -39,14 +39,42 @@
#include "../../defaults.h"
#include "../../content.h"
#include "../../retroarch.h"
+#include "../../verbosity.h"
#include "../../command.h"
#include "../../tasks/tasks_internal.h"
#include "../../file_path_special.h"
+void RWebAudioRecalibrateTime(void);
+
+static unsigned emscripten_fullscreen_reinit;
+
+static EM_BOOL emscripten_fullscreenchange_cb(int event_type,
+ const EmscriptenFullscreenChangeEvent *fullscreen_change_event,
+ void *user_data)
+{
+ (void)event_type;
+ (void)fullscreen_change_event;
+ (void)user_data;
+
+ emscripten_fullscreen_reinit = 5;
+
+ return EM_TRUE;
+}
+
static void emscripten_mainloop(void)
{
unsigned sleep_ms = 0;
- int ret = runloop_iterate(&sleep_ms);
+ int ret;
+
+ RWebAudioRecalibrateTime();
+
+ if (emscripten_fullscreen_reinit != 0)
+ {
+ if (--emscripten_fullscreen_reinit == 0)
+ command_event(CMD_EVENT_REINIT, NULL);
+ }
+
+ ret = runloop_iterate(&sleep_ms);
if (ret == 1 && sleep_ms > 0)
retro_sleep(sleep_ms);
@@ -162,19 +190,24 @@ static void frontend_emscripten_get_env(int *argc, char *argv[],
if (!string_is_empty(dir_path))
path_mkdir(dir_path);
}
-
- snprintf(g_defaults.settings.menu, sizeof(g_defaults.settings.menu), "rgui");
}
int main(int argc, char *argv[])
{
- settings_t *settings = config_get_ptr();
+ EMSCRIPTEN_RESULT r;
emscripten_set_canvas_element_size("#canvas", 800, 600);
emscripten_set_element_css_size("#canvas", 800.0, 600.0);
+ emscripten_set_main_loop(emscripten_mainloop, 0, 0);
rarch_main(argc, argv, NULL);
- emscripten_set_main_loop(emscripten_mainloop,
- settings->bools.video_vsync ? 0 : INT_MAX, 1);
+
+ r = emscripten_set_fullscreenchange_callback("#document", NULL, false,
+ emscripten_fullscreenchange_cb);
+ if (r != EMSCRIPTEN_RESULT_SUCCESS)
+ {
+ RARCH_ERR(
+ "[EMSCRIPTEN/CTX] failed to create fullscreen callback: %d\n", r);
+ }
return 0;
}
diff --git a/gfx/drivers_context/emscriptenegl_ctx.c b/gfx/drivers_context/emscriptenegl_ctx.c
index e72434b5cb..b3d7f3ae43 100644
--- a/gfx/drivers_context/emscriptenegl_ctx.c
+++ b/gfx/drivers_context/emscriptenegl_ctx.c
@@ -51,8 +51,11 @@ static int emscripten_initial_height;
static void gfx_ctx_emscripten_swap_interval(void *data, unsigned interval)
{
(void)data;
- /* no way to control VSync in WebGL. */
- (void)interval;
+
+ if (interval == 0)
+ emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0);
+ else
+ emscripten_set_main_loop_timing(EM_TIMING_RAF, (int)interval);
}
static void gfx_ctx_emscripten_get_canvas_size(int *width, int *height)
@@ -138,8 +141,13 @@ static void gfx_ctx_emscripten_check_window(void *data, bool *quit,
static void gfx_ctx_emscripten_swap_buffers(void *data, void *data2)
{
- (void)data;
- /* no-op in emscripten, no way to force swap/wait for VSync in browsers */
+ emscripten_ctx_data_t *emscripten = (emscripten_ctx_data_t*)data;
+
+ /* doesn't really do anything in WebGL, but it might if we use WebGL workers
+ * in the future */
+#ifdef HAVE_EGL
+ egl_swap_buffers(&emscripten->egl);
+#endif
}
static void gfx_ctx_emscripten_get_video_size(void *data,
diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c
index 8cdb425b5a..3108215bd1 100644
--- a/input/drivers/rwebinput_input.c
+++ b/input/drivers/rwebinput_input.c
@@ -567,7 +567,6 @@ static void rwebinput_input_free(void *data)
static void rwebinput_process_keyboard_events(rwebinput_input_t *rwebinput,
rwebinput_keyboard_event_t *event)
{
- uint32_t crc;
uint32_t keycode;
unsigned translated_keycode;
uint32_t character = 0;
diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html
index 8fbba05723..407a84e4fa 100644
--- a/pkg/emscripten/libretro/index.html
+++ b/pkg/emscripten/libretro/index.html
@@ -86,7 +86,7 @@
Cleanup
-