Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[web] Reuse ImageElement(s) across frames #18437

Merged
merged 8 commits into from
May 20, 2020
Merged

Conversation

ferhatb
Copy link
Contributor

@ferhatb ferhatb commented May 15, 2020

Related issue: flutter/flutter#48373

// Maps src url to image element to reuse image instances across frames.
// Optimization for some browsers that keep refreshing images causing
// flicker.
Map<String, List<html.ImageElement>> _reusableImages;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this global and clean up in commitScene instead of endOfPaint? This way images can be reused across canvases (we frequently create a new canvas because of a failed match, but it will contain the same image from the previous frame), we will allocate fewer maps and lists, and we can remove several null checks (we can keep the global map always non-null).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved cache to picture level, so it survives across picture updates.

@@ -172,7 +177,14 @@ class BitmapCanvas extends EngineCanvas {
_canvasPool.clear();
final int len = _children.length;
for (int i = 0; i < len; i++) {
_children[i].remove();
html.Element child = _children[i];
if (child is html.ImageElement) {
Copy link
Contributor

Choose a reason for hiding this comment

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

If the image is clipped it won't be a direct child of the root element but a descendant of a clipping element.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

if (child is html.ImageElement) {
_reusableImages ??= {};
final String src = child.src;
_reusableImages[src] ??= []..add(child);
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of adding the image during deconstruction of the canvas, I would add the image at the time it is painted. This way we don't have to read back from the DOM, and we can still reuse the image even if the canvas is not reused but a new one is painted.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@ferhatb ferhatb requested a review from yjbanov May 20, 2020 16:54
Copy link
Contributor

@harryterkelsen harryterkelsen left a comment

Choose a reason for hiding this comment

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

LGTM

class TestItem {
final String label;
TestItem(this.label);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: newline at end of file

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@@ -116,6 +117,11 @@ class BitmapCanvas extends EngineCanvas {
_setupInitialTransform();
}

/// Setup cache for reusing DOM elements across frames.
set elementCache(CrossFrameCache<html.HtmlElement> cache) {
Copy link
Contributor

Choose a reason for hiding this comment

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

/// A monotonically increasing frame number being rendered.
///
/// Used for debugging only.
int _debugFrameNumber = 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this here?

(_cache[key] ??= [])..add(item);
}

/// Given a key, consumes an item that has been cached in a prior frame.
Copy link
Contributor

Choose a reason for hiding this comment

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

This should also talk about what it returns, and in particular when does it return null.

Map<String, List<_CrossFrameCacheItem<T>>> _cache;

// Cached items that have been committed, ready for reuse on next frame.
Map<String, List<_CrossFrameCacheItem<T>>> _reusablePool;
Copy link
Contributor

Choose a reason for hiding this comment

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

I would call this field _cache, and I would rename the above _cache to _itemUsedThisFrame. After all, we want to cache items across frames, but confusingly the current _cache variable travels to the next frame as null.

@ferhatb ferhatb merged commit 4be3a03 into flutter:master May 20, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 21, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 21, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 22, 2020
wandyers pushed a commit to wandyers/engine that referenced this pull request May 23, 2020
* reuse images across frames
* Change implementation to CrossFrameCache at picture level
* Update licenses_flutter
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 23, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2020
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 26, 2020
@ferhatb ferhatb deleted the safariflicker branch August 10, 2020 20:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants