Add rendering frame-rate diagnostics and bump Nucleus to 2.5.5 - #58
Merged
Conversation
Issue #57 asks whether the Tao desktop backend renders offscreen or caps the frame rate, and whether a max_fps knob could be exposed. It does not: every desktop backend embeds a real native view (WKWebView NSView under the Compose Metal layer, reparented WebKit2GTK widget, WebView2 DComp visual) and no backend contains frame-rate logic. Measured on macOS/M4 with a 90 Hz display, embedded vs. a bare WKWebView in a plain NSWindow: 90 vs 90 fps for canvas/WebGL, 31-34 vs 32-35 fps on a GPU-bound shader — parity in both cases. - e2e-shared: new Rendering group in the shared catalog. R01 reports the requestAnimationFrame rate, R02 the WebGL renderer (a software renderer explains slow WebGL better than any fps number). R01 is Skipped when the document is hidden: every engine suspends rAF for an occluded window, so the sample would read 0 fps and say nothing about the backend. - e2e-shared: runMeasuredCase / SuiteSkip so a case can publish its measurement as the reported detail, and the suite UI + console keep showing details for passed cases. - Bump Nucleus 2.3.1 -> 2.5.5 (the version this library api-exports, so consumers inherit it). - README: document the rendering model, the absence of any throttle or max_fps knob, and how to measure it locally.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #57 — the issue stays open until the reporter confirms on their 120 Hz ProMotion hardware.
Rationale
#57 asks whether the Tao desktop backend renders the page offscreen, whether something caps it near 30 FPS, and whether a
max_fpsAPI could be exposed.It does not, and there is nothing to expose: every desktop backend embeds a real native view (macOS
WKWebViewNSViewbelow the Compose Metal layer with a punched hole, Linux WebKit2GTK widget reparented into Tao's content widget, Windows WebView2 as a DirectComposition visual). No backend contains frame-rate logic —grepfor fps/frame/vsync/timer overwebview-compose/src/jvmMain/native/**comes back empty. Pacing is entirely Nucleus Tao + the OS compositor.Measured on macOS / M4 / 90 Hz display, embedded WebView vs. the same page in a bare
WKWebViewin a plainNSWindow:NativeView)WKWebViewrAFCompose rendered at 90 fps in the same window at the same time. Since the answer is "nothing here caps it", this PR makes that verifiable on any machine instead of a matter of opinion — the reporter is likely on a 120 Hz ProMotion display, which I have no hardware to test.
Summary
e2e-shared: newRenderinggroup in the shared catalogR01reports therequestAnimationFramerate (e.g.90 fps); fails only below 10 fps, i.e. a frozen page.R02reports the WebGL renderer (e.g.Apple GPU) — a software renderer explains slow WebGL better than any fps number.R01is Skipped when the document ishidden: every engine suspendsrAFfor an occluded/backgrounded window, so the sample would read 0 fps and say nothing about the backend. Verified that a bareWKWebViewbehaves identically, so this is not a Tao artifact.runMeasuredCase/SuiteSkipso a case can publish its measurement as the reported detail; suite UI and console now keep showing details on passed cases instead ofok.api-exportsdecorated-window-tao, so consumers inherit this version. Rendering behaviour is identical to 2.3.1 (bisected 2.4.0 / 2.5.0 / 2.5.2 / 2.5.3 / 2.5.4 / 2.5.5: 90 fps everywhere).max_fpsknob, how to measure locally, reference numbers.Blending cost of the Compose overlay
Measured separately, since hole-punch blending is the obvious suspect. Full-screen window (2560×1040), animated Compose overlay in the
contentslot, page fps / Compose fps, plus GPU utilization sampled while both run at the display rate:WKWebView, opaque windowNo measurable blending penalty on this hardware — but it is a weak stress case (2560×1040 @1x, 90 Hz, desktop M4 ≈ 2.7 Mpx/frame) versus a Retina ProMotion laptop (≈ 7.7 Mpx at 120 Hz, ~4× the compositing bandwidth), so this does not rule it out there.
Side finding, now documented: an opaque Compose overlay does not stop the WebView underneath — it keeps rendering at full speed behind it, so the GPU work is duplicated.
Not included
Compose Multiplatform 1.12.0 is blocked: its Android artifacts require
compileSdk 37and AGP ≥ 9.1, and since AGP 9.0com.android.library/com.android.applicationare incompatible with the Kotlin Multiplatform plugin. Adopting it means migratingwebview-composeande2e-sharedtocom.android.kotlin.multiplatform.library, convertinge2e-androidto a non-KMP module, and updating the test task names in CI — a separate PR.Test plan
./gradlew :e2e-desktop:run(macOS / M4) —SUITE_FINISHED passed=true,R02 → Apple GPU,R01 → 90 fpswith the window in front,Skippedwhen occluded./gradlew :webview-compose:jvmTest :webview-compose:testDebugUnitTestwith the standardcommonTestfilters:e2e-sharedcompiles for wasmJs, Android and iOS simulatorR01value on a 120 Hz ProMotion Mac (the hardware in Offscreen rendering fps (Tao backend) #57)