Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web: Reload with canvas when webglcontextlost and 8+ instances exist #19822

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ features = [
"EventTarget", "GainNode", "Headers", "HtmlCanvasElement", "HtmlDocument", "HtmlElement", "HtmlFormElement",
"HtmlInputElement", "HtmlTextAreaElement", "KeyboardEvent", "Location", "PointerEvent",
"Request", "RequestInit", "Response", "Storage", "WheelEvent", "Window", "ReadableStream", "RequestCredentials",
"Url", "Clipboard", "FocusEvent", "ShadowRoot", "Gamepad", "GamepadButton"
"Url", "WebGlContextEvent", "Clipboard", "FocusEvent", "ShadowRoot", "Gamepad", "GamepadButton"
]

[package.metadata.cargo-machete]
Expand Down
19 changes: 19 additions & 0 deletions web/packages/core/src/internal/player/inner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
DataLoadOptions,
DEFAULT_CONFIG,
NetworkingAccessMode,
RenderBackend,
UnmuteOverlay,
URLLoadOptions,
WindowMode,
Expand Down Expand Up @@ -793,6 +794,24 @@ export class InnerPlayer {
}
}

/**
* Reloads the player, as if you called {@link RufflePlayer.load} with the same config as the last time it was called, but setting the preferredRenderer to "canvas".
*
* If this player has never been loaded, this method will return an error.
* If this player was already trying to use the canvas render, this method will panic.
*/
protected async reloadWithCanvasRenderer(): Promise<void> {
if (this.loadedConfig && this.loadedConfig.preferredRenderer !== RenderBackend.Canvas) {
const combinedOptions = { ...this.loadedConfig, preferredRenderer: RenderBackend.Canvas};
await this.load(combinedOptions);
} else if (this.loadedConfig) {
this.panic(new Error(text("error-canvas-reload")));
} else {
throw new Error("Cannot reload if load wasn't first called");
}
}


/**
* Loads a specified movie into this player.
*
Expand Down
1 change: 1 addition & 0 deletions web/packages/core/texts/en-US/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ clipboard-message-description =
clipboard-message-copy = { " " } for copy
clipboard-message-cut = { " " } for cut
clipboard-message-paste = { " " } for paste
error-canvas-reload = Cannot reload with the canvas renderer when the canvas renderer is already in use.
error-file-protocol =
It appears you are running Ruffle on the "file:" protocol.
This doesn't work as browsers block many features from working for security reasons.
Expand Down
22 changes: 21 additions & 1 deletion web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use wasm_bindgen::prelude::*;
use web_sys::{
AddEventListenerOptions, ClipboardEvent, Element, Event, EventTarget, FocusEvent,
Gamepad as WebGamepad, GamepadButton as WebGamepadButton, HtmlCanvasElement, HtmlElement,
KeyboardEvent, Node, PointerEvent, ShadowRoot, WheelEvent, Window,
KeyboardEvent, Node, PointerEvent, ShadowRoot, WebGlContextEvent, WheelEvent, Window,
};

static RUFFLE_GLOBAL_PANIC: Once = Once::new();
Expand Down Expand Up @@ -137,6 +137,7 @@ struct RuffleInstance {
focusin_callback: Option<JsCallback<FocusEvent>>,
focusout_callback: Option<JsCallback<FocusEvent>>,
focus_on_press_callback: Option<JsCallback<PointerEvent>>,
webglcontextlost_callback: Option<JsCallback<WebGlContextEvent>>,
has_focus: bool,
trace_observer: Rc<RefCell<JsValue>>,
log_subscriber: Arc<Layered<WASMLayer, Registry>>,
Expand Down Expand Up @@ -193,6 +194,9 @@ extern "C" {

#[wasm_bindgen(method, js_name = "suppressContextMenu")]
fn suppress_context_menu(this: &JavascriptPlayer);

#[wasm_bindgen(method, js_name = "reloadWithCanvasRenderer")]
fn reload_with_canvas_renderer(this: &JavascriptPlayer);
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -505,6 +509,7 @@ impl RuffleHandle {
focusin_callback: None,
focusout_callback: None,
focus_on_press_callback: None,
webglcontextlost_callback: None,
timestamp: None,
has_focus: false,
trace_observer: player.trace_observer,
Expand Down Expand Up @@ -771,6 +776,21 @@ impl RuffleHandle {
},
));

// Create webglcontextlost handler.
instance.webglcontextlost_callback = Some(JsCallback::register(
&player.canvas,
"webglcontextlost",
false,
move |_js_event: WebGlContextEvent| {
INSTANCES.with(|instances| {
if instances.borrow().len() >= 8 {
let _ = ruffle.remove_instance();
js_player.reload_with_canvas_renderer();
}
});
},
));

instance.unload_callback =
Some(JsCallback::register(&window, "unload", false, move |_| {
let _ = ruffle.with_core_mut(|core| {
Expand Down
Loading