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

Use a single OffscreenCanvas for rendering in CanvasKit #42672

Merged
merged 49 commits into from
Sep 12, 2023

Conversation

harryterkelsen
Copy link
Contributor

This changes CanvasKit's rendering model. Previously, each overlay canvas induced a new WebGL context and SkSurface. Now, there is only ever one SkSurface (backed by an OffscreenCanvas), and the overlays are HTML canvases with a bitmaprenderer context. The content is rendered using the SkSurface and passed to the overlays using transferToImageBitmap. This way, there is only one WebGL context in the lifetime of the app.

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.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@harryterkelsen harryterkelsen added the Work in progress (WIP) Not ready (yet) for review! label Jun 8, 2023
@github-actions github-actions bot added the platform-web Code specifically for the web engine label Jun 8, 2023
@flutter-dashboard
Copy link

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

Changes reported for pull request #42672 at sha 2d76c46

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

Changes reported for pull request #42672 at sha bb5b746

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

Changes reported for pull request #42672 at sha c29808b

@jezell
Copy link
Contributor

jezell commented Sep 7, 2023

So this is an interesting approach, it seems to use a single canvas to render each layer, and then use canvas to canvas drawing operations to output it to a non webgl canvas. The goals of this change, I believe, are to avoid the multiple webGL context limit enforced by the browser. Some observations:

This still doesn't actually solve the root problems related to too many layers when HTML elements get introduced into the DOM and we need overlay canvases. Instead of the browsers built-in error limit, now we have a new software defined overlay canvas limit (maximumOverlays), which is 7 vs the browsers 16 (and flutter's current 8?).

Am I missing something, or will every case that would fail before still fail under this proposed approach, with the caveat that in theory you can make that number whatever you want (if it's exposed) and avoid the hard cap of the browser, but in return we need to do tons of bitmap copy operations which might blow up perf (Firefox and Safari I'm looking at you).

I guess the proof is in the perf as to whether this is an improvement or not (I understand there might be other values to an offscreen canvas being used like rendering off the main thread which could be worth it), but how does it solve the problems behind #37890 and the other related issues if it doesn't reduce the number of overlays required and has an even lower limit of overlays due to the perf required for the copies?

The proposal in #41562 solves the problem that leads to the additional overlays being needed for things like video elements and image elements. Do we need to resurrect that even if this change gets merged?

Instead of going through all this work, or maybe as part of this work, why not just allow the overlays to render themselves into the canvas? The open issues related to Video and Image elements causing canvases to be created would require a lot less copying if they could just paint their media element directly into the canvas instead of copying around everything besides them. Skia supports it already so no reason it can't be supported with a special image constructor in web_ui that accepts an HTMLMediaElement.

@harryterkelsen
Copy link
Contributor Author

@jezell I have a follow-up change which reduces the overlays induced by HTML elements which uses the algorithm here: https://docs.google.com/document/d/1aCIOEEYe31HqCaCGUKsAmUu9T0U6o2zUMGpqdPEdJoQ/edit#heading=h.kj5jgtvn1u89

@eyebrowsoffire
Copy link
Contributor

@jezell Also, if all you're looking for is a way to create a ui.Image from a browser resource, I recently added a web-specific API for making a ui.Image from an ImageBitmap: #45256

You can use createImageBitmap to make an image bitmap from most browser sources you might care about, such as a video or image element.

@jezell
Copy link
Contributor

jezell commented Sep 11, 2023

@harryterkelsen @eyebrowsoffire awesome news!

@jezell
Copy link
Contributor

jezell commented Sep 11, 2023

@harryterkelsen you can in many cases make a further optimization and reduce the required platform views to one as I did in #41562. As long as the platform views are rectangular, opaque, and ignore pointer events, you can place them behind the canvas and render their region with a clear operation. While some platform views might not meet these conditions, many commonly problematic ones such as camera / video feeds or jpegs do. To the viewer, it appears that they are sitting in the correct location because the things that would have been rendered on top (because they are moved behind the canvas z-index) get erased during the drawing operation instead of creating a new canvas. I believe his approach is superior in these cases as it completely eliminates the need for the overlays when these constraints hold true.

@eyebrowsoffire
Copy link
Contributor

@jezell We have actually discussed the "cutout" approach in the past, but as you've already described it only works on completely opaque rectangular views, so we cannot use it as a general purpose solution for platform views.

To help reassure a bit, we have done benchmarking of this change and haven't found any major issues with the performance of this strategy. This is also roughly equivalent to the strategy we are using in the experimental Skwasm renderer, which has proven to be quite performant so far. The amount of copying happening under the hood is actually quite a bit less than you might imagine, as transferFromImageBitmap does not actually do any copying, but just replaces the backing store of the canvas itself with the contents of the ImageBitmap.

The main thing here is that practically speaking, there are hard limits and very real perf ramifications to creating multiple GL contexts, but those same limitations do not apply to making ImageBitmap objects. I don't know of any upper limit to the number of ImageBitmap objects one can create, but if there is one it's nowhere near the scale of the limit of the number of WebGL contexts that can be created. We have spent some time discussing this with browser folks too. There is a lot of intelligent resource pooling and reuse that happens under the hood in the browser when creating ImageBitmap objects, and they have said this is a reasonable use pattern.

The main thing we achieve from having a single GL context is that we can safely use the same GPU-side resources across multiple overlays. Right now, having multiple GL contexts is unfortunately pretty error prone and has performance cliffs when we have to move resources from one context to another.

Anyway, we really appreciate your engagement (and your patience) on these issues. I'm hoping the new ui_web API might be the best way forward for your use-case to avoid making platform views at all, but I'd be curious to hear about the outcomes of any experimentations with it, so please keep us informed. Thank you!

@jezell
Copy link
Contributor

jezell commented Sep 11, 2023

@eyebrowsoffire I agree that the ImageBitmap approach is the best general purpose solution, looking forward to giving it a shot. Should solve a lot of the cases for us that get us into trouble. Is the video_player web package being updated to use it? I'll work with the flutter_webrtc guys and see if we can get them to move over to it as well. I believe it should be good enough to solve our current blockers.

Copy link
Contributor

@eyebrowsoffire eyebrowsoffire left a comment

Choose a reason for hiding this comment

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

LGTM! One small comment.

lib/web_ui/lib/src/engine/canvaskit/surface.dart Outdated Show resolved Hide resolved
@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

Changes reported for pull request #42672 at sha 32f1c24

@harryterkelsen harryterkelsen merged commit c5ba843 into flutter:main Sep 12, 2023
24 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 12, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 12, 2023
bdero added a commit that referenced this pull request Sep 12, 2023
auto-submit bot pushed a commit that referenced this pull request Sep 12, 2023
)

Reverts #42672

This is causing breakages in the Framework roller on golden tests: flutter/flutter#134583
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Sep 13, 2023
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Sep 13, 2023
…134597)

flutter/engine@c90fadf...7c78ea2

2023-09-12 zanderso@users.noreply.github.com Revert "Lazily allocate RasterCacheItems only when caching is enabled" (flutter/engine#45734)
2023-09-12 1961493+harryterkelsen@users.noreply.github.com Revert "Use a single OffscreenCanvas for rendering in CanvasKit" (flutter/engine#45744)
2023-09-12 chinmaygarde@google.com [Impeller] Patch the compiler to account for subpass inputs and PSO metadata. (flutter/engine#45739)
2023-09-12 chinmaygarde@google.com [Impeller] Fix swapchain recreation for non-polling cases. (flutter/engine#45740)
2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from QgAHx3BtJfN3TmodS... to UCa49z8fu0hD9cypj... (flutter/engine#45738)
2023-09-12 ychris@google.com [ios] upload extension safe artifacts (flutter/engine#45664)
2023-09-12 30870216+gaaclarke@users.noreply.github.com Added test to assert the vulkan embedder threadsafe vkqueue usage (flutter/engine#45732)
2023-09-12 chinmaygarde@google.com [Impeller] If validations are enabled but not found, still create the VK context. (flutter/engine#45674)
2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 211d63b1e1f5 to 2d295711337c (7 revisions) (flutter/engine#45729)
2023-09-12 1961493+harryterkelsen@users.noreply.github.com Use a single OffscreenCanvas for rendering in CanvasKit (flutter/engine#42672)

Also rolling transitive DEPS:
  fuchsia/sdk/core/mac-amd64 from QgAHx3BtJfN3 to UCa49z8fu0hD

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Mairramer pushed a commit to Mairramer/flutter that referenced this pull request Oct 10, 2023
…lutter#134597)

flutter/engine@c90fadf...7c78ea2

2023-09-12 zanderso@users.noreply.github.com Revert "Lazily allocate RasterCacheItems only when caching is enabled" (flutter/engine#45734)
2023-09-12 1961493+harryterkelsen@users.noreply.github.com Revert "Use a single OffscreenCanvas for rendering in CanvasKit" (flutter/engine#45744)
2023-09-12 chinmaygarde@google.com [Impeller] Patch the compiler to account for subpass inputs and PSO metadata. (flutter/engine#45739)
2023-09-12 chinmaygarde@google.com [Impeller] Fix swapchain recreation for non-polling cases. (flutter/engine#45740)
2023-09-12 skia-flutter-autoroll@skia.org Roll Fuchsia Mac SDK from QgAHx3BtJfN3TmodS... to UCa49z8fu0hD9cypj... (flutter/engine#45738)
2023-09-12 ychris@google.com [ios] upload extension safe artifacts (flutter/engine#45664)
2023-09-12 30870216+gaaclarke@users.noreply.github.com Added test to assert the vulkan embedder threadsafe vkqueue usage (flutter/engine#45732)
2023-09-12 chinmaygarde@google.com [Impeller] If validations are enabled but not found, still create the VK context. (flutter/engine#45674)
2023-09-12 skia-flutter-autoroll@skia.org Roll Skia from 211d63b1e1f5 to 2d295711337c (7 revisions) (flutter/engine#45729)
2023-09-12 1961493+harryterkelsen@users.noreply.github.com Use a single OffscreenCanvas for rendering in CanvasKit (flutter/engine#42672)

Also rolling transitive DEPS:
  fuchsia/sdk/core/mac-amd64 from QgAHx3BtJfN3 to UCa49z8fu0hD

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC bdero@google.com,rmistry@google.com,zra@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform-web Code specifically for the web engine will affect goldens
Projects
None yet
4 participants