fix(web): use adapter limits (Functionality) so /play renders at native res

The 2048 surface limit was never wgpu's or the GPU's — it's
downlevel_webgl2_defaults().max_texture_dimension_2d (2048), which
WgpuSettingsPriority::WebGL2 forces. Switch to Functionality: on the WebGL2
(Gl) backend Bevy then adopts the adapter's real limits, which are still
WebGL2-constrained for features/buffers (shaders stay GLES-compatible) but
report the GPU's true max texture dimension (e.g. 16384). The device is
requested with exactly what the adapter offers, so creation can't fail, the
surface is no longer capped, and large viewports (4K) render with no letterbox
and no hardcoded cap.

Removes the resize_constraints cap and the play.html max-width/height caps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
funman300
2026-06-24 09:18:07 -07:00
parent 56e05caaa9
commit 81893788c1
2 changed files with 23 additions and 43 deletions
+4 -17
View File
@@ -7,23 +7,10 @@
<style> <style>
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; background: #000; overflow: hidden; } html, body { height: 100%; background: #000; overflow: hidden; }
/* Cap the canvas at WebGL2's 2048 max texture dimension (this mirrors /* No size cap: the wgpu device now takes its max_texture_dimension from
the Window `resize_constraints` in solitaire_web/src/lib.rs — winit the adapter (see solitaire_web/src/lib.rs), so the surface can match
applies that constraint as the canvas's own max-width/max-height). the full viewport. fit_canvas_to_parent sizes the canvas to 100%. */
On wasm Bevy creates the device with downlevel_webgl2_defaults() #bevy-canvas { display: block; width: 100%; height: 100%; }
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;
}
</style> </style>
</head> </head>
<body> <body>
+19 -26
View File
@@ -13,7 +13,7 @@ use bevy::asset::AssetMetaCheck;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::RenderPlugin; use bevy::render::RenderPlugin;
use bevy::render::settings::{RenderCreation, WgpuSettings, WgpuSettingsPriority}; 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_data::LocalOnlyProvider;
use solitaire_engine::CoreGamePlugin; use solitaire_engine::CoreGamePlugin;
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@@ -34,27 +34,15 @@ pub fn start() {
fit_canvas_to_parent: true, fit_canvas_to_parent: true,
// Prevent the browser stealing keyboard events and scroll. // Prevent the browser stealing keyboard events and scroll.
prevent_default_event_handling: true, prevent_default_event_handling: true,
// Force scale_factor = 1.0 so the wgpu surface is sized in // Render at CSS/logical pixels (scale_factor 1.0) rather
// CSS/logical pixels rather than physical pixels. Without this, // than physical (CSS × devicePixelRatio). This keeps the
// HiDPI displays (devicePixelRatio ≥ 2) produce a framebuffer // surface smaller on HiDPI displays — lighter GPU load and
// whose physical width can exceed WebGL2's 2048-pixel per- // stable sizing — at the cost of some crispness. The wgpu
// dimension limit, causing a wgpu validation panic on the first // texture-dimension limit is now taken from the adapter (see
// resize event and killing the WASM thread. // the RenderPlugin below), so this is purely a quality/perf
// choice, no longer a crash-avoidance hack.
resolution: WindowResolution::default() resolution: WindowResolution::default()
.with_scale_factor_override(1.0), .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()
}), }),
..default() ..default()
@@ -66,14 +54,19 @@ pub fn start() {
meta_check: AssetMetaCheck::Never, meta_check: AssetMetaCheck::Never,
..default() ..default()
}) })
// WebGL2 priority constrains naga (the shader translator) to emit // `Functionality` makes wgpu adopt the *adapter's* real limits
// GLES 300es-compatible GLSL. Without this, Chromium's ANGLE driver // instead of the conservative `downlevel_webgl2_defaults()` that
// rejects certain shader constructs (storage buffers, tight component // `WebGL2` priority forces. On the WebGL2 (Gl) backend the adapter
// limits) causing a fatal wgpu "Shader translation error". Firefox is // already reports WebGL2-constrained features/limits — no storage
// more lenient; this setting makes both browsers work identically. // 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 { .set(RenderPlugin {
render_creation: RenderCreation::Automatic(WgpuSettings { render_creation: RenderCreation::Automatic(WgpuSettings {
priority: WgpuSettingsPriority::WebGL2, priority: WgpuSettingsPriority::Functionality,
..default() ..default()
}), }),
..default() ..default()