web: Add preferred renderer config
This commit is contained in:
parent
569e822044
commit
1e3701279c
|
@ -35,4 +35,5 @@ export const DEFAULT_CONFIG: Required<BaseLoadOptions> = {
|
|||
publicPath: null,
|
||||
polyfills: true,
|
||||
playerVersion: null,
|
||||
preferredRenderer: null,
|
||||
};
|
||||
|
|
|
@ -117,6 +117,39 @@ export const enum WindowMode {
|
|||
Gpu = "gpu",
|
||||
}
|
||||
|
||||
/**
|
||||
* The render backend of a Ruffle player.
|
||||
*/
|
||||
export const enum RenderBackend {
|
||||
/*
|
||||
* A draft API that is currently unavailable, but will be preferred if available in the future.
|
||||
* Should behave the same as wgpu-webgl, except with lower overhead and thus better performance.
|
||||
*/
|
||||
WebGpu = "webgpu",
|
||||
|
||||
/*
|
||||
* The most featureful and currently preferred backend.
|
||||
* Rendering is done the same way as in the desktop app, then translated to WebGL on-the-fly.
|
||||
*/
|
||||
WgpuWebgl = "wgpu-webgl",
|
||||
|
||||
/*
|
||||
* A vanilla WebGL backend. Was previously the default backend,
|
||||
* but is now used as a fallback for devices that do not support WebGL 2.
|
||||
* Supports fewer features and has a faster initialization time;
|
||||
* may be useful for content that does not need advanced features like bitmap drawing or blend modes.
|
||||
*/
|
||||
Webgl = "webgl",
|
||||
|
||||
/*
|
||||
* The slowest and most basic backend, used as a fallback when all else fails.
|
||||
* However, this is currently the only backend that accurately scales hairline strokes.
|
||||
* If you notice excessively thick strokes in specific content,
|
||||
* you may want to use the canvas renderer for that content until the issue is resolved.
|
||||
*/
|
||||
Canvas = "canvas",
|
||||
}
|
||||
|
||||
/**
|
||||
* Any options used for loading a movie.
|
||||
*/
|
||||
|
@ -326,6 +359,20 @@ export interface BaseLoadOptions {
|
|||
*/
|
||||
playerVersion?: number | null;
|
||||
|
||||
/**
|
||||
* The preferred render backend of the Ruffle player.
|
||||
*
|
||||
* This option should only be used for testing;
|
||||
* The available backends may change in future releases.
|
||||
* By default, Ruffle chooses the most featureful backend supported by the user's system,
|
||||
* falling back to more basic backends if necessary.
|
||||
* The available values in order of default preference are:
|
||||
* "webgpu", "wgpu-webgl", "webgl", "canvas".
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
preferredRenderer?: RenderBackend | null;
|
||||
|
||||
/**
|
||||
* The URL at which Ruffle can load its extra files (i.e. `.wasm`).
|
||||
*
|
||||
|
|
|
@ -24,13 +24,17 @@
|
|||
<label for="ruffle_enable">Play Flash content in Ruffle</label>
|
||||
</div>
|
||||
<div class="option checkbox">
|
||||
<input type="checkbox" id="ignore_optout" />
|
||||
<label for="ignore_optout">Ignore website compatibility warnings</label>
|
||||
<input type="checkbox" id="show_swf_download" />
|
||||
<label for="show_swf_download">Show SWF download in context menu</label>
|
||||
</div>
|
||||
<div class="option checkbox">
|
||||
<input type="checkbox" id="warn_on_unsupported_content" />
|
||||
<label for="warn_on_unsupported_content">Warn on unsupported content</label>
|
||||
</div>
|
||||
<div class="option checkbox">
|
||||
<input type="checkbox" id="ignore_optout" />
|
||||
<label for="ignore_optout">Ignore website compatibility warnings</label>
|
||||
</div>
|
||||
<div class="option select">
|
||||
<select id="log_level">
|
||||
<option value="info">Info</option>
|
||||
|
@ -39,9 +43,14 @@
|
|||
</select>
|
||||
<label for="log_level">Log level</label>
|
||||
</div>
|
||||
<div class="option checkbox">
|
||||
<input type="checkbox" id="show_swf_download" />
|
||||
<label for="show_swf_download">Show SWF download in context menu</label>
|
||||
<div class="option select">
|
||||
<select id="preferred_renderer">
|
||||
<option value="webgpu">WebGPU</option>
|
||||
<option value="wgpu-webgl">Wgpu (via WebGL)</option>
|
||||
<option value="webgl">WebGL</option>
|
||||
<option value="canvas">Canvas2D</option>
|
||||
</select>
|
||||
<label for="preferred_renderer">Preferred renderer</label>
|
||||
</div>
|
||||
<div class="option checkbox">
|
||||
<input type="checkbox" id="autostart" />
|
||||
|
|
|
@ -170,6 +170,8 @@ struct Config {
|
|||
max_execution_duration: Duration,
|
||||
|
||||
player_version: Option<u8>,
|
||||
|
||||
preferred_renderer: Option<String>,
|
||||
}
|
||||
|
||||
/// Metadata about the playing SWF file to be passed back to JavaScript.
|
||||
|
@ -1292,20 +1294,38 @@ async fn create_renderer(
|
|||
document: &web_sys::Document,
|
||||
config: &Config,
|
||||
) -> Result<(PlayerBuilder, HtmlCanvasElement), Box<dyn Error>> {
|
||||
#[cfg(not(any(feature = "canvas", feature = "webgpu", feature = "wgpu-webgl")))]
|
||||
#[cfg(not(any(
|
||||
feature = "canvas",
|
||||
feature = "webgl",
|
||||
feature = "webgpu",
|
||||
feature = "wgpu-webgl"
|
||||
)))]
|
||||
std::compile_error!("You must enable one of the render backend features (e.g., webgl).");
|
||||
|
||||
let _is_transparent = config.wmode.as_deref() == Some("transparent");
|
||||
|
||||
let mut renderer_list = vec!["webgpu", "wgpu-webgl", "webgl", "canvas"];
|
||||
if let Some(preferred_renderer) = &config.preferred_renderer {
|
||||
if let Some(pos) = renderer_list.iter().position(|&r| r == preferred_renderer) {
|
||||
renderer_list.remove(pos);
|
||||
renderer_list.insert(0, preferred_renderer.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create a backend, falling through to the next backend on failure.
|
||||
// We must recreate the canvas each attempt, as only a single context may be created per canvas
|
||||
// with `getContext`.
|
||||
for renderer in renderer_list {
|
||||
match renderer {
|
||||
"webgpu" => {
|
||||
#[cfg(all(feature = "webgpu", target_family = "wasm"))]
|
||||
{
|
||||
// Check that we have access to WebGPU (navigator.gpu should exist).
|
||||
if web_sys::window()
|
||||
.ok_or(JsValue::FALSE)
|
||||
.and_then(|window| js_sys::Reflect::has(&window.navigator(), &JsValue::from_str("gpu")))
|
||||
.and_then(|window| {
|
||||
js_sys::Reflect::has(&window.navigator(), &JsValue::from_str("gpu"))
|
||||
})
|
||||
.unwrap_or_default()
|
||||
{
|
||||
tracing::info!("Creating wgpu webgpu renderer...");
|
||||
|
@ -1315,14 +1335,20 @@ async fn create_renderer(
|
|||
.dyn_into()
|
||||
.map_err(|_| "Expected HtmlCanvasElement")?;
|
||||
|
||||
match ruffle_render_wgpu::backend::WgpuRenderBackend::for_canvas(&canvas).await {
|
||||
match ruffle_render_wgpu::backend::WgpuRenderBackend::for_canvas(&canvas)
|
||||
.await
|
||||
{
|
||||
Ok(renderer) => {
|
||||
return Ok((builder.with_renderer(renderer), canvas));
|
||||
}
|
||||
Err(error) => tracing::error!("Error creating wgpu webgpu renderer: {}", error),
|
||||
Err(error) => {
|
||||
tracing::error!("Error creating wgpu webgpu renderer: {}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"wgpu-webgl" => {
|
||||
#[cfg(all(feature = "wgpu-webgl", target_family = "wasm"))]
|
||||
{
|
||||
tracing::info!("Creating wgpu webgl renderer...");
|
||||
|
@ -1332,17 +1358,18 @@ async fn create_renderer(
|
|||
.dyn_into()
|
||||
.map_err(|_| "Expected HtmlCanvasElement")?;
|
||||
|
||||
match ruffle_render_wgpu::backend::WgpuRenderBackend::for_canvas(&canvas).await {
|
||||
match ruffle_render_wgpu::backend::WgpuRenderBackend::for_canvas(&canvas).await
|
||||
{
|
||||
Ok(renderer) => {
|
||||
return Ok((builder.with_renderer(renderer), canvas));
|
||||
}
|
||||
Err(error) => tracing::error!("Error creating wgpu webgl renderer: {}", error),
|
||||
Err(error) => {
|
||||
tracing::error!("Error creating wgpu webgl renderer: {}", error)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create a backend, falling through to the next backend on failure.
|
||||
// We must recreate the canvas each attempt, as only a single context may be created per canvas
|
||||
// with `getContext`.
|
||||
}
|
||||
}
|
||||
"webgl" => {
|
||||
#[cfg(feature = "webgl")]
|
||||
{
|
||||
tracing::info!("Creating WebGL renderer...");
|
||||
|
@ -1358,23 +1385,32 @@ async fn create_renderer(
|
|||
Err(error) => tracing::error!("Error creating WebGL renderer: {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
"canvas" => {
|
||||
#[cfg(feature = "canvas")]
|
||||
{
|
||||
tracing::info!("Falling back to Canvas renderer...");
|
||||
tracing::info!("Creating Canvas renderer...");
|
||||
let canvas: HtmlCanvasElement = document
|
||||
.create_element("canvas")
|
||||
.into_js_result()?
|
||||
.dyn_into()
|
||||
.map_err(|_| "Expected HtmlCanvasElement")?;
|
||||
match ruffle_render_canvas::WebCanvasRenderBackend::new(&canvas, _is_transparent) {
|
||||
match ruffle_render_canvas::WebCanvasRenderBackend::new(
|
||||
&canvas,
|
||||
_is_transparent,
|
||||
) {
|
||||
Ok(renderer) => {
|
||||
return Ok((builder.with_renderer(renderer), canvas));
|
||||
}
|
||||
Err(error) => tracing::error!("Error creating canvas renderer: {}", error),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
_ => {
|
||||
tracing::error!("Unrecognized renderer name: {}", renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err("Unable to create renderer".into())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue