-
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
Allow embedder controlled composition of Flutter layers. #10195
Conversation
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 did a quick initial pass (although didn't to the test code). Is there a document somewhere that provides a high-level overview of how this all fits together? Building up and holding the whole state in my head while reviewing (especially without comments on many of the classes explaining their role in the flow) is quite difficult without already having a lot of context about how the entire rendering pipeline works.
fml/closure.h
Outdated
namespace fml { | ||
|
||
using closure = std::function<void()>; | ||
|
||
class AutoFireClosure { |
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 needs a class-level comment, per style guide.
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
fml/closure.h
Outdated
private: | ||
fml::closure closure_; | ||
|
||
FML_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure); |
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 macros like this are now strongly discouraged by the style guide, it would be better to use delete
directly in all new code.
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.
Can you link to this? I cannot find or rationalize the guidance w.r.t the macros in the style guide. The guidance "... move-only class should explicitly declare the move operations, and a non-copyable/movable class should explicitly delete the copy operations. Explicitly declaring or deleting all four copy/move operations is permitted, but not required." is adequately satisfied by the macros.
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.
https://google.github.io/styleguide/cppguide.html#Preprocessor_Macros
"Do not use macros to define pieces of a C++ API."
I misremembered; they are forbidden now, not just discouraged.
See also:
https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types
"a non-copyable/movable class should explicitly delete the copy operations"
I can also point you to internal discussion of exactly this macro construction if you'd like.
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.
Yes. Please. I'll also get rid of the macro and all usages in a separate patch. It is just best to stick to the guide.
|
||
namespace flutter { | ||
|
||
class GPUSurfaceSoftwareDelegate { |
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.
Comment class and methods.
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.
}; | ||
return fml::MakeCopyable( | ||
[gl_dispatch_table, fbo_reset_after_present, platform_dispatch_table, | ||
external_view_embedder = |
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.
It seems like this would be clearer if you used a new variable name instead of shadowing. (Same comment in the similar block below.)
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.
There is no variable shadowing in this case because there is no implicit capture of the external view embedder. Also, I think -Wshadow
which is on by default would have caught this form of shadowing.
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 was wrong #10480
shell/platform/embedder/embedder.cc
Outdated
return surface; | ||
} | ||
|
||
static sk_sp<SkSurface> WrapPlatformRenderTarget( |
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.
These helpers are all non-trivial, and need declaration-style comments explaining what they do.
@@ -685,6 +815,8 @@ typedef struct { | |||
// optional argument allows for the specification of task runner interfaces to | |||
// event loops managed by the embedder on threads it creates. | |||
const FlutterCustomTaskRunners* custom_task_runners; | |||
|
|||
const FlutterCompositor* compositor; |
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.
Comment.
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.
typedef struct { | ||
double x; | ||
double y; | ||
} FlutterPoint; |
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.
The inconsistency with existing APIs taking points and sizes is unfortunate. Have you thought about maybe doing a follow-up to add updated versions of the relevant APIs (window metrics, pointer)?
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 am not too excited about making that breaking API change (though the ABI would be stable). Maybe I should just place these inline in the struct instead of adding these additional structs for consistency?
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 was actually thinking you could freeze the old APIs, comment them as deprecated, and make new ones that used the new structs.
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 do that too. Though, I don't think this patch needs to include that change. But if we agree that this is the direction we want to go, I'll keep these structs around.
|
||
namespace flutter { | ||
|
||
class EmbedderExternalViewEmbedder : public ExternalViewEmbedder { |
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.
Comment
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.
|
||
namespace flutter { | ||
|
||
class EmbedderRenderTarget final { |
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.
Comment class and methods.
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.
|
||
namespace flutter { | ||
|
||
class EmbedderRenderTargetRegistry { |
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.
Comment.
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.
Wow awesome super fast progress!
Took a first crack, left a few comments, mainly I'm concerned about baking an assumption that each platform view has an associated overlay into the public API.
Side note - this PR is pretty big, it may be more productive to review in smaller chunks (I'm ok to continue with current PR if this is still your preference).
shell/platform/embedder/embedder.h
Outdated
FlutterCompositorLayerRendererCollectCallback collect_layer_renderer_callback; | ||
// Callback invoked by the engine to composite the contents of each platform | ||
// view into the specified render target. | ||
FlutterCompositorLayersPresentCallback present_layers_callback; |
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.
The comment should mention that when this is used present
won't be called for the root FlutterOpenGLRendererConfig
/FlutterSoftwareRendererConfig
and that the implementation should present the root surface as well.
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.
Or at least, wasn't that the plan?
shell/platform/embedder/embedder.h
Outdated
// their resources in the user_data field of that struct. | ||
FlutterCompositorLayerRendererCollectCallback collect_layer_renderer_callback; | ||
// Callback invoked by the engine to composite the contents of each platform | ||
// view into the specified render target. |
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: I'm not sure I understand what's the specified render target into which all the platform views (layers?) are rendered?
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.
Updated.
shell/platform/embedder/embedder.h
Outdated
void* user_data); | ||
|
||
typedef bool (*FlutterCompositorLayersPresentCallback)( | ||
const FlutterCompositorLayer** layers, |
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 bakes in an assumption that each platform view has an overlay surface, which is likely to not be true in the future.
What do you think about passing in a single list of layers, and have each layer refer to either a platform view or to an overlay?
shell/common/rasterizer.cc
Outdated
if (external_view_embedder != nullptr) { | ||
external_view_embedder->SubmitFrame(surface_->GetContext()); | ||
} | ||
frame->Submit(); |
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 submit will now happen after the CATransaction is committed on iOS (it's currently committed in the external view embedder SubmitFrame)
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, this is still to be fixed. Won't commit before addressing the same.
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.
Took a stab at reworking the API to think of layers having backing stores instead of introducing a layer at an interleaving level. Still need to work though (most) all comments made so far.
fml/closure.h
Outdated
namespace fml { | ||
|
||
using closure = std::function<void()>; | ||
|
||
class AutoFireClosure { |
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
shell/platform/embedder/embedder.h
Outdated
@@ -193,6 +193,15 @@ typedef struct { | |||
|
|||
typedef void (*VoidCallback)(void* /* user data */); | |||
|
|||
typedef enum { | |||
// Specifies an OpenGL texture target type. Textures are specified using |
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 though so too. But that was the pattern followed in this file already. See FlutterTransformation
above.
The API has been updated. Instead of thinking of the layers as being introduced at interleaving levels, a new |
99c6bbd
to
1a451be
Compare
The updated API has the implementation, tests and documentation. PTAL. |
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.
reviewed everything but tests
// the framebuffer is complete. | ||
FlutterOpenGLFramebuffer framebuffer; | ||
}; | ||
} FlutterOpenGLBackingStore; |
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 wondering whether we need these 2 levels of hierarchy (software/gl, texture/fbo) vs. flattening the hierarchy (which will reduce some boilerplate in this file)
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.
Seems like flattening the hierarchy will save the nested switch-case in CreateBackingStore
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.
Hmm, I see your point. But I am on the fence on this one. Since the addition of render targets for Vulkan & Metal will increase the backing store types, I'd rather just filter away entire target type classes in once shot in the future instead of adding client rendering API/target type combinations to this single enum.
shell/platform/embedder/embedder.h
Outdated
// call. When this happens, the Flutter rasterizer divides the effective view | ||
// hierarchy into multiple layers. Each layer gets its own backing store and | ||
// Flutter renders into the same. Once the layers contents have been | ||
// fulfilled, the embedder is asked to compositor these layers on-screen. At |
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: to composite
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.
}; | ||
// The offset of this layer relative to the top left of the root surface used | ||
// by the engine. | ||
FlutterPoint offset; |
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 should say what's the unit for the offset and the 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.
Clarified.
fml/closure.h
Outdated
/// automatically at the end of the scope. This covers the cases | ||
/// where there are early returns as well. | ||
/// | ||
class AutoFireClosure { |
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.
First running into this name I didn't know when to expect that closure will be fired, and I didn't guess it will fire on destruction. Maybe we can come up with a name that better conveys what this thing is doing?
InvokeOnDestruction?
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.
Coming back here after reviewing embedder.cc (which I believe is the only user of this), I'd reconsider whether the overhead of introducing this class is justified (see my comment on embedder.cc)
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 already introduced a resource leak on error as I was refactoring the initial version of the implementation. Since it is so easy to introduce such resource leaks in C and C++ interop code (in error cases no less), I'd rather make this a pattern we follow.
About the name, maybe ScopedFireClosure
is more immediately descriptive?
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 like Scoped
, since Scoped*
is a common naming pattern. What about ScopedCleanupClosure
, which more clearly indicates that it fires on destruction?
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.
ScopedCleanupClosure
sgtm
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.
|
||
NonOwnedMapping::~NonOwnedMapping() { | ||
if (release_proc_) { | ||
release_proc_(data_, 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.
Doesn't it make it an owned mapping once we have a release proc?
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 guess so. The argument could also be made that this object does not own the mapping but gives the closure to collect it (so whoever passes in the closure to this owns the mapping).
@@ -125,4 +125,9 @@ intptr_t AndroidSurfaceGL::GLContextFBO() const { | |||
return 0; | |||
} | |||
|
|||
// |GPUSurfaceGLDelegate| | |||
ExternalViewEmbedder* AndroidSurfaceGL::GetExternalViewEmbedder() { |
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.
Why not keep this default implementation in GPUSurfaceGLDelegate?
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 not all platforms implement platform views like iOS and embedders do, it was not immediately clear from looking at just one implementation if the technique was used on that platform (Android in this case). I believe this explicitness makes it more clear from looking at the Android implementation. Also, this happened to be the only function in the delegate that had a default implementation in the base class (the acquire and present calls on the backing store were pure virtual).
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
@@ -134,6 +134,11 @@ bool AndroidSurfaceSoftware::PresentBackingStore( | |||
return true; | |||
} | |||
|
|||
// |GPUSurfaceSoftwareDelegate| | |||
ExternalViewEmbedder* AndroidSurfaceSoftware::GetExternalViewEmbedder() { |
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.
Why not keep this in GPUSurfaceSoftwareDelegate?
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.
Similar reasoning as above.
|
||
struct Hash { | ||
constexpr std::size_t operator()(RegistryKey const& key) const { | ||
return key.view_identifier; |
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.
feels a bit dodgy to have the same hash for 2 values that are unequal (have different sizes)
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.
A hash function maps values from an arbitrarily large set into a finite set. Per that definition, how is this dodgy. The equality is implemented separately below as well.
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.
Right 😳
|
||
// |ExternalViewEmbedder| | ||
bool EmbedderExternalViewEmbedder::HasPendingViewOperations() { | ||
return false; |
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 semantically incorrect (e.g we may have "pending view operations"), I'd leave a comment explaining why we return false.
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.
render_canvas->flush(); | ||
|
||
// Indicate a layer for the platform view. | ||
presented_platform_views[view_id] = MakePlatformView(view_id); |
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.
What is presented_platform_views
used for?
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.
presented_layers
contain pointers to objects in presented_platform_views
(see the comment on line 144). These structs must be alive till the present_callback_
is invoked.
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.
wow I really missed that, do you mind clarifying on the presented_layers that it's sole purpose is to release the layers created below when we quit the method?
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.
That is why I added the comment on line 165. Were you referring to something else?
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 guess that comment wasn't explicit enough for me 😄
I'd suggest adding a comment here, saying that we add to presented_platform_views in order to keep at allocated just for the scope of the current method.
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.
Did another pass over new comments. PTAL. Only the move of the Submit on the rasterizer remains unaddressed. |
492def4
to
f1017ad
Compare
@amirh: When you do your next review pass, please pay close attention to the offset of the Fluter backing store backed layers in the unit-tests. I am not sure the current behavior is as intuitive as it could be. |
All comments and API suggestions and been incorporated. I believe this is good to go. |
I'll do another review pass by EOD, sorry for the 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.
Left a few more minor comments, but it's definitely easier to follow with comments. I still think it would be extremely helpful to have a doc/wiki page with a high-level overview of this part of the system though.
I'll leave more substantive review to others who have more familiarity with the details of the rendering pipeline.
fml/closure.h
Outdated
/// automatically at the end of the scope. This covers the cases | ||
/// where there are early returns as well. | ||
/// | ||
class AutoFireClosure { |
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 like Scoped
, since Scoped*
is a common naming pattern. What about ScopedCleanupClosure
, which more clearly indicates that it fires on destruction?
}; | ||
} FlutterOpenGLBackingStore; | ||
|
||
typedef struct { |
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 have a size field, or are you 100% confident that it won't grow over time?
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 was trying to make this consistent with the FlutterOpenGLTexture
and FlutterOpenGLFramebuffer
structs. No, I am not 100% confident.
// Decide if we want to discard the previous root render target. | ||
if (root_render_target_) { | ||
auto surface = root_render_target_->GetRenderSurface(); | ||
// This is unlikely to happen but the embedder could have given us a render |
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.
Please be more specific about 'us', 'we', etc. (go/avoidwe)
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.
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.
Left a few nits. Overall looks good.
Per offline discussion lets make sure we don't invoke both the fbo callback and create backing store for the root surface.
render_canvas->flush(); | ||
|
||
// Indicate a layer for the platform view. | ||
presented_platform_views[view_id] = MakePlatformView(view_id); |
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.
wow I really missed that, do you mind clarifying on the presented_layers that it's sole purpose is to release the layers created below when we quit the method?
flow/embedded_views.h
Outdated
@@ -191,6 +191,10 @@ class ExternalViewEmbedder { | |||
public: | |||
ExternalViewEmbedder() = default; | |||
|
|||
virtual ~ExternalViewEmbedder() = default; | |||
|
|||
virtual sk_sp<SkSurface> GetRootSurface(); |
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.
Let's document that it's open and explain the behaviors when it's null and non null.
Also - what do you think about leaving a TODO to implement this for iOS as well and then treat it as non-optional.
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.
Good idea. Done. Also documented the protocol and the iOS implementation that returns nullptr
.
shell/common/rasterizer.cc
Outdated
} | ||
|
||
// If the external view embedder has specified an optional root surface, the | ||
// root surface transformation can be affected by the embedder instead of |
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: s/can be affected/is set/
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.
shell/common/rasterizer.cc
Outdated
auto compositor_frame = compositor_context_->AcquireFrame( | ||
surface_->GetContext(), canvas, external_view_embedder, | ||
surface_->GetRootTransformation(), true); | ||
surface_->GetContext(), // skia GrContext |
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.
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 think it is the formatter trying to "columnize" the argument and their docstrings but the embedder_root_surface specification causing a wrap. Agreed that it was looking goofy however. I moved that into its own variable and now it is neatly arranged.
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.
Sorry, just saw this comment. I used /engine/src/flutter/ci/format.sh
for formatting if you still want to know.
testing/assertions_skia.h
Outdated
namespace flutter { | ||
namespace testing { | ||
|
||
// |
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.
Do we need 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.
No. It was for assertions that were later moved to embedder_assertions.h
. Removed.
357474a
to
f36c0f6
Compare
This patch allows embedders to split the Flutter layer tree into multiple chunks. These chunks are meant to be composed one on top of another. This gives embedders a chance to interleave their own contents between these chunks. The Flutter embedder API already provides hooks for the specification of textures for the Flutter engine to compose within its own hierarchy (for camera feeds, video, etc..). However, not all embedders can render the contents of such sources into textures the Flutter engine can accept. Moreover, this composition model may have overheads that are non-trivial for certain use cases. In such cases, the embedder may choose to specify multiple render target for Flutter to render into instead of just one. The use of this API allows embedders to perform composition very similar to the iOS embedder. This composition model is used on that platform for the embedding of UIKit view such and web view and map views within the Flutter hierarchy. However, do note that iOS also has threading configurations that are currently not available to custom embedders. The embedder API updates in this patch are ABI stable and existing embedders will continue to work are normal. For embedders that want to enable this composition mode, the API is designed to make it easy to opt into the same in an incremental manner. Rendering of contents into the “root” rendering surface remains unchanged. However, now the application can push “platform views” via a scene builder. These platform views need to handled by a FlutterCompositor specified in a new field at the end of the FlutterProjectArgs struct. When a new platform view in introduced within the layer tree, the compositor will ask the embedder to create a new render target for that platform view. Render targets can currently be OpenGL framebuffers, OpenGL textures or software buffers. The type of the render target returned by the embedder must be compatible with the root render surface. That is, if the root render surface is an OpenGL framebuffer, the render target for each platform view must either be a texture or a framebuffer in the same OpenGL context. New render target types as well as root renderers for newer APIs like Metal & Vulkan can and will be added in the future. The addition of these APIs will be done in an ABI & API stable manner. As Flutter renders frames, it gives the embedder a callback with information about the position of the various platform views in the effective hierarchy. The embedder is then meant to put the contents of the render targets that it setup and had previously given to the engine onto the screen (of course interleaving the contents of the platform views). Unit-tests have been added that test not only the structure and properties of layer hierarchy given to the compositor, but also the contents of the texels rendered by a test compositor using both the OpenGL and software rendering backends. Fixes b/132812775 Fixes flutter/flutter#35410
58118a0
to
9ac4d51
Compare
Ok, All comments have been addressed. The presubmits are having a rough time today but I'll keep patching targets as and when the bots encounter them. |
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.
Left a few nit, almost looks good, I just want to understand whether I'm misreading the test code first (left a comment)
GPUSurfaceGL(sk_sp<GrContext> gr_context, GPUSurfaceGLDelegate* delegate); | ||
GPUSurfaceGL(sk_sp<GrContext> gr_context, | ||
GPUSurfaceGLDelegate* delegate, | ||
bool render_to_surface); |
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.
The meaning of render_to_surface wasn't immediately clear to me (A GPU surface that does not render to surface?), maybe worth documenting 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 documented the ivar and filed a bug to get rid of this hack.
@@ -236,6 +244,13 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceGL::AcquireFrame(const SkISize& size) { | |||
return nullptr; | |||
} | |||
|
|||
if (!render_to_surface_) { |
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.
FWIW I feel like we've reached a point where we're applying concepts that doesn't align well with the higher level surface API and we should probably revisit it at some point. What do you think about leaving filing an issue saying we should refactor and leaving a TODO here describing the reason for this workaround and saying that we should clean it up in a coming refactoring?
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.
Right, added a TODO and filed a bug flutter/flutter#38466
render_canvas->flush(); | ||
|
||
// Indicate a layer for the platform view. | ||
presented_platform_views[view_id] = MakePlatformView(view_id); |
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 guess that comment wasn't explicit enough for me 😄
I'd suggest adding a comment here, saying that we add to presented_platform_views in order to keep at allocated just for the scope of the current method.
render_surface_(std::move(render_surface)), | ||
on_release_(on_release) { | ||
// The optimization to elide backing store updates between frames has not been | ||
// implemented yet. |
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.
Let's file an issue describing what has to be done and link it from a TODO 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.
} break; | ||
default: | ||
// Asked to render an unknown layer. | ||
FML_CHECK(false) << "Test was asked for unknown layer"; |
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: unknown platform view
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.
Color blue = Color.fromARGB(127, 0, 0, 255); | ||
Color gray = Color.fromARGB(127, 127, 127, 127); | ||
|
||
Size size = Size(100.0, 100.0); |
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: I'd make width != height to catch a possible faulty swap of these parameters.
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.
Roger. Update fixtures and expectations.
layer.type = kFlutterLayerContentTypeBackingStore; | ||
layer.backing_store = &backing_store; | ||
layer.size = FlutterSizeMake(100.0, 100.0); | ||
layer.offset = FlutterPointMake(20.0, 20.0); |
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 probably confused but shouldn't this be 0,0?
The test code is:
SceneBuilder builder = SceneBuilder();
builder.pushOffset(0.0, 0.0);
// 10
builder.addPicture(Offset(10.0, 10.0), CreateColoredBox(red, size)); // red - flutter
// 20
builder.pushOffset(20.0, 20.0);
builder.addPlatformView(1, width: size.width, height:size.height); // green - platform
builder.pop();
// 30
builder.addPicture(Offset(30.0, 30.0), CreateColoredBox(blue, size)); // blue - flutter
the [20,20] offset is popped just before adding the layer with index 2.
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.
You're right. But, isn't the size wrong too? Shouldn't it be the frame 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.
Fixed. I also updated the render size.
layer.type = kFlutterLayerContentTypeBackingStore; | ||
layer.backing_store = &backing_store; | ||
layer.size = FlutterSizeMake(100.0, 100.0); | ||
layer.offset = FlutterPointMake(40.0, 40.0); |
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.
Same here, shouldn't it be 0,0 ?
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.
Roger. Ditto about the size being wrong too.
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.
Fixed. I also updated the render 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.
LGTM!
[email protected]:flutter/engine.git/compare/be4c8338a6ab...4b6b4af git log be4c833..4b6b4af --no-merges --oneline 2019-08-13 [email protected] Roll src/third_party/skia cd8b6d5c1cb8..f75996469d02 (5 commits) (flutter/engine#10984) 2019-08-13 [email protected] Allow embedder controlled composition of Flutter layers. (flutter/engine#10195) The AutoRoll server is located here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+/master/autoroll/README.md If the roll is causing failures, please contact the current sheriff ([email protected]), and stop the roller if necessary.
@chinmaygarde : will this be used for Fuchsia in the future so we can retire all |
Yes. the plan is to use the Embedder API for the Fuchsia runner eventually. |
This patch allows embedders to split the Flutter layer tree into multiple chunks. These chunks are meant to be composed one on top of another. This gives embedders a chance to interleave their own contents between these chunks.
The Flutter embedder API already provides hooks for the specification of textures for the Flutter engine to compose within its own hierarchy (for camera feeds, video, etc..). However, not all embedders can render the contents of such sources into textures the Flutter engine can accept. Moreover, this composition model may have overheads that are non-trivial for certain use cases. In such cases, the embedder may choose to specify multiple render target for Flutter to render into instead of just one.
The use of this API allows embedders to perform composition very similar to the iOS embedder. This composition model is used on that platform for the embedding of UIKit view such and web view and map views within the Flutter hierarchy. However, do note that iOS also has threading configurations that are currently not available to custom embedders.
The embedder API updates in this patch are ABI stable and existing embedders will continue to work are normal. For embedders that want to enable this composition mode, the API is designed to make it easy to opt into the same in an incremental manner.
Rendering of contents into the “root” rendering surface remains unchanged. However, now the application can push “platform views” via a scene builder. These platform views need to handled by a
FlutterCompositor
specified in a new field at the end of theFlutterProjectArgs
struct.When a new platform view in introduced within the layer tree, the compositor will ask the embedder to create a new render target for that platform view. Render targets can currently be OpenGL framebuffers, OpenGL textures or software buffers. The type of the render target returned by the embedder must be compatible with the root render surface. That is, if the root render surface is an OpenGL framebuffer, the render target for each platform view must either be a texture or a framebuffer in the same OpenGL context. New render target types as well as root renderers for newer APIs like Metal & Vulkan can and will be added in the future. The addition of these APIs will be done in an ABI & API stable manner.
As Flutter renders frames, it gives the embedder a callback with information about the position of the various platform views in the effective hierarchy. The embedder is then meant to put the contents of the render targets that it setup and had previously given to the engine onto the screen (of course, interleaving the contents of the platform views).
Unit-tests have been added that test not only the structure and properties of layer hierarchy given to the compositor, but also the contents of the texels rendered by a test compositor using both the OpenGL and software rendering backends.
Fixes b/132812775
Fixes flutter/flutter#35410