[wimp] Implement images for wimp.#183913
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements image support for wimp, a significant feature for the web impeller backend. The core of the change is the introduction of lazy texture creation for DlImage objects, which is crucial for performance and correctness in the web environment. This is achieved by adding a new GetImpellerTexture method that takes an Impeller context. To avoid re-creating textures, a TextureCache is introduced and plumbed through the rendering pipeline. The changes are well-structured, with updates to the display list dispatcher, canvas, and paint objects to support the new mechanism. Unit tests for the texture caching logic have been added, and a number of existing tests have been enabled for wimp, demonstrating the feature's correctness. Overall, this is a solid implementation. I have one suggestion to reduce some code duplication.
5b8da49 to
58efb94
Compare
|
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. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
This change implements image support for wimp. * Refactored some impeller bits to support images which lazily create their textures on the raster thread. This plumbs a texture cache and impeller context through calls so that images can actually generate their texture using the impeller context when it is actually rendered for the first time, and then use a cached version thereafter. * Implements images from pictures, from pixels, and from external textures in wimp. * Turns golden testing on for wimp unit tests. * Enables a number of web engine unit tests which were skipped due to a lack of image support. * Wrote a few unit tests on the impeller side to ensure the image->texture logic and caching work as expected.
f0765b8 to
8549531
Compare
|
Turning on the golden tests on for wimp reveals that something is wrong with how the blur filter is working. I started fixing it here, but then reverted those changes and put them into a separate PR to experiment: #184087 We'll probably just ignore/accept the incorrect blur when landing this PR, since it's basically unrelated to the wimp image implementation. |
|
Golden file changes are available for triage from new commit, Click here to view. For more guidance, visit Writing a golden file test for Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
flar
left a comment
There was a problem hiding this comment.
I've reviewed everything except for the skwasm directory so far. Going to come back to that tomorrow.
Meanwhile, I think @gaaclarke should probably take a look at all the snapshot changes and verify how they manage data now wrt async/sync factories...
| const DlPaint* paint) { | ||
| SkOptionalPaint sk_paint(paint); | ||
| sk_sp<SkImage> sk_image = image->skia_image(); | ||
| auto skia_image = image ? image->asSkiaImage() : nullptr; |
There was a problem hiding this comment.
Even with these extra null checks, we'll die eventually when we call skia_image.get() anyway.
| canvas_->drawImage(image ? image->skia_image() : nullptr, point.x, point.y, | ||
| ToSk(sampling), safe_paint(render_with_attributes)); | ||
| auto skia_image = image ? image->asSkiaImage() : nullptr; | ||
| canvas_->drawImage(skia_image ? skia_image->skia_image() : nullptr, point.x, |
There was a problem hiding this comment.
This is an interesting case in that most SkCanvas methods that take an image just NOP on a null image, so these null checks do prevent a crash unlike the ones in the other file that just bounce it down the line.
| .setImageFilter(image_filter); | ||
| builder.DrawImage(DlImage::Make(test_image_src_data->image()), | ||
| builder.DrawImage(DlImageSkia::Make(test_image_src_data->image()), | ||
|
|
| FML_DCHECK(image_color_source && | ||
| image_color_source->image()->impeller_texture()); | ||
| auto texture = image_color_source->image()->impeller_texture(); | ||
| auto texture = |
| std::unique_ptr<TextShadowCache> text_shadow_cache_; | ||
|
|
||
| bool is_texture_caching_enabled_ = false; | ||
| mutable std::unordered_map<const flutter::DlImage*, std::shared_ptr<Texture>> |
There was a problem hiding this comment.
Are we worried about image pointers becoming reused due to heap reuse? Does it make sense to have an ID on (at least) DlImageImpeller?
There was a problem hiding this comment.
I actually considered that. In practice, at least at the current moment, this is not actually a concern. Wimp is the only one that actually uses this cache, and when wimp images are destroyed, we send a message to the raster thread to clear it from the context's cache. The messages to the raster thread are strictly serially ordered, so that is guaranteed to be processed before any subsequent calls which might create an image at the same heap address and attempt to draw it (and therefore populate a texture in the cache).
If and when we decide to enable this cache and use it on the native side, we'd have to implement a similar strategy anyway for evicting the cache when an image goes away. So I think this is fine.
| MOCK_METHOD(DlISize, GetSize, (), (const, override)); | ||
| MOCK_METHOD(sk_sp<SkImage>, skia_image, (), (const, override)); | ||
| MOCK_METHOD(bool, isOpaque, (), (const, override)); | ||
| MOCK_METHOD(bool, isTextureBacked, (), (const, override)); |
There was a problem hiding this comment.
This is missing after the changes. It looks like the object does have the method, but I guess we don't need a mock if we aren't going to call it in testing? (It's just a "true" stub).
There was a problem hiding this comment.
Since MockDlImage inherits from DlImageImpeller, and DlImageImpeller::isTextureBacked() returns true directly (not virtual override of a pure virtual in DlImageImpeller itself, but overrides DlImage), it inherits the implementation that returns true. So it doesn't need to be mocked unless we want to return false in some tests.
| // |DlImage| | ||
| flutter::DlColorSpace DlDeferredImageGPUImpeller::GetColorSpace() const { | ||
| if (!wrapper_) { | ||
| return flutter::DlColorSpace::kSRGB; |
There was a problem hiding this comment.
Still don't understand the implications here.
| raster_task_runner]() { | ||
| auto image = dl_image->skia_image(); | ||
| auto skia_image = dl_image->asSkiaImage(); | ||
| auto image = skia_image ? skia_image->skia_image() : nullptr; |
There was a problem hiding this comment.
These lines are repeated all over - maybe make an access utility method somewhere?
| sk_sp<SkImage> SnapshotControllerImpeller::MakeSkiaTextureImage( | ||
| sk_sp<SkImage> image, | ||
| SnapshotPixelFormat pixel_format) { | ||
| return nullptr; |
There was a problem hiding this comment.
Some of these are UNREACHABLE, others return null. Should they be consistent?
There was a problem hiding this comment.
Is the rule "If you can return, return null, otherwise UNREACHABLE"?
| DlISize size, | ||
| SnapshotPixelFormat pixel_format) { | ||
| FML_UNREACHABLE(); | ||
| return nullptr; |
There was a problem hiding this comment.
Ooh, some are UNREACHABLE and also return null...
I was trying to stay out of it now that flar took over while I was ooo. I was worried of "too many cooks in the kitchen". @eyebrowsoffire let me know if you really want me to review it, I'm happy to defer to flar. I know you already integrated my feedback weeks ago. |
I think I'm pretty much on it. Most of this isn't really publicly exposed yet, but it does touch the decoders and the snapshot delegates and changes the way they deliver their data. It looked fine to me, but I'm not up to speed on all of the different ways we use that code and their threading considerations, so that part might benefit from an extra set of eyes. |
flar
left a comment
There was a problem hiding this comment.
I don't see any blocking problems, but left a few questions and suggestions to consider...
This change implements image support for wimp, addressing #175371.