-
Notifications
You must be signed in to change notification settings - Fork 6k
[Impeller] Add Picture::RenderToImage #33864
Conversation
impeller/aiks/picture.cc
Outdated
| return nullptr; | ||
| } | ||
|
|
||
| return std::make_shared<Image>(target.GetRenderTargetTexture()); |
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 is a GPU resident texture right?
The API exposed via toImage expects a CPU resident image.
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 can mark the new texture as host visible and have Image handle the shared buffer transfer internally. Would prefer to punt that down the road to when we add in stuff like ReadPixels (if/when we need 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.
This isn't exposed up through the Dart API AFAICT, right?
If so, let's just document the behavior in a comment here.
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.
Nah this is only Impeller internal right now. Added a comment about the visibility.
impeller/aiks/picture.h
Outdated
| struct Picture { | ||
| std::unique_ptr<EntityPass> pass; | ||
|
|
||
| std::shared_ptr<Image> RenderToImage(AiksContext& renderer); |
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.
Nit: AiksContext& context?
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.
Another idea could be to flip it and ask the AiksContext to snapshot the picture as an image.
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.
|
|
||
| // | ||
| std::shared_ptr<Image> Picture::RenderToImage(AiksContext& renderer) { | ||
| auto coverage = pass->GetElementsCoverage(); |
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.
Since this is a utility method, add validity checks. Some stuff that comes to mind:
- Null checks for pass.
- Check for empty coverage. You won't be able to create a zero sized offscreen texture anyway.
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. Added check for render target + coverage. Gotta be more careful about these coverage optionals -- I've forgotten to check them before.
impeller/aiks/picture.cc
Outdated
| *renderer.context_, ISize(coverage->GetRight(), coverage->GetBottom())); | ||
|
|
||
| if (!renderer.Render(*this, target)) { | ||
| return nullptr; |
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.
VALIDATION_LOG here?
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.
impeller/aiks/picture.cc
Outdated
| std::shared_ptr<Image> Picture::RenderToImage(AiksContext& renderer) { | ||
| auto coverage = pass->GetElementsCoverage(); | ||
| auto target = RenderTarget::CreateOffscreen( | ||
| *renderer.context_, ISize(coverage->GetRight(), coverage->GetBottom())); |
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 create an unnecessarily large texture if the coverage has an offset element. In that case, pass entities would need to be copied and offset applied (I believe we already do this in the entity pass).
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 is the behavior of the picture.toImage. I found it a tad less confusing to reason about as opposed to returning the position as part of the result or otherwise forcing the caller to fetch coverage from the picture separately. Up to you though -- I don't really have a strong opinion.
A good middle ground might be to add a convenience method for walking the picture and absorbing the top left coverage margin as you mention.
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.
In that case, I think we should return an impeller::Snapshot in //impeller/entity/contents. Returning the position as part of image is then taken care of. Introducing a potentially large allocation overhead to make the API easier to reason makes me nervous. Especially when we have followed the right pattern elsewhere and have utilities for this purpose already.
If you do decide to use the snapshot, perhaps just call the method Picture::Snapshot as well and also move //impeller/entity/contents/snapshot to someplace more easily discoverable. Perhaps //impeller/renderer/snapshot? I think it's a good way of thinking about snapshotting and you have already thought through the various ways in which snapshotting can be used.
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.
SGTM, done.
impeller/aiks/picture.cc
Outdated
| return nullptr; | ||
| } | ||
|
|
||
| return std::make_shared<Image>(target.GetRenderTargetTexture()); |
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.
Check that the texture is not null. Add a validation log if it is and return nullptr.
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.
IMO, we should, by convention, not return invalid resources out of factories that return resources via a pointer. Instead, favoring returning null. This makes the caller not have to do a null and IsValid invocation pair.
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.
impeller/aiks/aiks_context.h
Outdated
| std::unique_ptr<ContentContext> content_context_; | ||
| bool is_valid_ = false; | ||
|
|
||
| friend Picture; |
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.
If the caller needs the impeller::Context from the AiksContext, you could just add a getter (completely reasonable IMO) instead of adding a friend.
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.
4a01f85 to
c0a7891
Compare
|
Left a comment about snapshotting. Not sure if this is a bit of a yak-shave though. |
|
cc @bdero Ping on the open question on the usage of an impeller::Snapshot. If you'd rather handle it in a later patch, LGTM here. I don't want to block other work that perhaps builds on top of this. |
|
Sorry for the delay, just got around to fixing this up. |
c932ced to
6bb5b25
Compare
|
This pull request is not suitable for automatic merging in its current state.
|
Been meaning to add this for a while to speed up some our of fancier tests (like color wheel). Just noticed flutter/flutter#104718 as I was making this PR. I don't know what the context of that issue is or how it might interface with the dispatcher, but perhaps this is in the right direction anyhow?
Screen.Recording.2022-06-06.at.7.20.22.PM.mov