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

Fix image source performance regression #11564

Merged
merged 8 commits into from
Mar 7, 2022

Conversation

ryanhamley
Copy link
Contributor

@ryanhamley ryanhamley commented Mar 4, 2022

Launch Checklist

  • briefly describe the changes in this PR
  • include before/after visuals or gifs if this PR includes visual changes
  • write tests for all new functionality
  • document any changes to public APIs
  • post benchmark scores
  • manually test the debug page
  • tagged @mapbox/map-design-team @mapbox/static-apis if this PR includes style spec API or visual changes
  • tagged @mapbox/gl-native if this PR includes shader changes or needs a native port
  • apply changelog label ('bug', 'feature', 'docs', etc) or use the label 'skip changelog'
  • add an entry inside this element for inclusion in the mapbox-gl-js changelog: <changelog>Prevent performance regression when animating image sources</changelog>

@ryanhamley ryanhamley added the performance ⚡ Speed, stability, CPU usage, memory usage, or power usage label Mar 4, 2022
@ryanhamley ryanhamley self-assigned this Mar 4, 2022
@ryanhamley ryanhamley requested review from karimnaaji and ansis March 4, 2022 01:09
Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

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

The PR looks good! I have a few questions before approving.

Could you confirm that #10685 is not reproducible after this PR is merged?

most newer browsers will create an ImageBitmap

Can we have a list of which ones would go through that code path to have an idea of the impact?

this.image = browser.getImageData(image);
const {HTMLImageElement} = window;
if (image instanceof HTMLImageElement) {
this.image = browser.getImageData(image);
Copy link
Contributor

@karimnaaji karimnaaji Mar 4, 2022

Choose a reason for hiding this comment

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

Not a blocker for this PR, but for this code path, should we investigate caching of canvas creation? We could reuse and retain a canvas once created until we need to use it for an image that has larger dimension. So that once the memory is there we would try to reuse it. For example:

  • Create image of size 1024x1024, create canvas of size 1024x1024
  • Create image of size 512x512, reuse canvas of size 1024x1024
  • Create image of size 2048x2048, drop canvas of size 1024x1024, create new canvas of size 2048x2048
    ...

One case where this would work great is where all images are of the same size. At the moment, we're always re-requesting new canvas even when sizes are matching.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have an implementation of this that seems to work well and looks like it's fairly performant.

Screen Shot 2022-03-04 at 2 33 00 PM

src/source/image_source.js Show resolved Hide resolved
@ryanhamley
Copy link
Contributor Author

Could you confirm that #10685 is not reproducible after this PR is merged?

It's not reproducible

Can we have a list of which ones would go through that code path to have an idea of the impact?

createImageBitmap is widely supported. All supported browsers except Safari have had support for at least 2 years. Safari added support recently with Safari 15.
Screen Shot 2022-03-04 at 3 18 17 PM

Comment on lines 53 to 54
canvas.width = width;
canvas.height = height;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you know why this commit didn't work out? 9d70bca

if (!canvas.width || canvas.width < width || !canvas.height || canvas.height < height) {
  canvas.width = width;
  canvas.height = height;
}

I'm concerned about these downsizing the canvas unnecessarily. Have you tried:

canvas.width = width > canvas.width ? width : canvas.width;

Comment on lines 52 to 57

canvas.width = width > canvas.width ? width : canvas.width;
canvas.height = height > canvas.height ? height : canvas.height;

context.drawImage(img, 0, 0, width, height);
return context.getImageData(-padding, -padding, width + 2 * padding, height + 2 * padding);
Copy link
Contributor

Choose a reason for hiding this comment

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

Following up from comment #11564 (comment), I think that would be the right way to resize:

Suggested change
canvas.width = width > canvas.width ? width : canvas.width;
canvas.height = height > canvas.height ? height : canvas.height;
context.drawImage(img, 0, 0, width, height);
return context.getImageData(-padding, -padding, width + 2 * padding, height + 2 * padding);
if (width > canvas.width || height > canvas.height) {
canvas.width = width;
canvas.height = height;
}
context.clearRect(-padding, -padding, width + 2 * padding, height + 2 * padding);
context.drawImage(img, 0, 0, width, height);
return context.getImageData(-padding, -padding, width + 2 * padding, height + 2 * padding);

The canvas might be dropped as soon as we resize it, to retain it we still need the condition but have a clear on the region where we'd like to use it. The above suggestion fixes that issue with proper caching.

@karimnaaji
Copy link
Contributor

Looks good to me pending the caching behavior fix mentioned in #11564 (comment). @sienki-jenki could you follow up to #11559 (comment) and confirm that this PR fixes the issue that you observed in your environment?

Copy link
Contributor

@karimnaaji karimnaaji left a comment

Choose a reason for hiding this comment

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

Ready to go now per confirmation on #11559 (comment) 🟢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance ⚡ Speed, stability, CPU usage, memory usage, or power usage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants