Emscripten: Support persistent storage

This commit is contained in:
Tamás Bálint Misius 2023-06-18 17:52:03 +02:00
parent 82bd834e05
commit 58229f49b2
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2
15 changed files with 188 additions and 19 deletions

View File

@ -209,7 +209,10 @@ if host_platform == 'emscripten'
'-s', 'WASM=1',
'-s', 'ALLOW_MEMORY_GROWTH=1',
'-s', 'FORCE_FILESYSTEM=1',
'-s', 'EXIT_RUNTIME=1',
'-s', 'EXIT_RUNTIME=0',
'-s', 'EXPORTED_RUNTIME_METHODS=ccall,cwrap',
'-s', 'FS_DEBUG',
'-lidbfs.js',
]
emcc_args = [
'-s', 'USE_SDL=2',

View File

@ -179,9 +179,14 @@ struct ExplicitSingletons
};
static std::unique_ptr<ExplicitSingletons> explicitSingletons;
int main(int argc, char * argv[])
int main(int argc, char *argv[])
{
Platform::SetupCrt();
return Platform::InvokeMain(argc, argv);
}
int Main(int argc, char *argv[])
{
Platform::Atexit([]() {
SaveWindowPosition();
// Unregister dodgy error handlers so they don't try to show the blue screen when the window is closed
@ -254,22 +259,22 @@ int main(int argc, char * argv[])
}
else
{
auto ddir = std::unique_ptr<char, decltype(&SDL_free)>(SDL_GetPrefPath(NULL, APPDATA), SDL_free);
auto ddir = Platform::DefaultDdir();
if (!Platform::FileExists("powder.pref"))
{
if (ddir)
if (ddir.size())
{
if (!Platform::ChangeDir(ddir.get()))
if (!Platform::ChangeDir(ddir))
{
perror("failed to chdir to default ddir");
ddir.reset();
ddir = {};
}
}
}
if (ddir)
if (ddir.size())
{
Platform::sharedCwd = ddir.get();
Platform::sharedCwd = ddir;
}
}
// We're now in the correct directory, time to get prefs.

View File

@ -3,12 +3,23 @@
#include <emscripten.h>
#include <iostream>
namespace Platform
{
void MaybeTriggerSyncFs();
}
static void MainLoopBody()
{
EngineProcess();
Platform::MaybeTriggerSyncFs();
}
void SetFpsLimit(FpsLimit newFpsLimit)
{
static bool mainLoopSet = false;
if (!mainLoopSet)
{
emscripten_set_main_loop(EngineProcess, 0, 0);
emscripten_set_main_loop(MainLoopBody, 0, 0);
mainLoopSet = true;
}
if (auto *fpsLimitVsync = std::get_if<FpsLimitVsync>(&newFpsLimit))
@ -28,8 +39,9 @@ void SetFpsLimit(FpsLimit newFpsLimit)
}
}
// Is actually only called once at startup, the real main loop body is MainLoopBody.
void MainLoop()
{
SetFpsLimit(ui::Engine::Ref().GetFpsLimit());
EngineProcess();
MainLoopBody();
}

View File

@ -17,7 +17,7 @@ namespace http
};
}
extern "C" void RequestManager_UpdateRequestStatusThunk(http::RequestHandleHttp *handle);
EMSCRIPTEN_KEEPALIVE extern "C" void RequestManager_UpdateRequestStatusThunk(http::RequestHandleHttp *handle);
namespace http
{

View File

@ -6,10 +6,6 @@ if not enable_http
client_files += files('Null.cpp')
elif host_platform == 'emscripten'
client_files += files('Emscripten.cpp')
project_link_args += [
'-s', 'EXPORTED_FUNCTIONS=_main,_RequestManager_UpdateRequestStatusThunk',
'-s', 'EXPORTED_RUNTIME_METHODS=cwrap',
]
else
client_files += files('Libcurl.cpp')
endif

View File

@ -24,4 +24,8 @@ bool CanUpdate()
{
return false;
}
void SetupCrt()
{
}
}

View File

@ -48,4 +48,8 @@ bool CanUpdate()
{
return false;
}
void SetupCrt()
{
}
}

View File

@ -0,0 +1,14 @@
#include "Platform.h"
#include "common/String.h"
#include "Config.h"
#include <SDL.h>
#include <memory>
namespace Platform
{
ByteString DefaultDdir()
{
auto ddir = std::unique_ptr<char, decltype(&SDL_free)>(SDL_GetPrefPath(NULL, APPDATA), SDL_free);
return ddir.get();
}
}

View File

@ -1,5 +1,17 @@
#include "Platform.h"
#include <ctime>
#include <emscripten.h>
#include <emscripten/threading.h>
#include <atomic>
#include <iostream>
static std::atomic<bool> shouldSyncFs = false;
static bool syncFsInFlight = false;
EMSCRIPTEN_KEEPALIVE extern "C" void Platform_SyncFsDone()
{
syncFsInFlight = false;
}
namespace Platform
{
@ -37,4 +49,84 @@ void Atexit(ExitFunc exitFunc)
void Exit(int code)
{
}
ByteString DefaultDdir()
{
return "/powder";
}
int InvokeMain(int argc, char *argv[])
{
EM_ASM({
FS.syncfs(true, () => {
Module.ccall('MainJs', 'number', [ 'number', 'number' ], [ $0, $1 ]);
});
}, argc, argv);
return 0;
}
void MaybeTriggerSyncFs()
{
if (!syncFsInFlight && shouldSyncFs.exchange(false, std::memory_order_relaxed))
{
std::cerr << "invoking FS.syncfs" << std::endl;
syncFsInFlight = true;
EM_ASM({
FS.syncfs(false, err => {
if (err) {
console.error(err);
}
Module.ccall('Platform_SyncFsDone', null, [], []);
});
});
}
}
}
EMSCRIPTEN_KEEPALIVE extern "C" int MainJs(int argc, char *argv[])
{
return Main(argc, argv);
}
EMSCRIPTEN_KEEPALIVE extern "C" void Platform_ShouldSyncFs()
{
shouldSyncFs.store(true, std::memory_order_relaxed);
}
namespace Platform
{
void SetupCrt()
{
EM_ASM({
let ddir = UTF8ToString($0);
let prefix = ddir + '/';
let shouldSyncFs = Module.cwrap(
'Platform_ShouldSyncFs',
null,
[]
);
FS.trackingDelegate['onMovePath'] = function(oldpath, newpath) {
if (oldpath.startsWith(prefix) || newpath.startsWith(prefix)) {
shouldSyncFs();
}
};
FS.trackingDelegate['onDeletePath'] = function(path) {
if (path.startsWith(prefix)) {
shouldSyncFs();
}
};
FS.trackingDelegate['onWriteToFile'] = function(path, bytesWritten) {
if (path.startsWith(prefix)) {
shouldSyncFs();
}
};
FS.trackingDelegate['onMakeDirectory'] = function(path, mode) {
if (path.startsWith(prefix)) {
shouldSyncFs();
}
};
FS.mkdir(ddir);
FS.mount(IDBFS, {}, ddir);
}, DefaultDdir().c_str());
}
}

View File

@ -109,4 +109,8 @@ bool Install()
}
return ok;
}
void SetupCrt()
{
}
}

View File

@ -0,0 +1,9 @@
#include "Platform.h"
namespace Platform
{
int InvokeMain(int argc, char *argv[])
{
return Main(argc, argv);
}
}

View File

@ -11,4 +11,8 @@ bool CanUpdate()
{
return false;
}
void SetupCrt()
{
}
}

View File

@ -62,4 +62,10 @@ namespace Platform
using ExitFunc = void (*)();
void Atexit(ExitFunc exitFunc);
void Exit(int code);
ByteString DefaultDdir();
int InvokeMain(int argc, char *argv[]);
}
extern "C" int Main(int argc, char *argv[]);

View File

@ -218,8 +218,4 @@ bool UpdateFinish()
void UpdateCleanup()
{
}
void SetupCrt()
{
}
}

View File

@ -12,6 +12,10 @@ if host_platform == 'windows'
'Windows.cpp',
'ExitCommon.cpp',
)
powder_files += files(
'MainCommon.cpp',
'DdirCommon.cpp',
)
elif host_platform == 'darwin'
can_install_enforce_no = true
common_files += files(
@ -19,6 +23,10 @@ elif host_platform == 'darwin'
'Posix.cpp',
'ExitCommon.cpp',
)
powder_files += files(
'MainCommon.cpp',
'DdirCommon.cpp',
)
elif host_platform == 'android'
can_install_enforce_no = true
common_files += files(
@ -26,6 +34,10 @@ elif host_platform == 'android'
'Posix.cpp',
'ExitCommon.cpp',
)
powder_files += files(
'MainCommon.cpp',
'DdirCommon.cpp',
)
elif host_platform == 'emscripten'
use_bluescreen = false
can_install_enforce_no = true
@ -41,6 +53,10 @@ elif host_platform == 'linux'
'Posix.cpp',
'ExitCommon.cpp',
)
powder_files += files(
'MainCommon.cpp',
'DdirCommon.cpp',
)
else
can_install_enforce_no = true
common_files += files(
@ -48,6 +64,10 @@ else
'Posix.cpp',
'ExitCommon.cpp',
)
powder_files += files(
'MainCommon.cpp',
'DdirCommon.cpp',
)
endif
conf_data.set('SET_WINDOW_ICON', set_window_icon ? 'true' : 'false')
conf_data.set('PATH_SEP_CHAR', path_sep_char)