Skip to content

[Impeller] Missing SurfaceContextVK submission tracker and double HostBuffer reset #196063

Closed

Description

@andywolff

While working on #192937 to fix the snapshot memory leak in #192097 by resetting the transient HostBuffer after each snapshot, I hit flaky pixel comparison failures in transform_test.dart and canvas_test.dart. I initially landed test workarounds in #193030, #193936, and #193937 (under #193029 and #193689), but closer inspection showed those failures were caused by two Impeller HostBuffer bugs rather than rendering nondeterminism.

The core problem is that DisplayListToTexture resets the shared HostBuffer twice per snapshot, and SurfaceContextVK fails to forward its parent ContextVK's GpuSubmissionTracker. Together, these cause Vulkan snapshots to wrap the 4-slot HostBuffer ring buffer after just 2 snapshots and overwrite in-flight GPU vertex and uniform data.

In transform_test.dart and canvas_test.dart, tests capture multiple toImage snapshots back-to-back before waiting on readback. With reset_host_buffer = true, entire drawn quads were disappearing from earlier snapshots because later snapshots overwrote their buffer slots before the GPU finished rendering them.

Tracing toImage into DisplayListToTexture (dl_dispatcher.cc) shows two issues:

  1. Double reset in DisplayListToTexture: At the end of a snapshot, DisplayListToTexture calls Reset() on both GetTransientsDataBuffer() and GetTransientsIndexesBuffer(). On all non-WebGL backends, both getters return the same HostBuffer instance, so each snapshot advances the 4-slot ring buffer twice instead of once (unlike RenderToTarget, which calls context.ResetTransientsBuffers()).
  2. Missing tracker in SurfaceContextVK: Before reusing a ring-buffer slot, HostBuffer::Reset() checks context->GetSubmissionTracker() (added in [Impeller] Recycle HostBuffer arena entries only after GPU completion #188965) to see if the GPU has finished with that slot. Both flutter_tester Vulkan (TesterContextVK) and Android Vulkan (AndroidSurfaceVKImpeller) pass a SurfaceContextVK wrapper to ContentContext, and SurfaceContextVK did not override GetSubmissionTracker() to forward parent_->GetSubmissionTracker(). Receiving nullptr, HostBuffer::Reset() skips the GPU completion check and reuses in-flight slots immediately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: renderingUI glitches reported at the engine/skia or impeller rendering levele: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.platform-androidAndroid applications specificallyteam-engineOwned by Engine team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions