fix(web): use adapter limits so /play renders at native res (no 2048 cap) #101

Merged
funman300 merged 1 commits from test/web-adapter-limits into master 2026-06-24 16:20:08 +00:00
2 changed files with 23 additions and 43 deletions
Showing only changes of commit 81893788c1 - Show all commits
+4 -17
View File
@@ -7,23 +7,10 @@
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; background: #000; overflow: hidden; }
/* Cap the canvas at WebGL2's 2048 max texture dimension (this mirrors
the Window `resize_constraints` in solitaire_web/src/lib.rs — winit
applies that constraint as the canvas's own max-width/max-height).
On wasm Bevy creates the device with downlevel_webgl2_defaults()
whose max_texture_dimension_2d is a fixed 2048, so a larger surface
(e.g. a 4K display at 150% scale → a 2560x1440 logical viewport)
makes Surface::configure panic. `max-*` directly on the canvas keeps
the surface ≤ 2048 regardless of how fit_canvas_to_parent resolves
its 100% width; `margin: 0 auto` centres the letterbox horizontally. */
#bevy-canvas {
display: block;
width: 100%;
height: 100%;
max-width: 2048px;
max-height: 2048px;
margin: 0 auto;
}
/* No size cap: the wgpu device now takes its max_texture_dimension from
the adapter (see solitaire_web/src/lib.rs), so the surface can match
the full viewport. fit_canvas_to_parent sizes the canvas to 100%. */
#bevy-canvas { display: block; width: 100%; height: 100%; }
</style>
</head>
<body>
+19 -26
View File
@@ -13,7 +13,7 @@ use bevy::asset::AssetMetaCheck;
use bevy::prelude::*;
use bevy::render::RenderPlugin;
use bevy::render::settings::{RenderCreation, WgpuSettings, WgpuSettingsPriority};
use bevy::window::{Window, WindowPlugin, WindowResizeConstraints, WindowResolution};
use bevy::window::{Window, WindowPlugin, WindowResolution};
use solitaire_data::LocalOnlyProvider;
use solitaire_engine::CoreGamePlugin;
use wasm_bindgen::prelude::*;
@@ -34,27 +34,15 @@ pub fn start() {
fit_canvas_to_parent: true,
// Prevent the browser stealing keyboard events and scroll.
prevent_default_event_handling: true,
// Force scale_factor = 1.0 so the wgpu surface is sized in
// CSS/logical pixels rather than physical pixels. Without this,
// HiDPI displays (devicePixelRatio ≥ 2) produce a framebuffer
// whose physical width can exceed WebGL2's 2048-pixel per-
// dimension limit, causing a wgpu validation panic on the first
// resize event and killing the WASM thread.
// Render at CSS/logical pixels (scale_factor 1.0) rather
// than physical (CSS × devicePixelRatio). This keeps the
// surface smaller on HiDPI displays — lighter GPU load and
// stable sizing — at the cost of some crispness. The wgpu
// texture-dimension limit is now taken from the adapter (see
// the RenderPlugin below), so this is purely a quality/perf
// choice, no longer a crash-avoidance hack.
resolution: WindowResolution::default()
.with_scale_factor_override(1.0),
// Cap the surface at WebGL2's max texture dimension (2048).
// On wasm Bevy creates the device with
// `Limits::downlevel_webgl2_defaults()` (max_texture_dimension_2d
// = 2048), so a larger surface — e.g. a 4K display at 150% scale
// gives a 2560x1440 logical viewport — makes Surface::configure
// panic on the first frame. winit maps this constraint to the
// canvas's `max-width`/`max-height` style, so the surface can
// never exceed it. Viewports wider/taller than 2048 letterbox.
resize_constraints: WindowResizeConstraints {
max_width: 2048.0,
max_height: 2048.0,
..default()
},
..default()
}),
..default()
@@ -66,14 +54,19 @@ pub fn start() {
meta_check: AssetMetaCheck::Never,
..default()
})
// WebGL2 priority constrains naga (the shader translator) to emit
// GLES 300es-compatible GLSL. Without this, Chromium's ANGLE driver
// rejects certain shader constructs (storage buffers, tight component
// limits) causing a fatal wgpu "Shader translation error". Firefox is
// more lenient; this setting makes both browsers work identically.
// `Functionality` makes wgpu adopt the *adapter's* real limits
// instead of the conservative `downlevel_webgl2_defaults()` that
// `WebGL2` priority forces. On the WebGL2 (Gl) backend the adapter
// already reports WebGL2-constrained features/limits — no storage
// buffers, etc., so shaders stay GLES-compatible on both Firefox and
// Chromium — but it reports the GPU's *true* `max_texture_dimension`
// (e.g. 16384) rather than 2048. The device is requested with exactly
// what the adapter offers, so creation can't fail, and the surface is
// no longer capped at 2048: large viewports (4K, etc.) render natively
// with no letterbox and no hardcoded cap.
.set(RenderPlugin {
render_creation: RenderCreation::Automatic(WgpuSettings {
priority: WgpuSettingsPriority::WebGL2,
priority: WgpuSettingsPriority::Functionality,
..default()
}),
..default()