From 23109b71feafaf1fd40bb3cf8b0014faafaaed6c Mon Sep 17 00:00:00 2001 From: Miguel de Benito Delgado Date: Sat, 19 Sep 2026 20:30:18 +0200 Subject: [PATCH] :bug: Fix playground rendering at non-unit device pixel ratio The playground called _init and _set_render_options with the DPR, which sets the ratio but leaves the Skia target, backbuffer and UI surfaces at CSS resolution. The canvas drawing buffer is physical (CSS x DPR), so at DPR > 1 the smaller surface anchored to the bottom-left of the framebuffer and left the top and right edges unpainted. Call _resize_viewbox after setting the DPR, the same sequence the application uses in resize-canvas!, so the renderer surfaces match the physical drawing buffer. Cover DPR 1, 1.25 and 2 in the adapter test. AI-assisted-by: deepseek-flash --- frontend/resources/wasm-playground/js/lib.js | 9 ++--- .../renderer-benchmarks/tests/adapter.test.js | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/frontend/resources/wasm-playground/js/lib.js b/frontend/resources/wasm-playground/js/lib.js index 9692ebfa22..b51e60ca06 100644 --- a/frontend/resources/wasm-playground/js/lib.js +++ b/frontend/resources/wasm-playground/js/lib.js @@ -37,13 +37,14 @@ export function createRendererAdapter(module, scheduler = globalThis) { handle = module.GL.registerContext(context, { majorVersion: 2 }); module.GL.makeContextCurrent(handle); context.getExtension("WEBGL_debug_renderer_info"); - module._init( - Math.round(canvas.width / dpr), - Math.round(canvas.height / dpr), - ); + const width = Math.round(canvas.width / dpr); + const height = Math.round(canvas.height / dpr); + module._init(width, height); module._set_render_options(0, dpr); // RawBrowser::Chrome = 1; use the same default browser as the benchmark. module._set_browser?.(1); + // Setting DPR does not resize the renderer's surfaces or framebuffer. + module._resize_viewbox(width, height); } function renderFull(flags = 4) { diff --git a/frontend/scripts/renderer-benchmarks/tests/adapter.test.js b/frontend/scripts/renderer-benchmarks/tests/adapter.test.js index eb4736ffff..2827756be9 100644 --- a/frontend/scripts/renderer-benchmarks/tests/adapter.test.js +++ b/frontend/scripts/renderer-benchmarks/tests/adapter.test.js @@ -47,6 +47,7 @@ function fixture() { }, _init() {}, _set_render_options() {}, + _resize_viewbox() {}, _set_browser() {}, _set_view_start() { calls.start++; @@ -74,6 +75,41 @@ function fixture() { return { adapter, state, calls, canvas, frames, timers, module }; } +for (const dpr of [1, 1.25, 2]) { + test(`adapter initializes the full drawing buffer at DPR ${dpr}`, () => { + const size = { width: 0, height: 0 }; + let rendererDpr = 1; + const module = { + GL: { + registerContext: () => 1, + makeContextCurrent() {}, + }, + _init(width, height) { + Object.assign(size, { width, height }); + }, + _set_render_options(_flags, value) { + rendererDpr = value; + }, + _resize_viewbox(width, height) { + // The renderer applies DPR when resizing, not when setting options. + Object.assign(size, { + width: width * rendererDpr, + height: height * rendererDpr, + }); + }, + }; + const canvas = { + width: 1920 * dpr, + height: 1080 * dpr, + getContext: () => ({ getExtension() {} }), + }; + + createRendererAdapter(module).assignCanvas(canvas, dpr); + + assert.deepEqual(size, { width: canvas.width, height: canvas.height }); + }); +} + test("wheel zoom flushes once per animation frame", () => { const f = fixture(); const wheel = (deltaY, offsetX, offsetY) =>