Skip to content

fix(service): update viewport on GL thread per rotation, reuse EGL surface - #14

Merged
kxxoling merged 1 commit into
mainfrom
bugfix/rotation-surface-coverage
Aug 27, 2026
Merged

fix(service): update viewport on GL thread per rotation, reuse EGL surface#14
kxxoling merged 1 commit into
mainfrom
bugfix/rotation-surface-coverage

Conversation

@kxxoling

Copy link
Copy Markdown
Owner

Fix wallpaper covering only a screen corner after rotation

Problem

After rotating the device (landscape ⇄ portrait), the wallpaper only covered a corner region of the screen (bottom-left or bottom-right). The rest of the screen showed the compositor background.

Root cause

Engine.onSurfaceChanged called renderer.onSurfaceChanged on the UI thread. The orthographic matrix update (plain memory) took effect, but glViewport is a GL call and the EGL context is current on the GL thread — a context can only be current on one thread at a time — so the call was silently dropped. The viewport kept the old orientation while the projection used the new one, squeezing the scene into the old viewport rectangle.

Additionally, the EGL window surface was never recreated when the system destroyed and recreated the Surface, leaving swaps silently failing into a dead native window (the swap return value was never checked). This was a latent bug on ROMs that recreate the Surface on rotation.

Fix

Route the surface lifecycle through the GL thread via volatile flags instead of touching GL state from the engine thread:

  • Plain resize (typical rotation): the EGL window surface follows the native window size, so only renderer.onSurfaceChanged (viewport + projection) runs on the GL thread — no EGL rebuild, no white flash. The GL surface and textures stay fully reused, matching the pre-fix behavior.
  • Surface destroy/recreate: the EGL window surface is released (context kept, so textures/programs survive) and rebuilt from the holder's current Surface, retrying on a later frame if the surface is not valid yet.
  • The initial size is seeded from the holder at thread start, since engine notifications may predate thread startup.

On the tested device, rotation resizes the surface in place, so the resize path is the exercised one; the destroy/recreate path is a robustness fix for ROMs that recreate the Surface.

Testing

  • Verified on a real device: landscape → portrait → landscape rotations keep the background covering the full screen with no white flash; drag, double-tap reset, and lock/unlock transitions are unaffected.
  • compileDebugKotlin, testDebugUnitTest, ktlintCheck pass.

…rface

Symptom: after rotating the device the wallpaper only covered a
corner region of the screen (bottom-left or bottom-right).

Root cause: Engine.onSurfaceChanged called renderer.onSurfaceChanged
on the UI thread. The orthographic matrix update (plain memory) took
effect, but glViewport is a GL call and the EGL context is current on
the GL thread, so the call was silently dropped - the viewport kept
the old orientation and the newly-projected scene was squeezed into
the old viewport rectangle. Additionally the EGL window surface was
never recreated when the system destroyed and recreated the Surface,
leaving swaps silently failing into a dead native window.

Fix: route surface lifecycle through the GL thread.
- Engine.onSurfaceCreated/Changed/Destroyed notify the GL thread via
  volatile flags instead of touching GL state directly.
- A plain resize (typical rotation): the EGL window surface follows
  the native window, so only renderer.onSurfaceChanged (viewport +
  projection) runs on the GL thread - no EGL rebuild, no white flash,
  matching the pre-fix reuse behavior.
- Surface destroy/recreate: release the EGL window surface (context
  kept, textures/programs survive) and rebuild it from the current
  holder Surface, retrying next frame if not valid yet.
- The initial size is taken from the holder at thread start since
  engine notifications may predate thread startup.
@kxxoling
kxxoling merged commit 5bd1e4b into main Aug 27, 2026
1 check passed
@kxxoling
kxxoling deleted the bugfix/rotation-surface-coverage branch August 27, 2026 21:47
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