Skip to content

perf: Track mounted pointer-event handlers so hit tests can early-out - #3982

Open
spydon wants to merge 1 commit into
perf/removal-teardown-bufferfrom
perf/pointer-handler-early-out
Open

perf: Track mounted pointer-event handlers so hit tests can early-out#3982
spydon wants to merge 1 commit into
perf/removal-teardown-bufferfrom
perf/pointer-handler-early-out

Conversation

@spydon

@spydon spydon commented Aug 5, 2026

Copy link
Copy Markdown
Member

Description

The root game now counts mounted components that can receive pointer events (TapCallbacks, DragCallbacks, DoubleTapCallbacks, ScaleCallbacks, SecondaryTapCallbacks), so containsEventHandlerAt, which Flutter calls on every hit test, returns immediately without walking the component tree for games without any pointer-event handlers.

Extracted from #3960 so the data-structure change there stands alone (as requested in this comment). Stacked on #3981.

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • [-] I have updated/added tests for ALL new/updated/fixed functionality.
  • [-] I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • [-] I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Related Issues

Relates to #3957

@spydon
spydon force-pushed the perf/pointer-handler-early-out branch from 7235298 to e24cd14 Compare August 5, 2026 20:18
@internal
void adjustPointerEventHandlerCount(int delta) {
_pointerEventHandlerCount += delta;
assert(_pointerEventHandlerCount >= 0);

@luanpotter luanpotter Aug 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

it might not be very actionable but can we still add a message

void onMount() {
super.onMount();
DoubleTapDispatcher.addDispatcher(this);
findRootGame()?.adjustPointerEventHandlerCount(1);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

is the extra recursive findRootGame() on every mount/unmount worth the optmization?

@luanpotter luanpotter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am again concerned with the complexity, ad-hoc-ness, and brittleness of these static/global caches and counters, that could lead to impossible to find bugs of undelivered events due to de-syncs. what if a component is removed w/o being mounted due to some edge-case, and then suddenly events stop working reliably.

I am again tempted to think more holistically, do we even need this, can't games just always return true on hitTestSelf within bounds? do we need to make this distinction of games without tap components being touch transparent, I didn't even know that was the case and doesn't feel intuitive. we also used to have and require the game-level mixins, which might be a good alternative, yes a bit more work for the user but more explicit and clear, less error-prone. or just an overridable config to make the game transparent (default false).

is there really an use case for a game that dynamically changes its tap transparency based on current components that we need to bake into the engine?

this also mixes concerns about event delivery even more into the game class instead of the dispatchers, but I am ok with that part as I might be refactoring it again once I remove all the old detectors. right now it is quite the mess already imo.

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.

2 participants