Skip to content

Rebuild the Android swapchain at the window's size after a rotation - #45

Merged
Xget7 merged 2 commits into
mainfrom
fix-android-rotation
Oct 20, 2026
Merged

Xget7 merged 2 commits into
mainfrom
fix-android-rotation

Conversation

@Xget7

@Xget7 Xget7 commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Summary

Android reports a surface's new size only after a frame is presented, so a swapchain rebuilt inside resize came back at the old size and nothing rebuilt it again once the pre-transform matched (portrait).

resize(w, h)                                  VulkanSurface
  windowExtent_ = (w, h)
  caps.currentExtent == window ?
    yes: rebuild now
    no:  keep the swapchain, rebuildPending() = true

render()                                      SplatEngine
  renderer.surfaceRebuildPending() -> redrawNeeded_
  draw -> present -> caps update
    rebuildIfChanged: swapchain != window and caps == window -> rebuild
  a surface that never reports the window's size settles on its own size after 60 frames
  • VulkanSurface keeps the window's size as the target and no longer depends on SUBOPTIMAL; pre-transform, present modes and formats are untouched.
  • SplatRenderer::surfaceRebuildPending() (default false, so Metal is unchanged) keeps the on-demand engine presenting until the rebuild lands.

Evidence

  • Before: main 9341a09, portrait -> landscape -> portrait. The last swapchain is the landscape size under a portrait window, and it never recovers.
    Screenshots: /Users/xget/.rn-build-external/smoke-android/rot-main/3-portrait-again.png, /Users/xget/.rn-build-external/smoke-android/rot-main/4-now.png; log /Users/xget/.rn-build-external/smoke-android/rot-main/log.txt.
    surface changed to 2265x1080, display rotation 1
    Swapchain 1080x2261
    Swapchain 2265x1080
    surface changed to 1080x2261, display rotation 0
    Swapchain 2265x1080
    
    After: rotations 0, 1, 0, 3, 0, five seconds each, and a background and resume. Every step ends on a swapchain of the window's size and the kitchen is undistorted.
    Screenshots: /Users/xget/.rn-build-external/rotation-after/{1-rot0,2-rot1,3-rot0,4-rot3,5-rot0,6-resume}.png; log /Users/xget/.rn-build-external/rotation-after/log.txt.
    surface changed to 2265x1080, display rotation 1
    surface resized to 2265x1080, swapchain was 1080x2261
    surface now reports 2265x1080
    Swapchain 2265x1080
    surface changed to 1080x2261, display rotation 0
    surface resized to 1080x2261, swapchain was 2265x1080
    surface now reports 1080x2261
    Swapchain 1080x2261
    
    The HUD reads idle afterwards, so the engine stops drawing once the swapchain converges.
  • Where it ran: physical Xiaomi Mi 9, Android 11, Adreno 640 (Vulkan 1.1.128), release build, kitchen world with 500,000 splats. No emulator.
  • Checks:
    • ran: FrameOrder.RendererWithAPendingSurfaceRebuildKeepsTheEngineDrawingUntilItSettles, written first and failing (1 draw, expected 3), then passing with the full engine suite (283 tests, kitchen fixtures skipped);
    • ran: scripts/lint-cpp.sh clean, :splatkit:assembleRelease :app:assembleRelease :splatkit:testDebugUnitTest, the host WorldFrameCompletion check;
    • skipped: iOS, React Native and the Android validation layer (release build only on the device);
    • the 60-frame fallback for a surface that never reports the window's size has no device or host test.

Merge Danger

Door: Two-way.

Blast Radius: Android

Every Android swapchain rebuild now goes through the new size check, including vsync and linear blending changes.
The engine interface gains one defaulted method, so the Metal renderer and its mirrors are unaffected.

@Xget7
Xget7 force-pushed the fix-android-rotation branch from 9a4ea78 to d77ab40 Compare October 20, 2026 14:10
@Xget7
Xget7 merged commit ddd53b5 into main Oct 20, 2026
22 checks passed
@Xget7
Xget7 deleted the fix-android-rotation branch October 20, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant