From 6655ec7eedc789afcfb586db35ba5968dcd461ef Mon Sep 17 00:00:00 2001 From: Viet Dinh <54ckb0y789@gmail.com> Date: Thu, 10 Oct 2024 21:53:54 -0400 Subject: [PATCH] Reset UI on WebGL context loss On Emscripten, the WebGL context may be loss for any reason, for example when restoring the application from the background, the GPU force- refreshed the application to reclaim memory, etc. In these cases, canvas data is lost and this commit accommodates that situation by reinitiali- zing the UI when the browser has restored the context. --- resources/emscripten/emscripten-pre.js | 6 ++++-- src/platform/emscripten/interface.cpp | 8 ++++++++ src/platform/emscripten/interface.h | 1 + src/platform/emscripten/main.cpp | 7 ++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/resources/emscripten/emscripten-pre.js b/resources/emscripten/emscripten-pre.js index 40bac40dd4..c720cd7583 100644 --- a/resources/emscripten/emscripten-pre.js +++ b/resources/emscripten/emscripten-pre.js @@ -15,13 +15,15 @@ Module = { ...Module, canvas: (() => { const canvas = document.getElementById('canvas'); - // As a default initial behavior, pop up an alert when webgl context is lost // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 canvas.addEventListener('webglcontextlost', event => { - alert('WebGL context lost. You will need to reload the page.'); event.preventDefault(); }, false); + canvas.addEventListener('webglcontextrestored', () => { + Module.api.resetCanvas(); + }); + return canvas; })(), diff --git a/src/platform/emscripten/interface.cpp b/src/platform/emscripten/interface.cpp index a57e9c9ff7..ccbd7b42a7 100644 --- a/src/platform/emscripten/interface.cpp +++ b/src/platform/emscripten/interface.cpp @@ -24,6 +24,7 @@ #include "system.h" #include "async_handler.h" +#include "baseui.h" #include "filefinder.h" #include "filesystem_stream.h" #include "player.h" @@ -159,6 +160,12 @@ bool Emscripten_Interface_Private::UploadFontStep2(std::string filename, int buf return true; } +bool Emscripten_Interface::ResetCanvas() { + DisplayUi.reset(); + DisplayUi = BaseUi::CreateUi(Player::screen_width, Player::screen_height, Player::ParseCommandLine()); + return DisplayUi != nullptr; +} + // Binding code EMSCRIPTEN_BINDINGS(player_interface) { emscripten::class_("api") @@ -173,6 +180,7 @@ EMSCRIPTEN_BINDINGS(player_interface) { #endif .class_function("refreshScene", &Emscripten_Interface::RefreshScene) .class_function("takeScreenshot", &Emscripten_Interface::TakeScreenshot) + .class_function("resetCanvas", &Emscripten_Interface::ResetCanvas) ; emscripten::class_("api_private") diff --git a/src/platform/emscripten/interface.h b/src/platform/emscripten/interface.h index 795587cc84..ae8fb360fa 100644 --- a/src/platform/emscripten/interface.h +++ b/src/platform/emscripten/interface.h @@ -29,6 +29,7 @@ class Emscripten_Interface { static void RefreshScene(); static void TakeScreenshot(); static void Reset(); + static bool ResetCanvas(); }; class Emscripten_Interface_Private { diff --git a/src/platform/emscripten/main.cpp b/src/platform/emscripten/main.cpp index b20b8f80f5..dc88edaa55 100644 --- a/src/platform/emscripten/main.cpp +++ b/src/platform/emscripten/main.cpp @@ -68,9 +68,14 @@ void main_loop() { Player::MainLoop(); if (!DisplayUi.get()) { // Yield on shutdown to ensure async operations (e.g. IDBFS saving) can finish - counter = -5; + counter = -10; } } else if (counter == -1) { + if (DisplayUi.get()) { + // we previously lost the UI and restored it, so continue doing stuff. + counter = 6; + return; + } emscripten_cancel_main_loop(); } }