Skip to content

fix(android): Avoid white flash on first frame#23593

Open
MartinZikmund wants to merge 1 commit into
masterfrom
dev/mazi/render-android-whiteflash
Open

fix(android): Avoid white flash on first frame#23593
MartinZikmund wants to merge 1 commit into
masterfrom
dev/mazi/render-android-whiteflash

Conversation

@MartinZikmund

Copy link
Copy Markdown
Member

Avoids the white flash between Android splash-screen dismissal and the first Skia paint.

The splash is held (OnPreDraw keeps returning false) until the GL thread has flushed the first Skia frame. A volatile bool FirstFrameRendered is set on the GL thread after the first _context.Flush(), which posts an invalidation so OnPreDraw re-evaluates and dismisses the splash only once pixels are actually ready.

Validation

  • Compile: Uno.UI.Runtime.Skia.Android.csproj (net10.0-android) builds clean — 0 errors (pre-existing XA0101 @(Content) warning only).
  • Runtime: pending device / CI.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KBAigLEAf3csGwnWE22Yr5

Hold the splash screen (OnPreDraw) until the GL thread has flushed the first Skia frame, so it is dismissed only once pixels are ready.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KBAigLEAf3csGwnWE22Yr5
@github-actions github-actions Bot added platform/android 🤖 Categorizes an issue or PR as relevant to the Android platform area/skia ✏️ Categorizes an issue or PR as relevant to Skia labels Jun 29, 2026
@github-actions

github-actions Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MartinZikmund's task in 2m 49s —— View job


PR Review: fix(android): Avoid white flash on first frame

  • Gather context and understand request
  • Read changed files
  • Review code for correctness, threading, and style
  • Post inline comments
  • Post summary

Summary

Verdict: fix-first — 1 blocking issue.

The mechanism is correct for the OpenGL path: a volatile bool FirstFrameRendered written on the GL thread after _context.Flush(), with a Post(Invalidate) to wake the main thread so OnPreDraw re-evaluates and dismisses the splash. The volatile write/read pairing across GL and UI threads is sound.

Blocking (1)

  • Vulkan path not covered. UnoSKVulkanView.RenderFrame() renders frames but never sets ApplicationActivity.Instance.FirstFrameRendered = true. With FeatureConfiguration.Rendering.UseVulkanOnSkiaAndroid = true, the splash screen will be held indefinitely — effectively a frozen-UI regression on Vulkan devices. The same signaling block from UnoSKCanvasView (set flag → Post(Invalidate)) needs to be placed after _vulkanContext.RenderFrame(...) in UnoSKVulkanView. (inline comment on UnoSKCanvasView.cs:220)

Informational (no action required)

  • The XML doc comment on the internal volatile bool FirstFrameRendered field is a bit verbose for an internal field per the repo's comment style (prefer a short single-line comment explaining the non-obvious why). Not a blocker.
  • The _contentViewAttachedToWindow flag is only set/read on the main thread; FirstFrameRendered is written on the render thread and read on the main thread. The volatile qualifier is the correct and sufficient synchronization primitive here.
  • The RelativeLayout?.Post(() => RelativeLayout?.Invalidate()) double null-check on the static field is defensive and harmless.

Runtime validation pending — as noted in the PR description, device/CI confirmation is still outstanding.


_context!.Flush();

if (!ApplicationActivity.Instance.FirstFrameRendered)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The equivalent signaling is missing from UnoSKVulkanView.RenderFrame(). When FeatureConfiguration.Rendering.UseVulkanOnSkiaAndroid = true, the Vulkan renderer renders frames but never sets FirstFrameRendered = true, so OnPreDraw() keeps returning false and the splash screen is held forever.

The same block (set flag → post Invalidate) should be placed after _vulkanContext.RenderFrame(...) in UnoSKVulkanView.RenderFrame().

Fix this →

@unodevops

Copy link
Copy Markdown
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here: https://unowasmprstaging.z20.web.core.windows.net/pr-23593/wasm-skia-net9/index.html

@nventive-devops

Copy link
Copy Markdown
Contributor

The build 220110 found UI Test snapshots differences: skia-linux-screenshots: 57, skia-windows-screenshots: 2348, wasm: 11

Details
  • skia-linux-screenshots: 57 changed over 2348

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • ContextRequested.png-dark
    • ContextRequested.png
    • DisplayInformation.png-dark
    • ButtonClippingTestsControl.png-dark
    • ButtonClippingTestsControl.png
    • ClipboardTests.png-dark
    • DropDownButtonPage.png-dark
    • DropDownButtonPage.png
    • Focus_FocusVisual_Properties.png-dark
    • ElementLevelTheme.png-dark
    • ElementLevelTheme.png
    • Buttons.png-dark
    • Buttons.png
    • CalendarView_Theming.png-dark
    • CalendarView_Theming.png
    • Examples.png-dark
    • Examples.png
    • ExpanderColorValidationPage.png-dark
    • ExpanderColorValidationPage.png
    • Gamepad_CurrentReading.png-dark
  • skia-windows-screenshots: 2348 changed over 2366

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • Accessibility_ScreenReader.png-dark
    • AppBarToggleButtonTest.png-dark
    • AppBar_KeyBoard.png-dark
    • AndroidWindowInsets.png-dark
    • AnimatedIconPage.png-dark
    • AppBarButtonWithIconTest.png-dark
    • AndroidWindowInsets.png
    • AppXamlDefinedResources.png
    • Attributed_text_Supserscript.png-dark
    • AppWindowFeatures.png
    • AppWindowTitleBar Properties.png-dark
    • ApplicationViewSpanningRectsPage.png-dark
    • Arrange_Performance01.png
    • ApplicationViewSizing.png-dark
    • AutoBorderStretchwithtopmargin.png-dark
    • AutoSizedTopLeft.png-dark
    • AppWindowTitleBar Properties.png
    • Attributed_text_Simple.png
    • Attributed_text_Supserscript.png
    • AutoBorderStretchwithleftmargin.png-dark
  • wasm: 11 changed over 1076

    🚨🚨 Comparison Details (first 20) 🚨🚨
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Ogg_Extension
    • UITests.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_NavigationProperties
    • UITests.Shared.Windows_UI_Xaml_Controls.MediaPlayerElement.MediaPlayerElement_Minimal
    • UITests.Windows_UI_Xaml_Media_Animation.ColorAnimation_Background
    • UITests.Uno_Web.Http.CookieManagerTests
    • SamplesApp.Wasm.Windows_UI_Xaml_Controls.ListView.ListView_IsSelected
    • Uno.UI.Samples.Content.UITests.WebView.WebView_AnchorNavigation
    • SamplesApp.Windows_UI_Xaml_Controls.ListView.ListViewSelectedItems
    • UITests.Shared.Microsoft_UI_Xaml_Controls.ExpanderTests.WinUIExpanderPage
    • SamplesApp.Microsoft_UI_Xaml_Controls.WebView2Tests.WebView2_EnableDevTools
    • UITests.Windows_UI_Xaml_Controls.CalendarView.CalendarView_Theming

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/skia ✏️ Categorizes an issue or PR as relevant to Skia platform/android 🤖 Categorizes an issue or PR as relevant to the Android platform

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants