flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.16k stars 27.24k forks source link

Perform device to host texture transfer on the IO thread. #44148

Open chinmaygarde opened 4 years ago

chinmaygarde commented 4 years ago

Capturing a snapshot of a scene is extremely expensive (multiple frame intervals worth of time) and needs to happen on the GPU thread within a frame workload. Because of this, operations like Scene.toImage and Picture.toImage can potentially cause extreme amounts of jank in a Flutter application.

The sequence of operations that need to be performed to realize a host snapshot allocation are as follows:

To fix the performance issues mentioned above, the entire series of operations were moved to the IO thread. This was because the concurrent use restrictions was not apparent to engine authors. Once issues related to this violation were surfaced in https://github.com/flutter/flutter/issues/43085, the patch was reverted in https://github.com/flutter/engine/pull/13467.

To get back the performance improvements while maintaining threading correctness, one of the following API enhancements from Skia would be necessary:

chinmaygarde commented 4 years ago

cc @gaaclarke @jason-simmons @liyuqian

gaaclarke commented 4 years ago

However, the only available API for the creation of a snapshot from a surface (the Skia abstraction for a render target / framebuffer) returns a regular SkImage

It seems like if we were taking advantage of texture caches we wouldn't have the issue with shared contexts since we'd just be able to get an address in memory we could memcpy from.

Maybe the Metal renderer doesn't have this issue? This seems like a very OpenGL problem.

liyuqian commented 4 years ago

Also CC @brianosman as this seems to be an ask for Skia.

brianosman commented 4 years ago

There is a way to move the texture from an SkImage across thread boundaries that (I think) will be sufficient for this case. SkImage::MakeBackendTextureFromSkImage (https://cs.chromium.org/chromium/src/third_party/skia/include/core/SkImage.h?q=MakeBackendTextureFromSk+file:%5Esrc/third_party/skia/+package:%5Echromium$&g=0&l=1095) lets you take a texture-backed SkImage and extract the GrBackendTexture from it. If the SkImage has no other references at the time (eg, you std::move the last reference into that function), then it avoids making a copy and destroys the SkImage, so the GrBackendTexture becomes the sole owner of the texture.

At that point, you can move the GrBackendTexture across the thread boundary, and re-import it on the IO thread with SkImage::MakeFromTexture. You can use the IO thread's context to do the read-back, and then do the final cleanup.

cmkweber commented 4 years ago

Is there an ETA for this issue? This is a significant blocker in our application: https://github.com/flutter/flutter/issues/40990

Ideally this would address screenshots taken onscreen with toImage (what this issue is referencing), but also an offscreen canvas (as mentioned in the linked issue).

cmkweber commented 4 years ago

@chinmaygarde - Any chance this could be looked at following Metal integration?

joshualitt commented 3 years ago

Just to give a brief update on this issue, we spoke with the Skia team offline. They were no longer comfortable recommending the approach mentioned above. Instead, they suggested trying an asynchronous read pixels(#81239). However, ideally we'd do both, an asynchronous read pixels to avoid blocking the CPU, and performing the device to host texture transfer on the IO thread. I'm going to leave this bug open, and focus on the async read pixels. Hopefully we can return to this later, but we may need a new API first.

flutter-triage-bot[bot] commented 1 year ago

This issue is assigned but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!