Skip to content

[Impeller] Avoid sharing scale information between TextFrame rendering calls#182539

Closed
flar wants to merge 3 commits into
flutter:masterfrom
flar:impeller-text-frame-no-render-data-sharing
Closed

[Impeller] Avoid sharing scale information between TextFrame rendering calls#182539
flar wants to merge 3 commits into
flutter:masterfrom
flar:impeller-text-frame-no-render-data-sharing

Conversation

@flar

@flar flar commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Impeller has been storing rendering data specific to a single invocation of a text operation in the TextFrame object itself. Unfortunately, the TextFrame lives (most commonly, especially in a Flutter app) in the DisplayList which should be an immutable data store. Even more importantly, DisplayLists can be shared and appear multiple times in different graphics contexts within a single frame. This potentially means that Impeller might store "this TextFrame is rendering at a scale of 2x" and "this TextFrame is rendering at a scale of 50x" into the same TextFrame object in the same scene and then try to render that TextFrame with the most recently stored information for both instances. This issue was discovered during a code read of the way that glyph caches are managed in Impeller as mentioned in the targeted issue:

Fixes: #177424

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions Bot added a: text input Entering text in a text field or keyboard related problems engine flutter/engine related. See also e: labels. e: impeller Impeller rendering backend issues and features requests labels Feb 18, 2026
@flar flar requested a review from eyebrowsoffire February 18, 2026 11:40
@flar

flar commented Feb 18, 2026

Copy link
Copy Markdown
Contributor Author

I'm seeing some flashing text running Wondrous that I need to investigate...

@flar

flar commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

I tracked the problem down to a mismatch of the drawText operations encountered during the FirstPass and the eventual Render pass. See #182639 for a full writeup.

It looks like the cull rects we use when traversing the Frame's DL during the FirstPass can sometimes be larger than the cull rects we use during the rendering pass.

Log of cull rects encountered during a Wondrous frame that skipped a drawText call
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1347)] Render2Target first pass cull rect: ((0, 0) => (1080, 2400))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, 0) => (411.429, 914.286))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, 0) => (411.429, 313))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, 0) => (411.429, 914.286))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, -501.719) => (411.429, 412.567))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, 0) => (411.429, 914.286))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, 0) => (411.429, 914.286))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((0, -820.286) => (411.429, 94))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((-9.82143, -808.286) => (401.607, 106))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((-88.1786, -825.286) => (323.25, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((-166.536, -825.286) => (244.893, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((-244.893, -825.286) => (166.536, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1164)]   FirstPass cull rect: ((-323.25, -825.286) => (88.1786, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(1369)] Render2Target render cull rect: ((0, 0) => (1080, 2400))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, 0) => (411.429, 914.286))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, 0) => (411.429, 313))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, 0) => (411.429, 820.19))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, -501.719) => (411.429, 318.471))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, 0) => (411.429, 820.19))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, 0) => (411.429, 820.19))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(863)] Skipped 1 RenderTextFrames
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((0, -820.286) => (411.429, 94))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((-9.82143, -808.286) => (401.607, 106))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((-88.1786, -825.286) => (323.25, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((-166.536, -825.286) => (244.893, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((-244.893, -825.286) => (166.536, 89))
E/flutter (25172): [ERROR:flutter/impeller/display_list/dl_dispatcher.cc(825)]   DispatcherBase cull rect: ((-323.25, -825.286) => (88.1786, 89))

@flar

flar commented Feb 19, 2026

Copy link
Copy Markdown
Contributor Author

I've implemented a basic workaround for the issue I discovered while debugging the Wondrous behavior. I basically just skip RenderTextFrames until I find one that is appropriate for the call site, but...

  • The comparison should be more complete, checking more than just the pointer identity of the TextFrame
  • This is implemented assuming that the RenderTextFrame list is a superset of what the rendering code needs (which is true for all observed cases, but can't be guaranteed)
  • A more flexible workaround should be implemented that uses a Map and compares more of the critical information used by the glyph atlas.

An interesting side note - if we pass this information as a map then we could save it from frame to frame and avoid having to recompute bounds. Unfortunately, bounds are computed in device space and are sub-pixel based in some cases so this idea would only work for static text that isn't scrolling.

@flar

flar commented Feb 27, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of a better solution in #182886

@flar flar closed this Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems e: impeller Impeller rendering backend issues and features requests engine flutter/engine related. See also e: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[impeller] TextFrame::SetPerFrameData is weird and possibly buggy

1 participant