-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Implement toGpuImage, a synchronous, GPU-resident version of #33736
Conversation
Picture.toImage. This method kicks off asynchronous work on the raster task runner. If it fails to rasterize, it will synchronously throw later when the user attempts to draw to a canvas. This supports several use cases: - Quickly snapping off an expensive-to-rasterize image for reuse across multiple frames. - Applying multi-pass filters to a render target. This patch amends flutter_tester so that it can produce an image object, but that image will always be transparent black pixels. Adds support for CanvasKit on Web, which basically already used this method for its Picture.toImage implementation. Throws an UnsupportedError for HTML on Web, since any implementation there would almost certainly be slower than drawPicture.
This won't work because of the mock gr context. Need to fix that. Going to close this in the mean time. |
Ok. On flutter_tester toGpuImage now just emits a checkerboard image. The following things remain around this:
|
/// | ||
/// In the flutter_tester, this will always created a light gray and white | ||
/// checkerboard bitmap with the requested dimensions. | ||
Image toGpuImage(int width, int height) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this just be toTexture
?
Is that term overloaded?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its all quite overloaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it worth clarifying here (and elsewhere) that these are physical pixels and not the dp used in the framework?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't document this elsewhere - I think generally all the dart:ui API works in physical pixels, the framework introduces logical pixels.
@@ -5871,3 +5905,22 @@ Future<T> _futurize<T>(_Callbacker<T> callbacker) { | |||
throw Exception(error); | |||
return completer.future; | |||
} | |||
|
|||
class PictureRasterizationException implements Exception { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this need to be its own exception type, or can use use Exception
for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want this to be something you can try to specifically catch, with the idea being that this API could potentially be grown to support more of an idea of what kind of exception was thrown (particularly if you tried to make a texture larger than the user's GPU supports)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where would you put the catch though?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Around calls to canvas.drawImage
, or whatever else calls it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would give this a documentation comment at least describing the intent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Gold has detected about 1 new digest(s) on patchset 7. |
Gold has detected about 1 new digest(s) on patchset 9. |
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. |
lib/ui/painting.dart
Outdated
@@ -5871,3 +5907,30 @@ Future<T> _futurize<T>(_Callbacker<T> callbacker) { | |||
throw Exception(error); | |||
return completer.future; | |||
} | |||
|
|||
/// An exception thrown by [Canvas.drawImage] and realted methods when drawing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// An exception thrown by [Canvas.drawImage] and realted methods when drawing | |
/// An exception thrown by [Canvas.drawImage] and related methods when drawing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
if (image->image()->owning_context() != DlImage::OwningContext::kIO) { | ||
matrix4.Release(); | ||
// TODO(dnfield): it should be possible to support this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm extremely excited about this
testing/dart/canvas_test.dart
Outdated
// On a slower CI machine, the raster thread may get behind the UI thread | ||
// here. However, once the image is in an error state it will immediately | ||
// throw on subsequent attempts. | ||
while (true) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes me a bit uncomfortable, I'd be worried about the scenario where we break the error reporting somehow and this shard times out instead of fails.
If this had a max iteration count + perhaps a delay between drawImage attempts that might prevent that scenario, assuming there is no other way to stabilize it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to introduce a delay - the await null is just to turn the event loop. I'm fine with having a max iteration count though. I thought we had timeouts on these tests though - somewhere in litetest or something it should just eventually say the test failed due to timeout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah as long as it times out before the CI shard times out, that is fine. The await null
will run the next iteration in another microtask which not be enough, you need a non-zero duration await to get a full event loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL. I'll add a 1ms delay.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overall LGTM
Gold has detected about 2 new digest(s) on patchset 24. |
Golden file changes are available for triage from new commit, Click here to view. |
} | ||
|
||
// |DlImage| | ||
size_t DlDeferredImageGPU::GetApproximateByteSize() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be invoked on the UI thread, and it's reading image_
(which is written on the raster thread).
Can this compute an estimate based on size_
? That would avoid potential races.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage"); | ||
FML_DCHECK(display_list); | ||
|
||
switch (gpu_image_behavior_) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be simplified to:
if (gpu_image_behavior_ == MakeGpuImageBehavior::kBitmap) {
return MakeBitmapImage(picture_size);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer to avoid == for enums
Gold has detected about 1 new digest(s) on patchset 26. |
Gold has detected about 1 new digest(s) on patchset 28. |
🎉 |
Picture.toImage.
Fixes flutter/flutter#13498
Fixes flutter/flutter#77289
fixes flutter/flutter#106381
Some additional context at flutter/flutter#40990
This method kicks off asynchronous work on the raster task runner.
If it fails to rasterize, it will synchronously throw later when
the user attempts to draw to a canvas.
This supports several use cases:
across multiple frames.
This patch amends flutter_tester so that it can produce an image
object, but that image will always be a four square checkerboard of white and light grey.
Adds support for CanvasKit on Web, which basically already used
this method for its Picture.toImage implementation.
Throws an UnsupportedError for HTML on Web, since any implementation
there would almost certainly be slower than drawPicture.
Starting as a draft to run tests.
Pre-launch Checklist
writing and running engine tests.
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.