Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@ColdPaleLight
Copy link
Member

@ColdPaleLight ColdPaleLight commented Feb 18, 2022

When the layer tree pipeline is empty, we should early return with RasterStatus::kFailed and should not call ExternalViewEmbedder::EndFrame, otherwise there will be side effects.

fix issue: flutter/flutter#98824

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides].
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or Hixie said the PR is test-exempt. See [testing the engine] for instructions on
    writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the [CLA].
  • All existing and new tests are passing.

@ColdPaleLight ColdPaleLight changed the title Don't call 'ExternalViewEmbedder::EndFrame' when pipeline is empty Stopped calling 'ExternalViewEmbedder::EndFrame' when pipeline is empty Feb 21, 2022
@dnfield dnfield requested a review from blasten February 22, 2022 17:37
Copy link
Contributor

@cyanglaz cyanglaz left a comment

Choose a reason for hiding this comment

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

Looking at the issue, should we just fix it on the android side? It seems to be an issue with the android EndFrame implementation, rather than an issue with calling EndFrame.
The doc of EndFrame says:

  // This method provides the embedder a way to do additional tasks after
  // |SubmitFrame|. For example, merge task runners if `should_resubmit_frame`
  // is true.

So EndFrame is pretty general, the invocation of EndFrame shouldn't depend on the value of the layer_tree. Rendering (or not rendering) an empty layer tree is still a frame.

This is currently hard for implementers to know this when implementing EndFrame. To make it better, maybe we can think of a way for the implementers to be aware of this. Maybe through documentation and tests to prevent future mistakes.

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Feb 23, 2022

@cyanglaz
An empty layer tree is a very special case and in theory it shouldn't happen. Here I filed another Issue to illustrate the specific scene it is currently happening.
flutter/flutter#98959

Then let's take a look at the call stacks of following scenarios.

  1. a normal frame
Rasterizer::Draw
  -> Rasterizer::DoDraw
    -> Rasterizer::DrawToSurface
      -> Rasterizer::DrawToSurfaceUnsafe
        -> ExternalViewEmbedder::BeginFrame
        -> ExternalViewEmbedder:: SubmitFrame
  -> ExternalViewEmbedder::EndFrame
  1. a frame without surface
Rasterizer::Draw
  // do noting
  1. a frame with empty layer tree
Rasterizer::Draw
  -> ExternalViewEmbedder::EndFrame
  1. redraw last layer tree
Rasterizer::DrawLastLayerTree
  -> Rasterizer::DrawToSurface
      -> Rasterizer::DrawToSurfaceUnsafe
        -> ExternalViewEmbedder::BeginFrame
        -> ExternalViewEmbedder:: SubmitFrame
  -> ExternalViewEmbedder::EndFrame
  1. redraw last layer tree but last layer tee is not exists
Rasterizer::DrawLastLayerTree
  // do noting

From the above scenarios, It seems that Rasterizer::Draw or Rasterizer::DrawLastLayerTree is not always call ExternalViewEmbedder::EndFrame. So I think when we draw an empty layer tee, we should do nothing, just like scene 2 (a frame without surface) and scene 5 (redraw last layer tree but last layer tee is not exists) above.

Calling EndFrame with an empty layer tree seems unnecessary and has side effects. At the same time, this also adds unnecessary work to the platform to correctly implement EndFrame

@cyanglaz
Copy link
Contributor

@ColdPaleLight Ok, sounds good to me.
I double checked the endFrame implementations for all the platforms, there doesn't seem to be any side effect of not calling endFrame. So I'm ok with it.

Copy link
Contributor

@cyanglaz cyanglaz left a comment

Choose a reason for hiding this comment

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

LGTM. please wait until @dnfield's comment to be resolved before merging.

@blasten
Copy link

blasten commented Feb 23, 2022

Another way to fix this issue is to pass consume_result to EndFrame, and update the docs, so implementors are aware of this behavior.

I think conditionally calling methods like this can be harder to reason about a few years from now. I'd definitely prefer something more explicit.

@ColdPaleLight
Copy link
Member Author

@blasten
The original intention of EndFrame design is not to call back every time in Rasterizer::Draw or Rasterizer::DrawLastLayerTree, otherwise it should also be called back when Rasterizer::surface_ does not exist.

For this scene of the empty layer tree, I think we should do the same thing as the scene where Rasterizer::surface_ does not exist. Because in this scenario, the Rasterizer::Draw method actually does nothing except call EndFrame. I think the current implementation itself is incorrect.

@cyanglaz
Copy link
Contributor

@ColdPaleLight actually, looking at the pattern when EndFrame "should" be called. Maybe we can add a DCHECK that crashes if EndFrame is called without a BeginFrame? Does it make more sense?

@ColdPaleLight
Copy link
Member Author

@ColdPaleLight actually, looking at the pattern when EndFrame "should" be called. Maybe we can add a DCHECK that crashes if EndFrame is called without a BeginFrame? Does it make more sense?

If we are sure that BeginFrame and EndFrame should be paired. Maybe we can set a flag when BeginFrame is called, and then only call EndFrame when this flag is set.

@cyanglaz
Copy link
Contributor

If we are sure that BeginFrame and EndFrame should be paired. Maybe we can set a flag when BeginFrame is called, and then only call EndFrame when this flag is set.

Yes, that's what the pattern you listed tells me and that's what I think we should do.

@ColdPaleLight
Copy link
Member Author

ColdPaleLight commented Feb 23, 2022

@cyanglaz
Can we continue to land this PR when @dnfield 's comment solved ? I think returning early in case of PipelineConsumeResult::NoneAvailable will make the code more robust.

I 'll file another PR to pair the BeginFrame and EndFrame

@cyanglaz
Copy link
Contributor

Yes I have approved this PR from my end! ;)

Copy link
Contributor

@dnfield dnfield left a comment

Choose a reason for hiding this comment

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

LGTM

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants