Revert "fuchsia: Remove dead code / break dependencies (#19396)" (#20302) (#20327)
This reverts commit 12a37478de2cc9aff7f8fc72bc3a47f5f02e083c.
Co-authored-by: Zachary Anderson <zanderso@users.noreply.github.com>
diff --git a/flow/layers/child_scene_layer.cc b/flow/layers/child_scene_layer.cc
index 2a51590..795946e 100644
--- a/flow/layers/child_scene_layer.cc
+++ b/flow/layers/child_scene_layer.cc
@@ -4,6 +4,8 @@
#include "flutter/flow/layers/child_scene_layer.h"
+#include "flutter/flow/view_holder.h"
+
namespace flutter {
ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
@@ -17,9 +19,11 @@
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ChildSceneLayer::Preroll");
+ set_needs_system_composite(true);
+
+ CheckForChildLayerBelow(context);
context->child_scene_layer_exists_below = true;
- CheckForChildLayerBelow(context);
// An alpha "hole punch" is required if the frame behind us is not opaque.
if (!context->is_opaque) {
@@ -45,7 +49,15 @@
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
TRACE_EVENT0("flutter", "ChildSceneLayer::UpdateScene");
FML_DCHECK(needs_system_composite());
- context.UpdateView(layer_id_, offset_, size_, hit_testable_);
+
+ Layer::UpdateScene(context);
+
+ auto* view_holder = ViewHolder::FromId(layer_id_);
+ FML_DCHECK(view_holder);
+
+ view_holder->UpdateScene(context, offset_, size_,
+ SkScalarRoundToInt(context.alphaf() * 255),
+ hit_testable_);
}
} // namespace flutter
diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc
index 825826b..d8bf8ed 100644
--- a/flow/layers/container_layer.cc
+++ b/flow/layers/container_layer.cc
@@ -4,8 +4,6 @@
#include "flutter/flow/layers/container_layer.h"
-#include <optional>
-
namespace flutter {
ContainerLayer::ContainerLayer() {}
@@ -32,9 +30,6 @@
const SkMatrix& child_matrix,
SkRect* child_paint_bounds) {
#if defined(LEGACY_FUCHSIA_EMBEDDER)
- // If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
- // Layers that appear above the embedded content will be turned into their own
- // Scenic layers.
child_layer_exists_below_ = context->child_scene_layer_exists_below;
context->child_scene_layer_exists_below = false;
#endif
@@ -103,20 +98,63 @@
}
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
+ auto update_scene_layers = [&] {
+ // Paint all of the layers which need to be drawn into the container.
+ // These may be flattened down to a containing Scenic Frame.
+ for (auto& layer : layers_) {
+ if (layer->needs_system_composite()) {
+ layer->UpdateScene(context);
+ }
+ }
+ };
+
FML_DCHECK(needs_system_composite());
- std::optional<SceneUpdateContext::Frame> frame;
+ // If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
+ // PhysicalShapeLayers that appear above the embedded content will be turned
+ // into their own Scenic layers.
if (child_layer_exists_below_) {
- frame.emplace(
- context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
- SkScalarRoundToInt(context.alphaf() * 255), "flutter::ContainerLayer");
- frame->AddPaintLayer(this);
- }
+ float global_scenic_elevation =
+ context.GetGlobalElevationForNextScenicLayer();
+ float local_scenic_elevation =
+ global_scenic_elevation - context.scenic_elevation();
+ float z_translation = -local_scenic_elevation;
- for (auto& layer : layers_) {
- if (layer->needs_system_composite()) {
- layer->UpdateScene(context);
+ // Retained rendering: speedup by reusing a retained entity node if
+ // possible. When an entity node is reused, no paint layer is added to the
+ // frame so we won't call PhysicalShapeLayer::Paint.
+ LayerRasterCacheKey key(unique_id(), context.Matrix());
+ if (context.HasRetainedNode(key)) {
+ TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
+ scenic::EntityNode* retained_node = context.GetRetainedNode(key);
+ FML_DCHECK(context.top_entity());
+ FML_DCHECK(retained_node->session() == context.session());
+
+ // Re-adjust the elevation.
+ retained_node->SetTranslation(0.f, 0.f, z_translation);
+
+ context.top_entity()->entity_node().AddChild(*retained_node);
+ return;
}
+
+ TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
+ // If we can't find an existing retained surface, create one.
+ SceneUpdateContext::Frame frame(
+ context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
+ SkScalarRoundToInt(context.alphaf() * 255),
+ "flutter::PhysicalShapeLayer", z_translation, this);
+
+ frame.AddPaintLayer(this);
+
+ // Node: UpdateSceneChildren needs to be called here so that |frame| is
+ // still in scope (and therefore alive) while UpdateSceneChildren is being
+ // called.
+ float scenic_elevation = context.scenic_elevation();
+ context.set_scenic_elevation(scenic_elevation + local_scenic_elevation);
+ update_scene_layers();
+ context.set_scenic_elevation(scenic_elevation);
+ } else {
+ update_scene_layers();
}
}
diff --git a/flow/layers/fuchsia_layer_unittests.cc b/flow/layers/fuchsia_layer_unittests.cc
index fcc17c0..b1e7d2b 100644
--- a/flow/layers/fuchsia_layer_unittests.cc
+++ b/flow/layers/fuchsia_layer_unittests.cc
@@ -238,17 +238,57 @@
fuchsia::ui::scenic::SessionListenerPtr listener_;
};
-class MockSessionWrapper : public flutter::SessionWrapper {
+class MockSurfaceProducerSurface
+ : public SceneUpdateContext::SurfaceProducerSurface {
public:
- MockSessionWrapper(fuchsia::ui::scenic::SessionPtr session_ptr)
- : session_(std::move(session_ptr)) {}
- ~MockSessionWrapper() override = default;
+ MockSurfaceProducerSurface(scenic::Session* session, const SkISize& size)
+ : image_(session, 0, 0, {}), size_(size) {}
- scenic::Session* get() override { return &session_; }
- void Present() override { session_.Flush(); }
+ size_t AdvanceAndGetAge() override { return 0; }
+
+ bool FlushSessionAcquireAndReleaseEvents() override { return false; }
+
+ bool IsValid() const override { return false; }
+
+ SkISize GetSize() const override { return size_; }
+
+ void SignalWritesFinished(
+ const std::function<void(void)>& on_writes_committed) override {}
+
+ scenic::Image* GetImage() override { return &image_; };
+
+ sk_sp<SkSurface> GetSkiaSurface() const override { return nullptr; };
private:
- scenic::Session session_;
+ scenic::Image image_;
+ SkISize size_;
+};
+
+class MockSurfaceProducer : public SceneUpdateContext::SurfaceProducer {
+ public:
+ MockSurfaceProducer(scenic::Session* session) : session_(session) {}
+ std::unique_ptr<SceneUpdateContext::SurfaceProducerSurface> ProduceSurface(
+ const SkISize& size,
+ const LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) override {
+ return std::make_unique<MockSurfaceProducerSurface>(session_, size);
+ }
+
+ // Query a retained entity node (owned by a retained surface) for retained
+ // rendering.
+ bool HasRetainedNode(const LayerRasterCacheKey& key) const override {
+ return false;
+ }
+
+ scenic::EntityNode* GetRetainedNode(const LayerRasterCacheKey& key) override {
+ return nullptr;
+ }
+
+ void SubmitSurface(std::unique_ptr<SceneUpdateContext::SurfaceProducerSurface>
+ surface) override {}
+
+ private:
+ scenic::Session* session_;
};
struct TestContext {
@@ -257,11 +297,12 @@
fml::RefPtr<fml::TaskRunner> task_runner;
// Session.
- fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener> listener_request;
MockSession mock_session;
- std::unique_ptr<MockSessionWrapper> mock_session_wrapper;
+ fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener> listener_request;
+ std::unique_ptr<scenic::Session> session;
// SceneUpdateContext.
+ std::unique_ptr<MockSurfaceProducer> mock_surface_producer;
std::unique_ptr<SceneUpdateContext> scene_update_context;
// PrerollContext.
@@ -283,13 +324,15 @@
fuchsia::ui::scenic::SessionListenerPtr listener;
context->listener_request = listener.NewRequest();
context->mock_session.Bind(session_ptr.NewRequest(), std::move(listener));
- context->mock_session_wrapper =
- std::make_unique<MockSessionWrapper>(std::move(session_ptr));
+ context->session = std::make_unique<scenic::Session>(std::move(session_ptr));
// Init SceneUpdateContext.
+ context->mock_surface_producer =
+ std::make_unique<MockSurfaceProducer>(context->session.get());
context->scene_update_context = std::make_unique<SceneUpdateContext>(
- "fuchsia_layer_unittest", fuchsia::ui::views::ViewToken(),
- scenic::ViewRefPair::New(), *(context->mock_session_wrapper));
+ context->session.get(), context->mock_surface_producer.get());
+ context->scene_update_context->set_metrics(
+ fidl::MakeOptional(fuchsia::ui::gfx::Metrics{1.f, 1.f, 1.f}));
// Init PrerollContext.
context->preroll_context = std::unique_ptr<PrerollContext>(new PrerollContext{
@@ -305,6 +348,7 @@
context->unused_texture_registry, // texture registry (not
// supported)
false, // checkerboard_offscreen_layers
+ 100.f, // maximum depth allowed for rendering
1.f // ratio between logical and physical
});
@@ -558,7 +602,7 @@
// against the list above.
root->UpdateScene(*(test_context->scene_update_context));
- test_context->mock_session_wrapper->Present();
+ test_context->session->Flush();
// Run loop until idle, so that the Session receives and processes
// its method calls.
@@ -740,7 +784,7 @@
// commands against the list above.
root->UpdateScene(*(test_context->scene_update_context));
- test_context->mock_session_wrapper->Present();
+ test_context->session->Flush();
// Run loop until idle, so that the Session receives and processes
// its method calls.
diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc
index a242f97..97da04f 100644
--- a/flow/layers/layer.cc
+++ b/flow/layers/layer.cc
@@ -58,9 +58,6 @@
#if defined(LEGACY_FUCHSIA_EMBEDDER)
void Layer::CheckForChildLayerBelow(PrerollContext* context) {
- // If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
- // PhysicalShapeLayers that appear above the embedded content will be turned
- // into their own Scenic layers.
child_layer_exists_below_ = context->child_scene_layer_exists_below;
if (child_layer_exists_below_) {
set_needs_system_composite(true);
@@ -68,14 +65,42 @@
}
void Layer::UpdateScene(SceneUpdateContext& context) {
- FML_DCHECK(needs_system_composite());
- FML_DCHECK(child_layer_exists_below_);
+ // If there is embedded Fuchsia content in the scene (a ChildSceneLayer),
+ // PhysicalShapeLayers that appear above the embedded content will be turned
+ // into their own Scenic layers.
+ if (child_layer_exists_below_) {
+ float global_scenic_elevation =
+ context.GetGlobalElevationForNextScenicLayer();
+ float local_scenic_elevation =
+ global_scenic_elevation - context.scenic_elevation();
+ float z_translation = -local_scenic_elevation;
- SceneUpdateContext::Frame frame(
- context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
- SkScalarRoundToInt(context.alphaf() * 255), "flutter::Layer");
+ // Retained rendering: speedup by reusing a retained entity node if
+ // possible. When an entity node is reused, no paint layer is added to the
+ // frame so we won't call PhysicalShapeLayer::Paint.
+ LayerRasterCacheKey key(unique_id(), context.Matrix());
+ if (context.HasRetainedNode(key)) {
+ TRACE_EVENT_INSTANT0("flutter", "retained layer cache hit");
+ scenic::EntityNode* retained_node = context.GetRetainedNode(key);
+ FML_DCHECK(context.top_entity());
+ FML_DCHECK(retained_node->session() == context.session());
- frame.AddPaintLayer(this);
+ // Re-adjust the elevation.
+ retained_node->SetTranslation(0.f, 0.f, z_translation);
+
+ context.top_entity()->entity_node().AddChild(*retained_node);
+ return;
+ }
+
+ TRACE_EVENT_INSTANT0("flutter", "cache miss, creating");
+ // If we can't find an existing retained surface, create one.
+ SceneUpdateContext::Frame frame(
+ context, SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
+ SkScalarRoundToInt(context.alphaf() * 255),
+ "flutter::PhysicalShapeLayer", z_translation, this);
+
+ frame.AddPaintLayer(this);
+ }
}
#endif
diff --git a/flow/layers/layer.h b/flow/layers/layer.h
index f973276..b22a322 100644
--- a/flow/layers/layer.h
+++ b/flow/layers/layer.h
@@ -56,10 +56,14 @@
const Stopwatch& ui_time;
TextureRegistry& texture_registry;
const bool checkerboard_offscreen_layers;
- const float frame_device_pixel_ratio;
+
+ // These allow us to make use of the scene metrics during Preroll.
+ float frame_physical_depth;
+ float frame_device_pixel_ratio;
// These allow us to track properties like elevation, opacity, and the
// prescence of a platform view during Preroll.
+ float total_elevation = 0.0f;
bool has_platform_view = false;
bool is_opaque = true;
#if defined(LEGACY_FUCHSIA_EMBEDDER)
@@ -124,7 +128,10 @@
TextureRegistry& texture_registry;
const RasterCache* raster_cache;
const bool checkerboard_offscreen_layers;
- const float frame_device_pixel_ratio;
+
+ // These allow us to make use of the scene metrics during Paint.
+ float frame_physical_depth;
+ float frame_device_pixel_ratio;
};
// Calls SkCanvas::saveLayer and restores the layer upon destruction. Also
diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc
index 9b247b4..0f598ae 100644
--- a/flow/layers/layer_tree.cc
+++ b/flow/layers/layer_tree.cc
@@ -11,14 +11,15 @@
namespace flutter {
-LayerTree::LayerTree(const SkISize& frame_size, float device_pixel_ratio)
+LayerTree::LayerTree(const SkISize& frame_size,
+ float frame_physical_depth,
+ float frame_device_pixel_ratio)
: frame_size_(frame_size),
- device_pixel_ratio_(device_pixel_ratio),
+ frame_physical_depth_(frame_physical_depth),
+ frame_device_pixel_ratio_(frame_device_pixel_ratio),
rasterizer_tracing_threshold_(0),
checkerboard_raster_cache_images_(false),
- checkerboard_offscreen_layers_(false) {
- FML_CHECK(device_pixel_ratio_ != 0.0f);
-}
+ checkerboard_offscreen_layers_(false) {}
void LayerTree::RecordBuildTime(fml::TimePoint build_start,
fml::TimePoint target_time) {
@@ -53,21 +54,32 @@
frame.context().ui_time(),
frame.context().texture_registry(),
checkerboard_offscreen_layers_,
- device_pixel_ratio_};
+ frame_physical_depth_,
+ frame_device_pixel_ratio_};
root_layer_->Preroll(&context, frame.root_surface_transformation());
return context.surface_needs_readback;
}
#if defined(LEGACY_FUCHSIA_EMBEDDER)
-void LayerTree::UpdateScene(SceneUpdateContext& context) {
+void LayerTree::UpdateScene(SceneUpdateContext& context,
+ scenic::ContainerNode& container) {
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
- // Reset for a new Scene.
- context.Reset();
+ // Ensure the context is aware of the view metrics.
+ context.set_dimensions(frame_size_, frame_physical_depth_,
+ frame_device_pixel_ratio_);
- const float inv_dpr = 1.0f / device_pixel_ratio_;
- SceneUpdateContext::Transform transform(context, inv_dpr, inv_dpr, 1.0f);
+ const auto& metrics = context.metrics();
+ FML_DCHECK(metrics->scale_x > 0.0f);
+ FML_DCHECK(metrics->scale_y > 0.0f);
+ FML_DCHECK(metrics->scale_z > 0.0f);
+
+ SceneUpdateContext::Transform transform(context, // context
+ 1.0f / metrics->scale_x, // X
+ 1.0f / metrics->scale_y, // Y
+ 1.0f / metrics->scale_z // Z
+ );
SceneUpdateContext::Frame frame(
context,
@@ -80,7 +92,7 @@
if (root_layer_->needs_painting()) {
frame.AddPaintLayer(root_layer_.get());
}
- context.root_node().AddChild(transform.entity_node());
+ container.AddChild(transform.entity_node());
}
#endif
@@ -113,7 +125,8 @@
frame.context().texture_registry(),
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
checkerboard_offscreen_layers_,
- device_pixel_ratio_};
+ frame_physical_depth_,
+ frame_device_pixel_ratio_};
if (root_layer_->needs_painting()) {
root_layer_->Paint(context);
@@ -138,18 +151,19 @@
root_surface_transformation.reset();
PrerollContext preroll_context{
- nullptr, // raster_cache (don't consult the cache)
- nullptr, // gr_context (used for the raster cache)
- nullptr, // external view embedder
- unused_stack, // mutator stack
- nullptr, // SkColorSpace* dst_color_space
- kGiantRect, // SkRect cull_rect
- false, // layer reads from surface
- unused_stopwatch, // frame time (dont care)
- unused_stopwatch, // engine time (dont care)
- unused_texture_registry, // texture registry (not supported)
- false, // checkerboard_offscreen_layers
- device_pixel_ratio_ // ratio between logical and physical
+ nullptr, // raster_cache (don't consult the cache)
+ nullptr, // gr_context (used for the raster cache)
+ nullptr, // external view embedder
+ unused_stack, // mutator stack
+ nullptr, // SkColorSpace* dst_color_space
+ kGiantRect, // SkRect cull_rect
+ false, // layer reads from surface
+ unused_stopwatch, // frame time (dont care)
+ unused_stopwatch, // engine time (dont care)
+ unused_texture_registry, // texture registry (not supported)
+ false, // checkerboard_offscreen_layers
+ frame_physical_depth_, // maximum depth allowed for rendering
+ frame_device_pixel_ratio_ // ratio between logical and physical
};
SkISize canvas_size = canvas->getBaseLayerSize();
@@ -161,12 +175,13 @@
canvas, // canvas
nullptr,
nullptr,
- unused_stopwatch, // frame time (dont care)
- unused_stopwatch, // engine time (dont care)
- unused_texture_registry, // texture registry (not supported)
- nullptr, // raster cache
- false, // checkerboard offscreen layers
- device_pixel_ratio_ // ratio between logical and physical
+ unused_stopwatch, // frame time (dont care)
+ unused_stopwatch, // engine time (dont care)
+ unused_texture_registry, // texture registry (not supported)
+ nullptr, // raster cache
+ false, // checkerboard offscreen layers
+ frame_physical_depth_, // maximum depth allowed for rendering
+ frame_device_pixel_ratio_ // ratio between logical and physical
};
// Even if we don't have a root layer, we still need to create an empty
diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h
index efee960..733284a 100644
--- a/flow/layers/layer_tree.h
+++ b/flow/layers/layer_tree.h
@@ -20,7 +20,9 @@
class LayerTree {
public:
- LayerTree(const SkISize& frame_size, float device_pixel_ratio);
+ LayerTree(const SkISize& frame_size,
+ float frame_physical_depth,
+ float frame_device_pixel_ratio);
// Perform a preroll pass on the tree and return information about
// the tree that affects rendering this frame.
@@ -33,7 +35,8 @@
bool ignore_raster_cache = false);
#if defined(LEGACY_FUCHSIA_EMBEDDER)
- void UpdateScene(SceneUpdateContext& context);
+ void UpdateScene(SceneUpdateContext& context,
+ scenic::ContainerNode& container);
#endif
void Paint(CompositorContext::ScopedFrame& frame,
@@ -48,7 +51,8 @@
}
const SkISize& frame_size() const { return frame_size_; }
- float device_pixel_ratio() const { return device_pixel_ratio_; }
+ float frame_physical_depth() const { return frame_physical_depth_; }
+ float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
void RecordBuildTime(fml::TimePoint build_start, fml::TimePoint target_time);
fml::TimePoint build_start() const { return build_start_; }
@@ -75,13 +79,16 @@
checkerboard_offscreen_layers_ = checkerboard;
}
+ double device_pixel_ratio() const { return frame_device_pixel_ratio_; }
+
private:
std::shared_ptr<Layer> root_layer_;
fml::TimePoint build_start_;
fml::TimePoint build_finish_;
fml::TimePoint target_time_;
SkISize frame_size_ = SkISize::MakeEmpty(); // Physical pixels.
- const float device_pixel_ratio_; // Logical / Physical pixels ratio.
+ float frame_physical_depth_;
+ float frame_device_pixel_ratio_ = 1.0f; // Logical / Physical pixels ratio.
uint32_t rasterizer_tracing_threshold_;
bool checkerboard_raster_cache_images_;
bool checkerboard_offscreen_layers_;
diff --git a/flow/layers/layer_tree_unittests.cc b/flow/layers/layer_tree_unittests.cc
index 7045497..1215b72 100644
--- a/flow/layers/layer_tree_unittests.cc
+++ b/flow/layers/layer_tree_unittests.cc
@@ -18,7 +18,7 @@
class LayerTreeTest : public CanvasTest {
public:
LayerTreeTest()
- : layer_tree_(SkISize::Make(64, 64), 1.0f),
+ : layer_tree_(SkISize::Make(64, 64), 100.0f, 1.0f),
compositor_context_(fml::kDefaultFrameBudget),
root_transform_(SkMatrix::Translate(1.0f, 1.0f)),
scoped_frame_(compositor_context_.AcquireFrame(nullptr,
diff --git a/flow/layers/opacity_layer.h b/flow/layers/opacity_layer.h
index ed5f028..73e508f 100644
--- a/flow/layers/opacity_layer.h
+++ b/flow/layers/opacity_layer.h
@@ -38,6 +38,7 @@
private:
SkAlpha alpha_;
SkPoint offset_;
+ SkRRect frameRRect_;
FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
};
diff --git a/flow/layers/physical_shape_layer.cc b/flow/layers/physical_shape_layer.cc
index 7ba2b7c..4f87fb2 100644
--- a/flow/layers/physical_shape_layer.cc
+++ b/flow/layers/physical_shape_layer.cc
@@ -21,7 +21,28 @@
shadow_color_(shadow_color),
elevation_(elevation),
path_(path),
- clip_behavior_(clip_behavior) {}
+ isRect_(false),
+ clip_behavior_(clip_behavior) {
+ SkRect rect;
+ if (path.isRect(&rect)) {
+ isRect_ = true;
+ frameRRect_ = SkRRect::MakeRect(rect);
+ } else if (path.isRRect(&frameRRect_)) {
+ isRect_ = frameRRect_.isRect();
+ } else if (path.isOval(&rect)) {
+ // isRRect returns false for ovals, so we need to explicitly check isOval
+ // as well.
+ frameRRect_ = SkRRect::MakeOval(rect);
+ } else {
+ // Scenic currently doesn't provide an easy way to create shapes from
+ // arbitrary paths.
+ // For shapes that cannot be represented as a rounded rectangle we
+ // default to use the bounding rectangle.
+ // TODO(amirh): fix this once we have a way to create a Scenic shape from
+ // an SkPath.
+ frameRRect_ = SkRRect::MakeRect(path.getBounds());
+ }
+}
void PhysicalShapeLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
@@ -29,9 +50,14 @@
Layer::AutoPrerollSaveLayerState save =
Layer::AutoPrerollSaveLayerState::Create(context, UsesSaveLayer());
+ context->total_elevation += elevation_;
+ total_elevation_ = context->total_elevation;
+
SkRect child_paint_bounds;
PrerollChildren(context, matrix, &child_paint_bounds);
+ context->total_elevation -= elevation_;
+
if (elevation_ == 0) {
set_paint_bounds(path_.getBounds());
} else {
diff --git a/flow/layers/physical_shape_layer.h b/flow/layers/physical_shape_layer.h
index ce49af1..2c04368 100644
--- a/flow/layers/physical_shape_layer.h
+++ b/flow/layers/physical_shape_layer.h
@@ -35,13 +35,16 @@
return clip_behavior_ == Clip::antiAliasWithSaveLayer;
}
- float elevation() const { return elevation_; }
+ float total_elevation() const { return total_elevation_; }
private:
SkColor color_;
SkColor shadow_color_;
float elevation_ = 0.0f;
+ float total_elevation_ = 0.0f;
SkPath path_;
+ bool isRect_;
+ SkRRect frameRRect_;
Clip clip_behavior_;
};
diff --git a/flow/layers/physical_shape_layer_unittests.cc b/flow/layers/physical_shape_layer_unittests.cc
index bb5d0ac..7ad0b4e 100644
--- a/flow/layers/physical_shape_layer_unittests.cc
+++ b/flow/layers/physical_shape_layer_unittests.cc
@@ -131,7 +131,7 @@
initial_elevation, 1.0f));
EXPECT_TRUE(layer->needs_painting());
EXPECT_FALSE(layer->needs_system_composite());
- EXPECT_EQ(layer->elevation(), initial_elevation);
+ EXPECT_EQ(layer->total_elevation(), initial_elevation);
// The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
// their shadows , so we do not use the direct |Paint()| path there.
@@ -162,6 +162,7 @@
// |
// layers[1] + 2.0f = 3.0f
constexpr float initial_elevations[4] = {1.0f, 2.0f, 3.0f, 4.0f};
+ constexpr float total_elevations[4] = {1.0f, 3.0f, 4.0f, 8.0f};
SkPath layer_path;
layer_path.addRect(0, 0, 80, 80).close();
@@ -186,6 +187,7 @@
1.0f /* pixel_ratio */)));
EXPECT_TRUE(layers[i]->needs_painting());
EXPECT_FALSE(layers[i]->needs_system_composite());
+ EXPECT_EQ(layers[i]->total_elevation(), total_elevations[i]);
}
// The Fuchsia system compositor handles all elevated PhysicalShapeLayers and
diff --git a/flow/layers/platform_view_layer.cc b/flow/layers/platform_view_layer.cc
index 80514b5..0bd6ee7 100644
--- a/flow/layers/platform_view_layer.cc
+++ b/flow/layers/platform_view_layer.cc
@@ -48,9 +48,7 @@
#if defined(LEGACY_FUCHSIA_EMBEDDER)
void PlatformViewLayer::UpdateScene(SceneUpdateContext& context) {
- TRACE_EVENT0("flutter", "PlatformViewLayer::UpdateScene");
- FML_DCHECK(needs_system_composite());
- context.UpdateView(view_id_, offset_, size_);
+ context.UpdateScene(view_id_, offset_, size_);
}
#endif
diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc
index 8fe5dd3..d01c219 100644
--- a/flow/layers/transform_layer.cc
+++ b/flow/layers/transform_layer.cc
@@ -4,8 +4,6 @@
#include "flutter/flow/layers/transform_layer.h"
-#include <optional>
-
namespace flutter {
TransformLayer::TransformLayer(const SkMatrix& transform)
@@ -58,12 +56,12 @@
TRACE_EVENT0("flutter", "TransformLayer::UpdateScene");
FML_DCHECK(needs_system_composite());
- std::optional<SceneUpdateContext::Transform> transform;
if (!transform_.isIdentity()) {
- transform.emplace(context, transform_);
+ SceneUpdateContext::Transform transform(context, transform_);
+ UpdateSceneChildren(context);
+ } else {
+ UpdateSceneChildren(context);
}
-
- UpdateSceneChildren(context);
}
#endif
diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc
index c39a7e7..1e39e37 100644
--- a/flow/raster_cache.cc
+++ b/flow/raster_cache.cc
@@ -169,6 +169,7 @@
context->texture_registry,
context->has_platform_view ? nullptr : context->raster_cache,
context->checkerboard_offscreen_layers,
+ context->frame_physical_depth,
context->frame_device_pixel_ratio};
if (layer->needs_painting()) {
layer->Paint(paintContext);
diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc
index 698a23a..b0628ed 100644
--- a/flow/scene_update_context.cc
+++ b/flow/scene_update_context.cc
@@ -4,7 +4,6 @@
#include "flutter/flow/scene_update_context.h"
-#include <lib/ui/scenic/cpp/commands.h>
#include <lib/ui/scenic/cpp/view_token_pair.h>
#include "flutter/flow/layers/layer.h"
@@ -14,10 +13,10 @@
#include "include/core/SkColor.h"
namespace flutter {
-namespace {
-void SetEntityNodeClipPlanes(scenic::EntityNode& entity_node,
- const SkRect& bounds) {
+// Helper function to generate clip planes for a scenic::EntityNode.
+static void SetEntityNodeClipPlanes(scenic::EntityNode& entity_node,
+ const SkRect& bounds) {
const float top = bounds.top();
const float bottom = bounds.bottom();
const float left = bounds.left();
@@ -54,69 +53,20 @@
entity_node.SetClipPlanes(std::move(clip_planes));
}
-void SetMaterialColor(scenic::Material& material,
- SkColor color,
- SkAlpha opacity) {
- const SkAlpha color_alpha = static_cast<SkAlpha>(
- ((float)SkColorGetA(color) * (float)opacity) / 255.0f);
- material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
- color_alpha);
+SceneUpdateContext::SceneUpdateContext(scenic::Session* session,
+ SurfaceProducer* surface_producer)
+ : session_(session), surface_producer_(surface_producer) {
+ FML_DCHECK(surface_producer_ != nullptr);
}
-} // namespace
-
-SceneUpdateContext::SceneUpdateContext(std::string debug_label,
- fuchsia::ui::views::ViewToken view_token,
- scenic::ViewRefPair view_ref_pair,
- SessionWrapper& session)
- : session_(session),
- root_view_(session_.get(),
- std::move(view_token),
- std::move(view_ref_pair.control_ref),
- std::move(view_ref_pair.view_ref),
- debug_label),
- root_node_(session_.get()) {
- root_view_.AddChild(root_node_);
- root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
-
- session_.Present();
-}
-
-std::vector<SceneUpdateContext::PaintTask> SceneUpdateContext::GetPaintTasks() {
- std::vector<PaintTask> frame_paint_tasks = std::move(paint_tasks_);
-
- paint_tasks_.clear();
-
- return frame_paint_tasks;
-}
-
-void SceneUpdateContext::EnableWireframe(bool enable) {
- session_.get()->Enqueue(
- scenic::NewSetEnableDebugViewBoundsCmd(root_view_.id(), enable));
-}
-
-void SceneUpdateContext::Reset() {
- paint_tasks_.clear();
- top_entity_ = nullptr;
- top_scale_x_ = 1.f;
- top_scale_y_ = 1.f;
- top_elevation_ = 0.f;
- next_elevation_ = 0.f;
- alpha_ = 1.f;
-
- // We are going to be sending down a fresh node hierarchy every frame. So just
- // enqueue a detach op on the imported root node.
- session_.get()->Enqueue(scenic::NewDetachChildrenCmd(root_node_.id()));
-}
-
-void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node,
+void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node,
const SkRRect& rrect,
SkColor color,
SkAlpha opacity,
const SkRect& paint_bounds,
- std::vector<Layer*> paint_layers) {
- if (rrect.isEmpty())
- return;
+ std::vector<Layer*> paint_layers,
+ Layer* layer) {
+ FML_DCHECK(!rrect.isEmpty());
// Frames always clip their children.
SkRect shape_bounds = rrect.getBounds();
@@ -124,8 +74,11 @@
// and possibly for its texture.
// TODO(SCN-137): Need to be able to express the radii as vectors.
- scenic::ShapeNode shape_node(session_.get());
- scenic::Rectangle shape(session_.get(), rrect.width(), rrect.height());
+ scenic::ShapeNode shape_node(session());
+ scenic::Rectangle shape(session_, // session
+ rrect.width(), // width
+ rrect.height() // height
+ );
shape_node.SetShape(shape);
shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
shape_bounds.height() * 0.5f + shape_bounds.top(),
@@ -135,49 +88,155 @@
if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds))
paint_layers.clear();
- scenic::Material material(session_.get());
+ scenic::Material material(session());
shape_node.SetMaterial(material);
entity_node.AddChild(shape_node);
// Check whether a solid color will suffice.
- if (paint_layers.empty() || shape_bounds.isEmpty()) {
+ if (paint_layers.empty()) {
SetMaterialColor(material, color, opacity);
} else {
+ // Apply current metrics and transformation scale factors.
+ const float scale_x = ScaleX();
+ const float scale_y = ScaleY();
+
+ // Apply a texture to the whole shape.
+ SetMaterialTextureAndColor(material, color, opacity, scale_x, scale_y,
+ shape_bounds, std::move(paint_layers), layer,
+ std::move(entity_node));
+ }
+}
+
+void SceneUpdateContext::SetMaterialTextureAndColor(
+ scenic::Material& material,
+ SkColor color,
+ SkAlpha opacity,
+ SkScalar scale_x,
+ SkScalar scale_y,
+ const SkRect& paint_bounds,
+ std::vector<Layer*> paint_layers,
+ Layer* layer,
+ scenic::EntityNode entity_node) {
+ scenic::Image* image = GenerateImageIfNeeded(
+ color, scale_x, scale_y, paint_bounds, std::move(paint_layers), layer,
+ std::move(entity_node));
+
+ if (image != nullptr) {
// The final shape's color is material_color * texture_color. The passed in
// material color was already used as a background when generating the
// texture, so set the model color to |SK_ColorWHITE| in order to allow
// using the texture's color unmodified.
SetMaterialColor(material, SK_ColorWHITE, opacity);
-
- // Enqueue a paint task for these layers, to apply a texture to the whole
- // shape.
- paint_tasks_.emplace_back(PaintTask{.paint_bounds = paint_bounds,
- .scale_x = top_scale_x_,
- .scale_y = top_scale_y_,
- .background_color = color,
- .material = std::move(material),
- .layers = std::move(paint_layers)});
+ material.SetTexture(*image);
+ } else {
+ // No texture was needed, so apply a solid color to the whole shape.
+ SetMaterialColor(material, color, opacity);
}
}
-void SceneUpdateContext::UpdateView(int64_t view_id,
- const SkPoint& offset,
- const SkSize& size,
- std::optional<bool> override_hit_testable) {
+void SceneUpdateContext::SetMaterialColor(scenic::Material& material,
+ SkColor color,
+ SkAlpha opacity) {
+ const SkAlpha color_alpha = static_cast<SkAlpha>(
+ ((float)SkColorGetA(color) * (float)opacity) / 255.0f);
+ material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
+ color_alpha);
+}
+
+scenic::Image* SceneUpdateContext::GenerateImageIfNeeded(
+ SkColor color,
+ SkScalar scale_x,
+ SkScalar scale_y,
+ const SkRect& paint_bounds,
+ std::vector<Layer*> paint_layers,
+ Layer* layer,
+ scenic::EntityNode entity_node) {
+ // Bail if there's nothing to paint.
+ if (paint_layers.empty())
+ return nullptr;
+
+ // Bail if the physical bounds are empty after rounding.
+ SkISize physical_size = SkISize::Make(paint_bounds.width() * scale_x,
+ paint_bounds.height() * scale_y);
+ if (physical_size.isEmpty())
+ return nullptr;
+
+ // Acquire a surface from the surface producer and register the paint tasks.
+ std::unique_ptr<SurfaceProducerSurface> surface =
+ surface_producer_->ProduceSurface(
+ physical_size,
+ LayerRasterCacheKey(
+ // Root frame has a nullptr layer
+ layer ? layer->unique_id() : 0, Matrix()),
+ std::make_unique<scenic::EntityNode>(std::move(entity_node)));
+
+ if (!surface) {
+ FML_LOG(ERROR) << "Could not acquire a surface from the surface producer "
+ "of size: "
+ << physical_size.width() << "x" << physical_size.height();
+ return nullptr;
+ }
+
+ auto image = surface->GetImage();
+
+ // Enqueue the paint task.
+ paint_tasks_.push_back({.surface = std::move(surface),
+ .left = paint_bounds.left(),
+ .top = paint_bounds.top(),
+ .scale_x = scale_x,
+ .scale_y = scale_y,
+ .background_color = color,
+ .layers = std::move(paint_layers)});
+ return image;
+}
+
+std::vector<
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
+SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
+ TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
+ std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces_to_submit;
+ for (auto& task : paint_tasks_) {
+ FML_DCHECK(task.surface);
+ SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
+ Layer::PaintContext context = {canvas,
+ canvas,
+ frame.gr_context(),
+ nullptr,
+ frame.context().raster_time(),
+ frame.context().ui_time(),
+ frame.context().texture_registry(),
+ &frame.context().raster_cache(),
+ false,
+ frame_physical_depth_,
+ frame_device_pixel_ratio_};
+ canvas->restoreToCount(1);
+ canvas->save();
+ canvas->clear(task.background_color);
+ canvas->scale(task.scale_x, task.scale_y);
+ canvas->translate(-task.left, -task.top);
+ for (Layer* layer : task.layers) {
+ layer->Paint(context);
+ }
+ surfaces_to_submit.emplace_back(std::move(task.surface));
+ }
+ paint_tasks_.clear();
+ alpha_ = 1.f;
+ topmost_global_scenic_elevation_ = kScenicZElevationBetweenLayers;
+ scenic_elevation_ = 0.f;
+ return surfaces_to_submit;
+}
+
+void SceneUpdateContext::UpdateScene(int64_t view_id,
+ const SkPoint& offset,
+ const SkSize& size) {
auto* view_holder = ViewHolder::FromId(view_id);
FML_DCHECK(view_holder);
- if (size.width() > 0.f && size.height() > 0.f) {
- view_holder->SetProperties(size.width(), size.height(), 0, 0, 0, 0,
- view_holder->focusable());
- }
-
- bool hit_testable = override_hit_testable.has_value()
- ? *override_hit_testable
- : view_holder->hit_testable();
- view_holder->UpdateScene(session_.get(), top_entity_->embedder_node(), offset,
- size, SkScalarRoundToInt(alphaf() * 255),
- hit_testable);
+ view_holder->SetProperties(size.width(), size.height(), 0, 0, 0, 0,
+ view_holder->focusable());
+ view_holder->UpdateScene(*this, offset, size,
+ SkScalarRoundToInt(alphaf() * 255),
+ view_holder->hit_testable());
}
void SceneUpdateContext::CreateView(int64_t view_id,
@@ -201,17 +260,13 @@
SceneUpdateContext::Entity::Entity(SceneUpdateContext& context)
: context_(context),
previous_entity_(context.top_entity_),
- entity_node_(context.session_.get()) {
+ entity_node_(context.session()) {
+ if (previous_entity_)
+ previous_entity_->embedder_node().AddChild(entity_node_);
context.top_entity_ = this;
}
SceneUpdateContext::Entity::~Entity() {
- if (previous_entity_) {
- previous_entity_->embedder_node().AddChild(entity_node_);
- } else {
- context_.root_node_.AddChild(entity_node_);
- }
-
FML_DCHECK(context_.top_entity_ == this);
context_.top_entity_ = previous_entity_;
}
@@ -274,20 +329,18 @@
const SkRRect& rrect,
SkColor color,
SkAlpha opacity,
- std::string label)
+ std::string label,
+ float z_translation,
+ Layer* layer)
: Entity(context),
- previous_elevation_(context.top_elevation_),
rrect_(rrect),
color_(color),
opacity_(opacity),
- opacity_node_(context.session_.get()),
- paint_bounds_(SkRect::MakeEmpty()) {
+ opacity_node_(context.session()),
+ paint_bounds_(SkRect::MakeEmpty()),
+ layer_(layer) {
entity_node().SetLabel(label);
- entity_node().SetTranslation(0.f, 0.f,
- context.next_elevation_ - previous_elevation_);
- context.top_elevation_ += kScenicZElevationBetweenLayers;
- context.next_elevation_ += kScenicZElevationBetweenLayers;
-
+ entity_node().SetTranslation(0.f, 0.f, z_translation);
entity_node().AddChild(opacity_node_);
// Scenic currently lacks an API to enable rendering of alpha channel; alpha
// channels are only rendered if there is a OpacityNode higher in the tree
@@ -297,11 +350,20 @@
}
SceneUpdateContext::Frame::~Frame() {
- // Add a part which represents the frame's geometry for clipping purposes
- context().CreateFrame(entity_node(), rrect_, color_, opacity_, paint_bounds_,
- std::move(paint_layers_));
+ // We don't need a shape if the frame is zero size.
+ if (rrect_.isEmpty())
+ return;
- context().top_elevation_ = previous_elevation_;
+ // isEmpty should account for this, but we are adding these experimental
+ // checks to validate if this is the root cause for b/144933519.
+ if (std::isnan(rrect_.width()) || std::isnan(rrect_.height())) {
+ FML_LOG(ERROR) << "Invalid RoundedRectangle";
+ return;
+ }
+
+ // Add a part which represents the frame's geometry for clipping purposes
+ context().CreateFrame(std::move(entity_node()), rrect_, color_, opacity_,
+ paint_bounds_, std::move(paint_layers_), layer_);
}
void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) {
diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h
index 9ca6c7d..3b46fb2 100644
--- a/flow/scene_update_context.h
+++ b/flow/scene_update_context.h
@@ -5,19 +5,18 @@
#ifndef FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
#define FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
-#include <fuchsia/ui/views/cpp/fidl.h>
-#include <lib/ui/scenic/cpp/resources.h>
-#include <lib/ui/scenic/cpp/session.h>
-#include <lib/ui/scenic/cpp/view_ref_pair.h>
-
#include <cfloat>
#include <memory>
#include <set>
#include <vector>
+#include "flutter/flow/compositor_context.h"
#include "flutter/flow/embedded_views.h"
+#include "flutter/flow/raster_cache_key.h"
+#include "flutter/fml/compiler_specific.h"
#include "flutter/fml/logging.h"
#include "flutter/fml/macros.h"
+#include "lib/ui/scenic/cpp/resources.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -34,16 +33,50 @@
// How much layers are separated in Scenic z elevation.
constexpr float kScenicZElevationBetweenLayers = 10.f;
-class SessionWrapper {
- public:
- virtual ~SessionWrapper() {}
-
- virtual scenic::Session* get() = 0;
- virtual void Present() = 0;
-};
-
class SceneUpdateContext : public flutter::ExternalViewEmbedder {
public:
+ class SurfaceProducerSurface {
+ public:
+ virtual ~SurfaceProducerSurface() = default;
+
+ virtual size_t AdvanceAndGetAge() = 0;
+
+ virtual bool FlushSessionAcquireAndReleaseEvents() = 0;
+
+ virtual bool IsValid() const = 0;
+
+ virtual SkISize GetSize() const = 0;
+
+ virtual void SignalWritesFinished(
+ const std::function<void(void)>& on_writes_committed) = 0;
+
+ virtual scenic::Image* GetImage() = 0;
+
+ virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
+ };
+
+ class SurfaceProducer {
+ public:
+ virtual ~SurfaceProducer() = default;
+
+ // The produced surface owns the entity_node and has a layer_key for
+ // retained rendering. The surface will only be retained if the layer_key
+ // has a non-null layer pointer (layer_key.id()).
+ virtual std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
+ const SkISize& size,
+ const LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) = 0;
+
+ // Query a retained entity node (owned by a retained surface) for retained
+ // rendering.
+ virtual bool HasRetainedNode(const LayerRasterCacheKey& key) const = 0;
+ virtual scenic::EntityNode* GetRetainedNode(
+ const LayerRasterCacheKey& key) = 0;
+
+ virtual void SubmitSurface(
+ std::unique_ptr<SurfaceProducerSurface> surface) = 0;
+ };
+
class Entity {
public:
Entity(SceneUpdateContext& context);
@@ -83,7 +116,9 @@
const SkRRect& rrect,
SkColor color,
SkAlpha opacity,
- std::string label);
+ std::string label,
+ float z_translation = 0.0f,
+ Layer* layer = nullptr);
virtual ~Frame();
scenic::ContainerNode& embedder_node() override { return opacity_node_; }
@@ -91,8 +126,6 @@
void AddPaintLayer(Layer* layer);
private:
- const float previous_elevation_;
-
const SkRRect rrect_;
SkColor const color_;
SkAlpha const opacity_;
@@ -100,6 +133,7 @@
scenic::OpacityNodeHACK opacity_node_;
std::vector<Layer*> paint_layers_;
SkRect paint_bounds_;
+ Layer* layer_;
};
class Clip : public Entity {
@@ -108,35 +142,68 @@
~Clip() = default;
};
- struct PaintTask {
- SkRect paint_bounds;
- SkScalar scale_x;
- SkScalar scale_y;
- SkColor background_color;
- scenic::Material material;
- std::vector<Layer*> layers;
- };
-
- SceneUpdateContext(std::string debug_label,
- fuchsia::ui::views::ViewToken view_token,
- scenic::ViewRefPair view_ref_pair,
- SessionWrapper& session);
+ SceneUpdateContext(scenic::Session* session,
+ SurfaceProducer* surface_producer);
~SceneUpdateContext() = default;
- scenic::ContainerNode& root_node() { return root_node_; }
+ scenic::Session* session() { return session_; }
+
+ Entity* top_entity() { return top_entity_; }
+
+ bool has_metrics() const { return !!metrics_; }
+ void set_metrics(fuchsia::ui::gfx::MetricsPtr metrics) {
+ metrics_ = std::move(metrics);
+ }
+ const fuchsia::ui::gfx::MetricsPtr& metrics() const { return metrics_; }
+
+ void set_dimensions(const SkISize& frame_physical_size,
+ float frame_physical_depth,
+ float frame_device_pixel_ratio) {
+ frame_physical_size_ = frame_physical_size;
+ frame_physical_depth_ = frame_physical_depth;
+ frame_device_pixel_ratio_ = frame_device_pixel_ratio;
+ }
+ const SkISize& frame_size() const { return frame_physical_size_; }
+ float frame_physical_depth() const { return frame_physical_depth_; }
+ float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
+
+ // TODO(chinmaygarde): This method must submit the surfaces as soon as paint
+ // tasks are done. However, given that there is no support currently for
+ // Vulkan semaphores, we need to submit all the surfaces after an explicit
+ // CPU wait. Once Vulkan semaphores are available, this method must return
+ // void and the implementation must submit surfaces on its own as soon as the
+ // specific canvas operations are done.
+ [[nodiscard]] std::vector<std::unique_ptr<SurfaceProducerSurface>>
+ ExecutePaintTasks(CompositorContext::ScopedFrame& frame);
+
+ float ScaleX() const { return metrics_->scale_x * top_scale_x_; }
+ float ScaleY() const { return metrics_->scale_y * top_scale_y_; }
+
+ // The transformation matrix of the current context. It's used to construct
+ // the LayerRasterCacheKey for a given layer.
+ SkMatrix Matrix() const { return SkMatrix::MakeScale(ScaleX(), ScaleY()); }
+
+ bool HasRetainedNode(const LayerRasterCacheKey& key) const {
+ return surface_producer_->HasRetainedNode(key);
+ }
+ scenic::EntityNode* GetRetainedNode(const LayerRasterCacheKey& key) {
+ return surface_producer_->GetRetainedNode(key);
+ }
// The cumulative alpha value based on all the parent OpacityLayers.
void set_alphaf(float alpha) { alpha_ = alpha; }
float alphaf() { return alpha_; }
- // Returns all `PaintTask`s generated for the current frame.
- std::vector<PaintTask> GetPaintTasks();
+ // The global scenic elevation at a given point in the traversal.
+ float scenic_elevation() { return scenic_elevation_; }
- // Enable/disable wireframe rendering around the root view bounds.
- void EnableWireframe(bool enable);
+ void set_scenic_elevation(float elevation) { scenic_elevation_ = elevation; }
- // Reset state for a new frame.
- void Reset();
+ float GetGlobalElevationForNextScenicLayer() {
+ float elevation = topmost_global_scenic_elevation_;
+ topmost_global_scenic_elevation_ += kScenicZElevationBetweenLayers;
+ return elevation;
+ }
// |ExternalViewEmbedder|
SkCanvas* GetRootCanvas() override { return nullptr; }
@@ -167,34 +234,73 @@
}
void CreateView(int64_t view_id, bool hit_testable, bool focusable);
+
void DestroyView(int64_t view_id);
- void UpdateView(int64_t view_id,
- const SkPoint& offset,
- const SkSize& size,
- std::optional<bool> override_hit_testable = std::nullopt);
+
+ void UpdateScene(int64_t view_id, const SkPoint& offset, const SkSize& size);
private:
- void CreateFrame(scenic::EntityNode& entity_node,
+ struct PaintTask {
+ std::unique_ptr<SurfaceProducerSurface> surface;
+ SkScalar left;
+ SkScalar top;
+ SkScalar scale_x;
+ SkScalar scale_y;
+ SkColor background_color;
+ std::vector<Layer*> layers;
+ };
+
+ // Setup the entity_node as a frame that materialize all the paint_layers. In
+ // most cases, this creates a VulkanSurface (SurfaceProducerSurface) by
+ // calling SetShapeTextureOrColor and GenerageImageIfNeeded. Such surface will
+ // own the associated entity_node. If the layer pointer isn't nullptr, the
+ // surface (and thus the entity_node) will be retained for that layer to
+ // improve the performance.
+ void CreateFrame(scenic::EntityNode entity_node,
const SkRRect& rrect,
SkColor color,
SkAlpha opacity,
const SkRect& paint_bounds,
- std::vector<Layer*> paint_layers);
-
- SessionWrapper& session_;
-
- scenic::View root_view_;
- scenic::EntityNode root_node_;
-
- std::vector<PaintTask> paint_tasks_;
+ std::vector<Layer*> paint_layers,
+ Layer* layer);
+ void SetMaterialTextureAndColor(scenic::Material& material,
+ SkColor color,
+ SkAlpha opacity,
+ SkScalar scale_x,
+ SkScalar scale_y,
+ const SkRect& paint_bounds,
+ std::vector<Layer*> paint_layers,
+ Layer* layer,
+ scenic::EntityNode entity_node);
+ void SetMaterialColor(scenic::Material& material,
+ SkColor color,
+ SkAlpha opacity);
+ scenic::Image* GenerateImageIfNeeded(SkColor color,
+ SkScalar scale_x,
+ SkScalar scale_y,
+ const SkRect& paint_bounds,
+ std::vector<Layer*> paint_layers,
+ Layer* layer,
+ scenic::EntityNode entity_node);
Entity* top_entity_ = nullptr;
float top_scale_x_ = 1.f;
float top_scale_y_ = 1.f;
- float top_elevation_ = 0.f;
- float next_elevation_ = 0.f;
- float alpha_ = 1.f;
+ scenic::Session* const session_;
+ SurfaceProducer* const surface_producer_;
+
+ fuchsia::ui::gfx::MetricsPtr metrics_;
+ SkISize frame_physical_size_;
+ float frame_physical_depth_ = 0.0f;
+ float frame_device_pixel_ratio_ =
+ 1.0f; // Ratio between logical and physical pixels.
+
+ float alpha_ = 1.0f;
+ float scenic_elevation_ = 0.f;
+ float topmost_global_scenic_elevation_ = kScenicZElevationBetweenLayers;
+
+ std::vector<PaintTask> paint_tasks_;
FML_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext);
};
diff --git a/flow/testing/layer_test.h b/flow/testing/layer_test.h
index d2df8b4..c63057f 100644
--- a/flow/testing/layer_test.h
+++ b/flow/testing/layer_test.h
@@ -47,9 +47,11 @@
kGiantRect, /* cull_rect */
false, /* layer reads from surface */
raster_time_, ui_time_, texture_registry_,
- false, /* checkerboard_offscreen_layers */
- 1.0f, /* frame_device_pixel_ratio */
- false, /* has_platform_view */
+ false, /* checkerboard_offscreen_layers */
+ 100.0f, /* frame_physical_depth */
+ 1.0f, /* frame_device_pixel_ratio */
+ 0.0f, /* total_elevation */
+ false, /* has_platform_view */
}),
paint_context_({
TestT::mock_canvas().internal_canvas(), /* internal_nodes_canvas */
@@ -59,6 +61,7 @@
raster_time_, ui_time_, texture_registry_,
nullptr, /* raster_cache */
false, /* checkerboard_offscreen_layers */
+ 100.0f, /* frame_physical_depth */
1.0f, /* frame_device_pixel_ratio */
}) {
use_null_raster_cache();
diff --git a/flow/testing/mock_layer.cc b/flow/testing/mock_layer.cc
index b32bdb2..5fe1b98 100644
--- a/flow/testing/mock_layer.cc
+++ b/flow/testing/mock_layer.cc
@@ -22,6 +22,7 @@
parent_mutators_ = context->mutators_stack;
parent_matrix_ = matrix;
parent_cull_rect_ = context->cull_rect;
+ parent_elevation_ = context->total_elevation;
parent_has_platform_view_ = context->has_platform_view;
context->has_platform_view = fake_has_platform_view_;
diff --git a/flow/testing/mock_layer.h b/flow/testing/mock_layer.h
index b92583f..835c3ee 100644
--- a/flow/testing/mock_layer.h
+++ b/flow/testing/mock_layer.h
@@ -28,6 +28,7 @@
const MutatorsStack& parent_mutators() { return parent_mutators_; }
const SkMatrix& parent_matrix() { return parent_matrix_; }
const SkRect& parent_cull_rect() { return parent_cull_rect_; }
+ float parent_elevation() { return parent_elevation_; }
bool parent_has_platform_view() { return parent_has_platform_view_; }
private:
@@ -36,6 +37,7 @@
SkRect parent_cull_rect_ = SkRect::MakeEmpty();
SkPath fake_paint_path_;
SkPaint fake_paint_;
+ float parent_elevation_ = 0;
bool parent_has_platform_view_ = false;
bool fake_has_platform_view_ = false;
bool fake_needs_system_composite_ = false;
diff --git a/flow/testing/mock_layer_unittests.cc b/flow/testing/mock_layer_unittests.cc
index ebb837c..0e6e379 100644
--- a/flow/testing/mock_layer_unittests.cc
+++ b/flow/testing/mock_layer_unittests.cc
@@ -39,11 +39,13 @@
const SkMatrix start_matrix = SkMatrix::Translate(1.0f, 2.0f);
const SkMatrix scale_matrix = SkMatrix::Scale(0.5f, 0.5f);
const SkRect cull_rect = SkRect::MakeWH(5.0f, 5.0f);
+ const float parent_elevation = 5.0f;
const bool parent_has_platform_view = true;
auto layer = std::make_shared<MockLayer>(path, paint);
preroll_context()->mutators_stack.PushTransform(scale_matrix);
preroll_context()->cull_rect = cull_rect;
+ preroll_context()->total_elevation = parent_elevation;
preroll_context()->has_platform_view = parent_has_platform_view;
layer->Preroll(preroll_context(), start_matrix);
EXPECT_EQ(preroll_context()->has_platform_view, false);
@@ -53,6 +55,7 @@
EXPECT_EQ(layer->parent_mutators(), std::vector{Mutator(scale_matrix)});
EXPECT_EQ(layer->parent_matrix(), start_matrix);
EXPECT_EQ(layer->parent_cull_rect(), cull_rect);
+ EXPECT_EQ(layer->parent_elevation(), parent_elevation);
EXPECT_EQ(layer->parent_has_platform_view(), parent_has_platform_view);
layer->Paint(paint_context());
diff --git a/flow/view_holder.cc b/flow/view_holder.cc
index c201182..7fd0050 100644
--- a/flow/view_holder.cc
+++ b/flow/view_holder.cc
@@ -4,8 +4,6 @@
#include "flutter/flow/view_holder.h"
-#include <unordered_map>
-
#include "flutter/fml/thread_local.h"
namespace {
@@ -100,17 +98,18 @@
FML_DCHECK(pending_view_holder_token_.value);
}
-void ViewHolder::UpdateScene(scenic::Session* session,
- scenic::ContainerNode& container_node,
+void ViewHolder::UpdateScene(SceneUpdateContext& context,
const SkPoint& offset,
const SkSize& size,
SkAlpha opacity,
bool hit_testable) {
if (pending_view_holder_token_.value) {
- entity_node_ = std::make_unique<scenic::EntityNode>(session);
- opacity_node_ = std::make_unique<scenic::OpacityNodeHACK>(session);
+ entity_node_ = std::make_unique<scenic::EntityNode>(context.session());
+ opacity_node_ =
+ std::make_unique<scenic::OpacityNodeHACK>(context.session());
view_holder_ = std::make_unique<scenic::ViewHolder>(
- session, std::move(pending_view_holder_token_), "Flutter SceneHost");
+ context.session(), std::move(pending_view_holder_token_),
+ "Flutter SceneHost");
opacity_node_->AddChild(*entity_node_);
opacity_node_->SetLabel("flutter::ViewHolder");
entity_node_->Attach(*view_holder_);
@@ -126,7 +125,7 @@
FML_DCHECK(opacity_node_);
FML_DCHECK(view_holder_);
- container_node.AddChild(*opacity_node_);
+ context.top_entity()->embedder_node().AddChild(*opacity_node_);
opacity_node_->SetOpacity(opacity / 255.0f);
entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
entity_node_->SetHitTestBehavior(
diff --git a/flow/view_holder.h b/flow/view_holder.h
index f25b205..bb8ff83 100644
--- a/flow/view_holder.h
+++ b/flow/view_holder.h
@@ -9,17 +9,17 @@
#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/ui/scenic/cpp/id.h>
#include <lib/ui/scenic/cpp/resources.h>
-#include <lib/ui/scenic/cpp/session.h>
#include <zircon/types.h>
+#include "third_party/skia/include/core/SkMatrix.h"
+#include "third_party/skia/include/core/SkPoint.h"
+#include "third_party/skia/include/core/SkSize.h"
#include <memory>
+#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
#include "flutter/fml/task_runner.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkPoint.h"
-#include "third_party/skia/include/core/SkSize.h"
namespace flutter {
@@ -54,8 +54,7 @@
// Creates or updates the contained ViewHolder resource using the specified
// |SceneUpdateContext|.
- void UpdateScene(scenic::Session* session,
- scenic::ContainerNode& container_node,
+ void UpdateScene(SceneUpdateContext& context,
const SkPoint& offset,
const SkSize& size,
SkAlpha opacity,
diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc
index 96eac58..d70033a 100644
--- a/lib/ui/compositing/scene.cc
+++ b/lib/ui/compositing/scene.cc
@@ -50,6 +50,7 @@
layer_tree_ = std::make_unique<LayerTree>(
SkISize::Make(viewport_metrics.physical_width,
viewport_metrics.physical_height),
+ static_cast<float>(viewport_metrics.physical_depth),
static_cast<float>(viewport_metrics.device_pixel_ratio));
layer_tree_->set_root_layer(std::move(rootLayer));
layer_tree_->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
diff --git a/lib/ui/hooks.dart b/lib/ui/hooks.dart
index fa44deb..c010954 100644
--- a/lib/ui/hooks.dart
+++ b/lib/ui/hooks.dart
@@ -14,6 +14,7 @@
double devicePixelRatio,
double width,
double height,
+ double depth,
double viewPaddingTop,
double viewPaddingRight,
double viewPaddingBottom,
@@ -30,6 +31,7 @@
window
.._devicePixelRatio = devicePixelRatio
.._physicalSize = Size(width, height)
+ .._physicalDepth = depth
.._viewPadding = WindowPadding._(
top: viewPaddingTop,
right: viewPaddingRight,
diff --git a/lib/ui/window.dart b/lib/ui/window.dart
index 9b562ba..03fcfb0 100644
--- a/lib/ui/window.dart
+++ b/lib/ui/window.dart
@@ -627,6 +627,20 @@
Size get physicalSize => _physicalSize;
Size _physicalSize = Size.zero;
+ /// The physical depth is the maximum elevation that the Window allows.
+ ///
+ /// Physical layers drawn at or above this elevation will have their elevation
+ /// clamped to this value. This can happen if the physical layer itself has
+ /// an elevation larger than available depth, or if some ancestor of the layer
+ /// causes it to have a cumulative elevation that is larger than the available
+ /// depth.
+ ///
+ /// The default value is [double.maxFinite], which is used for platforms that
+ /// do not specify a maximum elevation. This property is currently on expected
+ /// to be set to a non-default value on Fuchsia.
+ double get physicalDepth => _physicalDepth;
+ double _physicalDepth = double.maxFinite;
+
/// The number of physical pixels on each side of the display rectangle into
/// which the application can render, but over which the operating system
/// will likely place system UI, such as the keyboard, that fully obscures
diff --git a/lib/ui/window/viewport_metrics.cc b/lib/ui/window/viewport_metrics.cc
index f642bd1..329cea0 100644
--- a/lib/ui/window/viewport_metrics.cc
+++ b/lib/ui/window/viewport_metrics.cc
@@ -8,8 +8,6 @@
namespace flutter {
-ViewportMetrics::ViewportMetrics() = default;
-
ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height,
@@ -50,6 +48,40 @@
ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
+ double p_physical_height,
+ double p_physical_depth,
+ double p_physical_padding_top,
+ double p_physical_padding_right,
+ double p_physical_padding_bottom,
+ double p_physical_padding_left,
+ double p_physical_view_inset_front,
+ double p_physical_view_inset_back,
+ double p_physical_view_inset_top,
+ double p_physical_view_inset_right,
+ double p_physical_view_inset_bottom,
+ double p_physical_view_inset_left)
+ : device_pixel_ratio(p_device_pixel_ratio),
+ physical_width(p_physical_width),
+ physical_height(p_physical_height),
+ physical_depth(p_physical_depth),
+ physical_padding_top(p_physical_padding_top),
+ physical_padding_right(p_physical_padding_right),
+ physical_padding_bottom(p_physical_padding_bottom),
+ physical_padding_left(p_physical_padding_left),
+ physical_view_inset_top(p_physical_view_inset_top),
+ physical_view_inset_right(p_physical_view_inset_right),
+ physical_view_inset_bottom(p_physical_view_inset_bottom),
+ physical_view_inset_left(p_physical_view_inset_left),
+ physical_view_inset_front(p_physical_view_inset_front),
+ physical_view_inset_back(p_physical_view_inset_back) {
+ // Ensure we don't have nonsensical dimensions.
+ FML_DCHECK(physical_width >= 0);
+ FML_DCHECK(physical_height >= 0);
+ FML_DCHECK(device_pixel_ratio > 0);
+}
+
+ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
+ double p_physical_width,
double p_physical_height)
: device_pixel_ratio(p_device_pixel_ratio),
physical_width(p_physical_width),
diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h
index 01081e3..d4a7311 100644
--- a/lib/ui/window/viewport_metrics.h
+++ b/lib/ui/window/viewport_metrics.h
@@ -5,10 +5,21 @@
#ifndef FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_
#define FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_
+#include <stdint.h>
+
namespace flutter {
+// This is the value of double.maxFinite from dart:core.
+// Platforms that do not explicitly set a depth will use this value, which
+// avoids the need to special case logic that wants to check the max depth on
+// the Dart side.
+static const double kUnsetDepth = 1.7976931348623157e+308;
+
struct ViewportMetrics {
- ViewportMetrics();
+ ViewportMetrics() = default;
+ ViewportMetrics(const ViewportMetrics& other) = default;
+
+ // Create a 2D ViewportMetrics instance.
ViewportMetrics(double p_device_pixel_ratio,
double p_physical_width,
double p_physical_height,
@@ -25,6 +36,22 @@
double p_physical_system_gesture_inset_bottom,
double p_physical_system_gesture_inset_left);
+ // Create a ViewportMetrics instance that contains z information.
+ ViewportMetrics(double p_device_pixel_ratio,
+ double p_physical_width,
+ double p_physical_height,
+ double p_physical_depth,
+ double p_physical_padding_top,
+ double p_physical_padding_right,
+ double p_physical_padding_bottom,
+ double p_physical_padding_left,
+ double p_physical_view_inset_front,
+ double p_physical_view_inset_back,
+ double p_physical_view_inset_top,
+ double p_physical_view_inset_right,
+ double p_physical_view_inset_bottom,
+ double p_physical_view_inset_left);
+
// Create a ViewportMetrics instance that doesn't include depth, padding, or
// insets.
ViewportMetrics(double p_device_pixel_ratio,
@@ -34,6 +61,7 @@
double device_pixel_ratio = 1.0;
double physical_width = 0;
double physical_height = 0;
+ double physical_depth = kUnsetDepth;
double physical_padding_top = 0;
double physical_padding_right = 0;
double physical_padding_bottom = 0;
@@ -42,6 +70,8 @@
double physical_view_inset_right = 0;
double physical_view_inset_bottom = 0;
double physical_view_inset_left = 0;
+ double physical_view_inset_front = kUnsetDepth;
+ double physical_view_inset_back = kUnsetDepth;
double physical_system_gesture_inset_top = 0;
double physical_system_gesture_inset_right = 0;
double physical_system_gesture_inset_bottom = 0;
@@ -51,6 +81,7 @@
struct LogicalSize {
double width = 0.0;
double height = 0.0;
+ double depth = kUnsetDepth;
};
struct LogicalInset {
@@ -58,11 +89,14 @@
double top = 0.0;
double right = 0.0;
double bottom = 0.0;
+ double front = kUnsetDepth;
+ double back = kUnsetDepth;
};
struct LogicalMetrics {
LogicalSize size;
double scale = 1.0;
+ double scale_z = 1.0;
LogicalInset padding;
LogicalInset view_inset;
};
diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc
index 1779998..d583682 100644
--- a/lib/ui/window/window.cc
+++ b/lib/ui/window/window.cc
@@ -49,6 +49,7 @@
tonic::ToDart(metrics.device_pixel_ratio),
tonic::ToDart(metrics.physical_width),
tonic::ToDart(metrics.physical_height),
+ tonic::ToDart(metrics.physical_depth),
tonic::ToDart(metrics.physical_padding_top),
tonic::ToDart(metrics.physical_padding_right),
tonic::ToDart(metrics.physical_padding_bottom),
diff --git a/lib/web_ui/lib/src/engine/window.dart b/lib/web_ui/lib/src/engine/window.dart
index 5f75265..6463e60 100644
--- a/lib/web_ui/lib/src/engine/window.dart
+++ b/lib/web_ui/lib/src/engine/window.dart
@@ -146,6 +146,9 @@
/// Overrides the value of [physicalSize] in tests.
ui.Size? webOnlyDebugPhysicalSizeOverride;
+ @override
+ double get physicalDepth => double.maxFinite;
+
/// Handles the browser history integration to allow users to use the back
/// button, etc.
final BrowserHistory _browserHistory = BrowserHistory();
diff --git a/lib/web_ui/lib/src/ui/window.dart b/lib/web_ui/lib/src/ui/window.dart
index ac4d936..fd9e667 100644
--- a/lib/web_ui/lib/src/ui/window.dart
+++ b/lib/web_ui/lib/src/ui/window.dart
@@ -455,6 +455,19 @@
/// observe when this value changes.
Size get physicalSize;
+ /// The physical depth is the maximum elevation that the Window allows.
+ ///
+ /// Physical layers drawn at or above this elevation will have their elevation
+ /// clamped to this value. This can happen if the physical layer itself has
+ /// an elevation larger than available depth, or if some ancestor of the layer
+ /// causes it to have a cumulative elevation that is larger than the available
+ /// depth.
+ ///
+ /// The default value is [double.maxFinite], which is used for platforms that
+ /// do not specify a maximum elevation. This property is currently on expected
+ /// to be set to a non-default value on Fuchsia.
+ double get physicalDepth;
+
/// The number of physical pixels on each side of the display rectangle into
/// which the application can render, but over which the operating system
/// will likely place system UI, such as the keyboard, that fully obscures
diff --git a/shell/common/engine.cc b/shell/common/engine.cc
index dc309f7..79f885d 100644
--- a/shell/common/engine.cc
+++ b/shell/common/engine.cc
@@ -276,6 +276,7 @@
bool dimensions_changed =
viewport_metrics_.physical_height != metrics.physical_height ||
viewport_metrics_.physical_width != metrics.physical_width ||
+ viewport_metrics_.physical_depth != metrics.physical_depth ||
viewport_metrics_.device_pixel_ratio != metrics.device_pixel_ratio;
viewport_metrics_ = metrics;
runtime_controller_->SetViewportMetrics(viewport_metrics_);
@@ -461,7 +462,8 @@
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||
- layer_tree->device_pixel_ratio() <= 0.0f) {
+ layer_tree->frame_physical_depth() <= 0.0f ||
+ layer_tree->frame_device_pixel_ratio() <= 0.0f) {
return;
}
diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc
index 6846884..075f4ad 100644
--- a/shell/common/shell_test.cc
+++ b/shell/common/shell_test.cc
@@ -129,6 +129,7 @@
auto layer_tree = std::make_unique<LayerTree>(
SkISize::Make(viewport_metrics.physical_width,
viewport_metrics.physical_height),
+ static_cast<float>(viewport_metrics.physical_depth),
static_cast<float>(viewport_metrics.device_pixel_ratio));
SkMatrix identity;
identity.setIdentity();
diff --git a/shell/platform/fuchsia/flutter/BUILD.gn b/shell/platform/fuchsia/flutter/BUILD.gn
index c8652cc..ba68d1b 100644
--- a/shell/platform/fuchsia/flutter/BUILD.gn
+++ b/shell/platform/fuchsia/flutter/BUILD.gn
@@ -12,6 +12,7 @@
import("//flutter/tools/fuchsia/fuchsia_archive.gni")
import("//flutter/tools/fuchsia/fuchsia_libs.gni")
import("//flutter/vulkan/config.gni")
+import("engine_flutter_runner.gni")
# Fuchsia uses its own custom Surface implementation.
shell_gpu_configuration("fuchsia_legacy_gpu_configuration") {
@@ -21,158 +22,10 @@
enable_metal = false
}
-source_set("flutter_runner_sources") {
- sources = [
- "accessibility_bridge.cc",
- "accessibility_bridge.h",
- "component.cc",
- "component.h",
- "compositor_context.cc",
- "compositor_context.h",
- "engine.cc",
- "engine.h",
- "flutter_runner_product_configuration.cc",
- "flutter_runner_product_configuration.h",
- "fuchsia_intl.cc",
- "fuchsia_intl.h",
- "isolate_configurator.cc",
- "isolate_configurator.h",
- "logging.h",
- "loop.cc",
- "loop.h",
- "platform_view.cc",
- "platform_view.h",
- "runner.cc",
- "runner.h",
- "session_connection.cc",
- "session_connection.h",
- "surface.cc",
- "surface.h",
- "task_observers.cc",
- "task_observers.h",
- "task_runner_adapter.cc",
- "task_runner_adapter.h",
- "thread.cc",
- "thread.h",
- "unique_fdio_ns.h",
- "vsync_recorder.cc",
- "vsync_recorder.h",
- "vsync_waiter.cc",
- "vsync_waiter.h",
- "vulkan_surface.cc",
- "vulkan_surface.h",
- "vulkan_surface_pool.cc",
- "vulkan_surface_pool.h",
- "vulkan_surface_producer.cc",
- "vulkan_surface_producer.h",
- ]
-
- # The use of these dependencies is temporary and will be moved behind the
- # embedder API.
- flutter_public_deps = [
- "//flutter/flow:flow_fuchsia_legacy",
- "//flutter/lib/ui:ui_fuchsia_legacy",
- "//flutter/runtime:runtime_fuchsia_legacy",
- "//flutter/shell/common:common_fuchsia_legacy",
- ]
- flutter_deps = [
- ":fuchsia_legacy_gpu_configuration",
- "//flutter/assets",
- "//flutter/common",
- "//flutter/fml",
- "//flutter/vulkan",
- ]
-
- public_deps = [
- "$fuchsia_sdk_root/pkg:scenic_cpp",
- "$fuchsia_sdk_root/pkg:sys_cpp",
- "//flutter/shell/platform/fuchsia/runtime/dart/utils",
- ] + flutter_public_deps
-
- deps = [
- "$fuchsia_sdk_root/fidl:fuchsia.accessibility.semantics",
- "$fuchsia_sdk_root/fidl:fuchsia.fonts",
- "$fuchsia_sdk_root/fidl:fuchsia.images",
- "$fuchsia_sdk_root/fidl:fuchsia.intl",
- "$fuchsia_sdk_root/fidl:fuchsia.io",
- "$fuchsia_sdk_root/fidl:fuchsia.sys",
- "$fuchsia_sdk_root/fidl:fuchsia.ui.app",
- "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic",
- "$fuchsia_sdk_root/pkg:async-cpp",
- "$fuchsia_sdk_root/pkg:async-default",
- "$fuchsia_sdk_root/pkg:async-loop",
- "$fuchsia_sdk_root/pkg:async-loop-cpp",
- "$fuchsia_sdk_root/pkg:fdio",
- "$fuchsia_sdk_root/pkg:fidl_cpp",
- "$fuchsia_sdk_root/pkg:syslog",
- "$fuchsia_sdk_root/pkg:trace",
- "$fuchsia_sdk_root/pkg:trace-engine",
- "$fuchsia_sdk_root/pkg:trace-provider-so",
- "$fuchsia_sdk_root/pkg:vfs_cpp",
- "$fuchsia_sdk_root/pkg:zx",
- "//flutter/shell/platform/fuchsia/dart-pkg/fuchsia",
- "//flutter/shell/platform/fuchsia/dart-pkg/zircon",
- ] + flutter_deps
-}
-
# Things that explicitly being excluded:
# 1. Kernel snapshot framework mode.
# 2. Profiler symbols.
-# Builds a flutter_runner
-#
-# Parameters:
-#
-# output_name (required):
-# The name of the resulting binary.
-#
-# extra_deps (required):
-# Any additional dependencies.
-#
-# product (required):
-# Whether to link against a Product mode Dart VM.
-#
-# extra_defines (optional):
-# Any additional preprocessor defines.
-template("flutter_runner") {
- assert(defined(invoker.output_name), "flutter_runner must define output_name")
- assert(defined(invoker.extra_deps), "flutter_runner must define extra_deps")
- assert(defined(invoker.product), "flutter_runner must define product")
-
- invoker_output_name = invoker.output_name
- extra_deps = invoker.extra_deps
-
- extra_defines = []
- if (defined(invoker.extra_defines)) {
- extra_defines += invoker.extra_defines
- }
-
- executable(target_name) {
- output_name = invoker_output_name
-
- defines = extra_defines
-
- sources = [ "main.cc" ]
-
- deps = [
- ":flutter_runner_sources",
- "$fuchsia_sdk_root/pkg:async-loop-cpp",
- "$fuchsia_sdk_root/pkg:trace",
- "$fuchsia_sdk_root/pkg:trace-provider-so",
- ] + extra_deps
-
- # The flags below are needed so that Dart's CPU profiler can walk the
- # C++ stack.
- cflags = [ "-fno-omit-frame-pointer" ]
-
- if (!invoker.product) {
- # This flag is needed so that the call to dladdr() in Dart's native symbol
- # resolver can report good symbol information for the CPU profiler.
- ldflags = [ "-rdynamic" ]
- }
- }
-}
-
flutter_runner("jit") {
output_name = "flutter_jit_runner"
product = false
@@ -414,36 +267,66 @@
output_name = "flutter_runner_tests"
sources = [
+ "accessibility_bridge.cc",
+ "accessibility_bridge.h",
"accessibility_bridge_unittest.cc",
+ "component.cc",
+ "component.h",
"component_unittest.cc",
"flutter_runner_fakes.h",
+ "flutter_runner_product_configuration.cc",
+ "flutter_runner_product_configuration.h",
+ "fuchsia_intl.cc",
+ "fuchsia_intl.h",
"fuchsia_intl_unittest.cc",
+ "logging.h",
+ "loop.cc",
+ "loop.h",
+ "platform_view.cc",
+ "platform_view.h",
"platform_view_unittest.cc",
+ "runner.cc",
+ "runner.h",
"runner_unittest.cc",
+ "surface.cc",
+ "surface.h",
+ "task_observers.cc",
+ "task_observers.h",
+ "task_runner_adapter.cc",
+ "task_runner_adapter.h",
"tests/flutter_runner_product_configuration_unittests.cc",
"tests/vsync_recorder_unittests.cc",
+ "thread.cc",
+ "thread.h",
+ "vsync_recorder.cc",
+ "vsync_recorder.h",
+ "vsync_waiter.cc",
+ "vsync_waiter.h",
"vsync_waiter_unittests.cc",
]
# This is needed for //third_party/googletest for linking zircon symbols.
libs = [ "//fuchsia/sdk/$host_os/arch/$target_cpu/sysroot/lib/libzircon.so" ]
- # The use of these dependencies is temporary and will be moved behind the
- # embedder API.
- flutter_deps = [
+ deps = [
+ ":aot",
+ ":flutter_runner_fixtures",
+ "//build/fuchsia/fidl:fuchsia.accessibility.semantics",
+ "//build/fuchsia/pkg:async-default",
+ "//build/fuchsia/pkg:async-loop-cpp",
+ "//build/fuchsia/pkg:async-loop-default",
+ "//build/fuchsia/pkg:scenic_cpp",
+ "//build/fuchsia/pkg:sys_cpp_testing",
+ "//flutter/common",
"//flutter/flow:flow_fuchsia_legacy",
"//flutter/lib/ui:ui_fuchsia_legacy",
+ "//flutter/runtime:runtime_fuchsia_legacy",
"//flutter/shell/common:common_fuchsia_legacy",
+ "//flutter/shell/platform/fuchsia/runtime/dart/utils",
+ "//flutter/testing",
"//third_party/dart/runtime:libdart_jit",
"//third_party/dart/runtime/platform:libdart_platform_jit",
]
-
- deps = [
- ":flutter_runner_fixtures",
- ":flutter_runner_sources",
- "//build/fuchsia/pkg:sys_cpp_testing",
- "//flutter/testing",
- ] + flutter_deps
}
executable("flutter_runner_tzdata_unittests") {
@@ -451,24 +334,34 @@
output_name = "flutter_runner_tzdata_tests"
- sources = [ "runner_tzdata_unittest.cc" ]
+ sources = [
+ "runner.cc",
+ "runner.h",
+ "runner_tzdata_unittest.cc",
+ ]
# This is needed for //third_party/googletest for linking zircon symbols.
libs = [ "//fuchsia/sdk/$host_os/arch/$target_cpu/sysroot/lib/libzircon.so" ]
- # The use of these dependencies is temporary and will be moved behind the
- # embedder API.
- flutter_deps = [
+ deps = [
+ ":aot",
+ ":flutter_runner_fixtures",
+ "//build/fuchsia/fidl:fuchsia.accessibility.semantics",
+ "//build/fuchsia/pkg:async-loop-cpp",
+ "//build/fuchsia/pkg:async-loop-default",
+ "//build/fuchsia/pkg:scenic_cpp",
+ "//build/fuchsia/pkg:sys_cpp_testing",
+ "//flutter/flow:flow_fuchsia_legacy",
"//flutter/lib/ui:ui_fuchsia_legacy",
+ "//flutter/runtime:runtime_fuchsia_legacy",
+ "//flutter/shell/common:common_fuchsia_legacy",
+ "//flutter/shell/platform/fuchsia/runtime/dart/utils",
+ "//flutter/testing",
"//third_party/dart/runtime:libdart_jit",
"//third_party/dart/runtime/platform:libdart_platform_jit",
+ "//third_party/icu",
+ "//third_party/skia",
]
-
- deps = [
- ":flutter_runner_fixtures",
- ":flutter_runner_sources",
- "//flutter/testing",
- ] + flutter_deps
}
executable("flutter_runner_scenic_unittests") {
@@ -476,27 +369,84 @@
output_name = "flutter_runner_scenic_tests"
- sources = [ "tests/session_connection_unittests.cc" ]
+ sources = [
+ "component.cc",
+ "component.h",
+ "compositor_context.cc",
+ "compositor_context.h",
+ "engine.cc",
+ "engine.h",
+ "fuchsia_intl.cc",
+ "fuchsia_intl.h",
+ "isolate_configurator.cc",
+ "isolate_configurator.h",
+ "logging.h",
+ "loop.cc",
+ "loop.h",
+ "platform_view.cc",
+ "platform_view.h",
+ "runner.cc",
+ "runner.h",
+ "session_connection.cc",
+ "session_connection.h",
+ "surface.cc",
+ "surface.h",
+ "task_observers.cc",
+ "task_observers.h",
+ "task_runner_adapter.cc",
+ "task_runner_adapter.h",
+ "tests/session_connection_unittests.cc",
+ "thread.cc",
+ "thread.h",
+ "unique_fdio_ns.h",
+ "vsync_recorder.cc",
+ "vsync_recorder.h",
+ "vsync_waiter.cc",
+ "vsync_waiter.h",
+ "vsync_waiter_unittests.cc",
+ "vulkan_surface.cc",
+ "vulkan_surface.h",
+ "vulkan_surface_pool.cc",
+ "vulkan_surface_pool.h",
+ "vulkan_surface_producer.cc",
+ "vulkan_surface_producer.h",
+ ]
# This is needed for //third_party/googletest for linking zircon symbols.
libs = [ "//fuchsia/sdk/$host_os/arch/$target_cpu/sysroot/lib/libzircon.so" ]
- # The use of these dependencies is temporary and will be moved behind the
- # embedder API.
- flutter_deps = [
+ deps = [
+ ":flutter_runner_fixtures",
+ ":jit",
+ "$fuchsia_sdk_root/fidl:fuchsia.ui.policy",
+ "$fuchsia_sdk_root/pkg:trace-provider-so",
+ "//build/fuchsia/fidl:fuchsia.accessibility.semantics",
+ "//build/fuchsia/pkg:async-default",
+ "//build/fuchsia/pkg:async-loop-cpp",
+ "//build/fuchsia/pkg:async-loop-default",
+ "//build/fuchsia/pkg:scenic_cpp",
+ "//build/fuchsia/pkg:sys_cpp_testing",
+ "//flutter/common",
+ "//flutter/flow:flow_fuchsia_legacy",
"//flutter/lib/ui:ui_fuchsia_legacy",
+ "//flutter/runtime:runtime_fuchsia_legacy",
+ "//flutter/shell/common:common_fuchsia_legacy",
+ "//flutter/shell/platform/fuchsia/dart-pkg/fuchsia",
+ "//flutter/shell/platform/fuchsia/dart-pkg/zircon",
+ "//flutter/shell/platform/fuchsia/runtime/dart/utils",
+ "//flutter/testing",
+ "//flutter/vulkan",
"//third_party/dart/runtime:libdart_jit",
"//third_party/dart/runtime/platform:libdart_platform_jit",
+ "//third_party/icu",
+ "//third_party/skia",
]
- deps = [
- ":flutter_runner_fixtures",
- ":flutter_runner_sources",
- "$fuchsia_sdk_root/fidl:fuchsia.ui.policy",
- "//flutter/testing",
- ] + flutter_deps
+ public_deps = [ "//third_party/googletest:gtest" ]
}
+# When adding a new dep here, please also ensure the dep is added to
+# testing/fuchsia/run_tests.sh and testing/fuchsia/test_fars
fuchsia_archive("flutter_runner_tests") {
testonly = true
@@ -843,8 +793,6 @@
resources += vulkan_icds
}
-# When adding a new dep here, please also ensure the dep is added to
-# testing/fuchsia/run_tests.sh and testing/fuchsia/test_fars
group("tests") {
testonly = true
diff --git a/shell/platform/fuchsia/flutter/component.cc b/shell/platform/fuchsia/flutter/component.cc
index 0106931..00cd9d3 100644
--- a/shell/platform/fuchsia/flutter/component.cc
+++ b/shell/platform/fuchsia/flutter/component.cc
@@ -365,12 +365,6 @@
// Controls whether category "skia" trace events are enabled.
settings_.trace_skia = true;
- settings_.verbose_logging = true;
-
- settings_.advisory_script_uri = debug_label_;
-
- settings_.advisory_script_entrypoint = debug_label_;
-
settings_.icu_data_path = "";
settings_.assets_dir = application_assets_directory_.get();
diff --git a/shell/platform/fuchsia/flutter/compositor_context.cc b/shell/platform/fuchsia/flutter/compositor_context.cc
index 599ebf7..b0bbfc7 100644
--- a/shell/platform/fuchsia/flutter/compositor_context.cc
+++ b/shell/platform/fuchsia/flutter/compositor_context.cc
@@ -4,8 +4,6 @@
#include "compositor_context.h"
-#include <vector>
-
#include "flutter/flow/layers/layer_tree.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
@@ -13,38 +11,30 @@
class ScopedFrame final : public flutter::CompositorContext::ScopedFrame {
public:
- ScopedFrame(CompositorContext& context,
- GrContext* gr_context,
- SkCanvas* canvas,
- flutter::ExternalViewEmbedder* view_embedder,
+ ScopedFrame(flutter::CompositorContext& context,
const SkMatrix& root_surface_transformation,
+ flutter::ExternalViewEmbedder* view_embedder,
bool instrumentation_enabled,
- bool surface_supports_readback,
- fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger,
- SessionConnection& session_connection,
- VulkanSurfaceProducer& surface_producer,
- flutter::SceneUpdateContext& scene_update_context)
- : flutter::CompositorContext::ScopedFrame(context,
- surface_producer.gr_context(),
- canvas,
- view_embedder,
- root_surface_transformation,
- instrumentation_enabled,
- surface_supports_readback,
- raster_thread_merger),
- session_connection_(session_connection),
- surface_producer_(surface_producer),
- scene_update_context_(scene_update_context) {}
+ SessionConnection& session_connection)
+ : flutter::CompositorContext::ScopedFrame(
+ context,
+ session_connection.vulkan_surface_producer()->gr_context(),
+ nullptr,
+ view_embedder,
+ root_surface_transformation,
+ instrumentation_enabled,
+ true,
+ nullptr),
+ session_connection_(session_connection) {}
private:
SessionConnection& session_connection_;
- VulkanSurfaceProducer& surface_producer_;
- flutter::SceneUpdateContext& scene_update_context_;
flutter::RasterStatus Raster(flutter::LayerTree& layer_tree,
bool ignore_raster_cache) override {
- std::vector<flutter::SceneUpdateContext::PaintTask> frame_paint_tasks;
- std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;
+ if (!session_connection_.has_metrics()) {
+ return flutter::RasterStatus::kSuccess;
+ }
{
// Preroll the Flutter layer tree. This allows Flutter to perform
@@ -57,80 +47,15 @@
// Traverse the Flutter layer tree so that the necessary session ops to
// represent the frame are enqueued in the underlying session.
TRACE_EVENT0("flutter", "UpdateScene");
- layer_tree.UpdateScene(scene_update_context_);
+ layer_tree.UpdateScene(session_connection_.scene_update_context(),
+ session_connection_.root_node());
}
{
- // Flush all pending session ops: create surfaces and enqueue session
- // Image ops for the frame's paint tasks, then Present.
+ // Flush all pending session ops.
TRACE_EVENT0("flutter", "SessionPresent");
- frame_paint_tasks = scene_update_context_.GetPaintTasks();
- for (auto& task : frame_paint_tasks) {
- SkISize physical_size =
- SkISize::Make(layer_tree.device_pixel_ratio() * task.scale_x *
- task.paint_bounds.width(),
- layer_tree.device_pixel_ratio() * task.scale_y *
- task.paint_bounds.height());
- if (physical_size.width() == 0 || physical_size.height() == 0) {
- frame_surfaces.emplace_back(nullptr);
- continue;
- }
- std::unique_ptr<SurfaceProducerSurface> surface =
- surface_producer_.ProduceSurface(physical_size);
- if (!surface) {
- FML_LOG(ERROR)
- << "Could not acquire a surface from the surface producer "
- "of size: "
- << physical_size.width() << "x" << physical_size.height();
- } else {
- task.material.SetTexture(*(surface->GetImage()));
- }
-
- frame_surfaces.emplace_back(std::move(surface));
- }
-
- session_connection_.Present();
- }
-
- {
- // Execute paint tasks in parallel with Scenic's side of the Present, then
- // signal fences.
- TRACE_EVENT0("flutter", "ExecutePaintTasks");
- size_t surface_index = 0;
- for (auto& task : frame_paint_tasks) {
- std::unique_ptr<SurfaceProducerSurface>& task_surface =
- frame_surfaces[surface_index++];
- if (!task_surface) {
- continue;
- }
-
- SkCanvas* canvas = task_surface->GetSkiaSurface()->getCanvas();
- flutter::Layer::PaintContext paint_context = {
- canvas,
- canvas,
- gr_context(),
- nullptr,
- context().raster_time(),
- context().ui_time(),
- context().texture_registry(),
- &context().raster_cache(),
- false,
- layer_tree.device_pixel_ratio()};
- canvas->restoreToCount(1);
- canvas->save();
- canvas->clear(task.background_color);
- canvas->scale(layer_tree.device_pixel_ratio() * task.scale_x,
- layer_tree.device_pixel_ratio() * task.scale_y);
- canvas->translate(-task.paint_bounds.left(), -task.paint_bounds.top());
- for (flutter::Layer* layer : task.layers) {
- layer->Paint(paint_context);
- }
- }
-
- // Tell the surface producer that a present has occurred so it can perform
- // book-keeping on buffer caches.
- surface_producer_.OnSurfacesPresented(std::move(frame_surfaces));
+ session_connection_.Present(this);
}
return flutter::RasterStatus::kSuccess;
@@ -140,14 +65,51 @@
};
CompositorContext::CompositorContext(
- SessionConnection& session_connection,
- VulkanSurfaceProducer& surface_producer,
- flutter::SceneUpdateContext& scene_update_context)
- : session_connection_(session_connection),
- surface_producer_(surface_producer),
- scene_update_context_(scene_update_context) {}
+ std::string debug_label,
+ fuchsia::ui::views::ViewToken view_token,
+ scenic::ViewRefPair view_ref_pair,
+ fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
+ fml::closure session_error_callback,
+ zx_handle_t vsync_event_handle)
+ : debug_label_(std::move(debug_label)),
+ session_connection_(
+ debug_label_,
+ std::move(view_token),
+ std::move(view_ref_pair),
+ std::move(session),
+ session_error_callback,
+ [](auto) {},
+ vsync_event_handle) {}
-CompositorContext::~CompositorContext() = default;
+void CompositorContext::OnSessionMetricsDidChange(
+ const fuchsia::ui::gfx::Metrics& metrics) {
+ session_connection_.set_metrics(metrics);
+}
+
+void CompositorContext::OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor) {
+ session_connection_.OnSessionSizeChangeHint(width_change_factor,
+ height_change_factor);
+}
+
+void CompositorContext::OnWireframeEnabled(bool enabled) {
+ session_connection_.set_enable_wireframe(enabled);
+}
+
+void CompositorContext::OnCreateView(int64_t view_id,
+ bool hit_testable,
+ bool focusable) {
+ session_connection_.scene_update_context().CreateView(view_id, hit_testable,
+ focusable);
+}
+
+void CompositorContext::OnDestroyView(int64_t view_id) {
+ session_connection_.scene_update_context().DestroyView(view_id);
+}
+
+CompositorContext::~CompositorContext() {
+ OnGrContextDestroyed();
+}
std::unique_ptr<flutter::CompositorContext::ScopedFrame>
CompositorContext::AcquireFrame(
@@ -158,10 +120,16 @@
bool instrumentation_enabled,
bool surface_supports_readback,
fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) {
+ // TODO: The AcquireFrame interface is too broad and must be refactored to get
+ // rid of the context and canvas arguments as those seem to be only used for
+ // colorspace correctness purposes on the mobile shells.
return std::make_unique<flutter_runner::ScopedFrame>(
- *this, gr_context, canvas, view_embedder, root_surface_transformation,
- instrumentation_enabled, surface_supports_readback, raster_thread_merger,
- session_connection_, surface_producer_, scene_update_context_);
+ *this, //
+ root_surface_transformation, //
+ view_embedder,
+ instrumentation_enabled, //
+ session_connection_ //
+ );
}
} // namespace flutter_runner
diff --git a/shell/platform/fuchsia/flutter/compositor_context.h b/shell/platform/fuchsia/flutter/compositor_context.h
index 542e5d3..6ad2878 100644
--- a/shell/platform/fuchsia/flutter/compositor_context.h
+++ b/shell/platform/fuchsia/flutter/compositor_context.h
@@ -5,15 +5,15 @@
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPOSITOR_CONTEXT_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPOSITOR_CONTEXT_H_
-#include <memory>
+#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <fuchsia/ui/views/cpp/fidl.h>
+#include <lib/fit/function.h>
+#include <lib/ui/scenic/cpp/view_ref_pair.h>
#include "flutter/flow/compositor_context.h"
#include "flutter/flow/embedded_views.h"
-#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
-
#include "session_connection.h"
-#include "vulkan_surface_producer.h"
namespace flutter_runner {
@@ -21,16 +21,31 @@
// Fuchsia.
class CompositorContext final : public flutter::CompositorContext {
public:
- CompositorContext(SessionConnection& session_connection,
- VulkanSurfaceProducer& surface_producer,
- flutter::SceneUpdateContext& scene_update_context);
+ CompositorContext(std::string debug_label,
+ fuchsia::ui::views::ViewToken view_token,
+ scenic::ViewRefPair view_ref_pair,
+ fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
+ fml::closure session_error_callback,
+ zx_handle_t vsync_event_handle);
~CompositorContext() override;
+ void OnSessionMetricsDidChange(const fuchsia::ui::gfx::Metrics& metrics);
+ void OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor);
+
+ void OnWireframeEnabled(bool enabled);
+ void OnCreateView(int64_t view_id, bool hit_testable, bool focusable);
+ void OnDestroyView(int64_t view_id);
+
+ flutter::ExternalViewEmbedder* GetViewEmbedder() {
+ return &session_connection_.scene_update_context();
+ }
+
private:
- SessionConnection& session_connection_;
- VulkanSurfaceProducer& surface_producer_;
- flutter::SceneUpdateContext& scene_update_context_;
+ const std::string debug_label_;
+ scenic::ViewRefPair view_ref_pair_;
+ SessionConnection session_connection_;
// |flutter::CompositorContext|
std::unique_ptr<ScopedFrame> AcquireFrame(
diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc
index 82c66fc..7868a19 100644
--- a/shell/platform/fuchsia/flutter/engine.cc
+++ b/shell/platform/fuchsia/flutter/engine.cc
@@ -7,6 +7,9 @@
#include <lib/async/cpp/task.h>
#include <zircon/status.h>
+#include <sstream>
+
+#include "compositor_context.h"
#include "flutter/common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/waitable_event.h"
@@ -14,21 +17,18 @@
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/run_configuration.h"
-#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
-
-#include "../runtime/dart/utils/files.h"
-#include "compositor_context.h"
#include "flutter_runner_product_configuration.h"
#include "fuchsia_intl.h"
#include "platform_view.h"
+#include "runtime/dart/utils/files.h"
#include "task_runner_adapter.h"
+#include "third_party/skia/include/ports/SkFontMgr_fuchsia.h"
#include "thread.h"
namespace flutter_runner {
-namespace {
-void UpdateNativeThreadLabelNames(const std::string& label,
- const flutter::TaskRunners& runners) {
+static void UpdateNativeThreadLabelNames(const std::string& label,
+ const flutter::TaskRunners& runners) {
auto set_thread_name = [](fml::RefPtr<fml::TaskRunner> runner,
std::string prefix, std::string suffix) {
if (!runner) {
@@ -44,15 +44,13 @@
set_thread_name(runners.GetIOTaskRunner(), label, ".io");
}
-fml::RefPtr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
+static fml::RefPtr<flutter::PlatformMessage> MakeLocalizationPlatformMessage(
const fuchsia::intl::Profile& intl_profile) {
return fml::MakeRefCounted<flutter::PlatformMessage>(
"flutter/localization", MakeLocalizationPlatformMessageData(intl_profile),
nullptr);
}
-} // namespace
-
Engine::Engine(Delegate& delegate,
std::string thread_label,
std::shared_ptr<sys::ServiceDirectory> svc,
@@ -66,70 +64,28 @@
FlutterRunnerProductConfiguration product_config)
: delegate_(delegate),
thread_label_(std::move(thread_label)),
+ settings_(std::move(settings)),
weak_factory_(this) {
if (zx::event::create(0, &vsync_event_) != ZX_OK) {
FML_DLOG(ERROR) << "Could not create the vsync event.";
return;
}
- // Get the task runners from the managed threads. The current thread will be
- // used as the "platform" thread.
- const flutter::TaskRunners task_runners(
- thread_label_, // Dart thread labels
- CreateFMLTaskRunner(async_get_default_dispatcher()), // platform
- CreateFMLTaskRunner(threads_[0].dispatcher()), // raster
- CreateFMLTaskRunner(threads_[1].dispatcher()), // ui
- CreateFMLTaskRunner(threads_[2].dispatcher()) // io
- );
- UpdateNativeThreadLabelNames(thread_label_, task_runners);
+ // Launch the threads that will be used to run the shell. These threads will
+ // be joined in the destructor.
+ for (auto& thread : threads_) {
+ thread.reset(new Thread());
+ }
- // Connect to Scenic.
+ // Set up the session connection.
auto scenic = svc->Connect<fuchsia::ui::scenic::Scenic>();
fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session;
fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> session_listener;
auto session_listener_request = session_listener.NewRequest();
scenic->CreateSession(session.NewRequest(), session_listener.Bind());
- // Make clones of the `ViewRef` before sending it down to Scenic.
- fuchsia::ui::views::ViewRef platform_view_ref, isolate_view_ref;
- view_ref_pair.view_ref.Clone(&platform_view_ref);
- view_ref_pair.view_ref.Clone(&isolate_view_ref);
-
- // Session is terminated on the raster thread, but we must terminate ourselves
- // on the platform thread.
- //
- // This handles the fidl error callback when the Session connection is
- // broken. The SessionListener interface also has an OnError method, which is
- // invoked on the platform thread (in PlatformView).
- fml::closure session_error_callback = [dispatcher =
- async_get_default_dispatcher(),
- weak = weak_factory_.GetWeakPtr()]() {
- async::PostTask(dispatcher, [weak]() {
- if (weak) {
- weak->Terminate();
- }
- });
- };
-
- // Set up the session connection and other Scenic helpers on the raster
- // thread.
- task_runners.GetRasterTaskRunner()->PostTask(fml::MakeCopyable(
- [this, session = std::move(session),
- session_error_callback = std::move(session_error_callback),
- view_token = std::move(view_token),
- view_ref_pair = std::move(view_ref_pair),
- vsync_handle = vsync_event_.get()]() mutable {
- session_connection_.emplace(
- thread_label_, std::move(session),
- std::move(session_error_callback), [](auto) {}, vsync_handle);
- surface_producer_.emplace(session_connection_->get());
- scene_update_context_.emplace(thread_label_, std::move(view_token),
- std::move(view_ref_pair),
- session_connection_.value());
- }));
-
- // Grab the parent environment services. The platform view may want to
- // access some of these services.
+ // Grab the parent environment services. The platform view may want to access
+ // some of these services.
fuchsia::sys::EnvironmentPtr environment;
svc->Connect(environment.NewRequest());
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider>
@@ -137,15 +93,23 @@
environment->GetServices(parent_environment_service_provider.NewRequest());
environment.Unbind();
- OnEnableWireframe on_enable_wireframe_callback = std::bind(
- &Engine::DebugWireframeSettingsChanged, this, std::placeholders::_1);
+ // We need to manually schedule a frame when the session metrics change.
+ OnMetricsUpdate on_session_metrics_change_callback = std::bind(
+ &Engine::OnSessionMetricsDidChange, this, std::placeholders::_1);
- OnCreateView on_create_view_callback =
- std::bind(&Engine::CreateView, this, std::placeholders::_1,
+ OnSizeChangeHint on_session_size_change_hint_callback =
+ std::bind(&Engine::OnSessionSizeChangeHint, this, std::placeholders::_1,
+ std::placeholders::_2);
+
+ OnEnableWireframe on_enable_wireframe_callback = std::bind(
+ &Engine::OnDebugWireframeSettingsChanged, this, std::placeholders::_1);
+
+ flutter_runner::OnCreateView on_create_view_callback =
+ std::bind(&Engine::OnCreateView, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3);
- OnDestroyView on_destroy_view_callback =
- std::bind(&Engine::DestroyView, this, std::placeholders::_1);
+ flutter_runner::OnDestroyView on_destroy_view_callback =
+ std::bind(&Engine::OnDestroyView, this, std::placeholders::_1);
OnGetViewEmbedder on_get_view_embedder_callback =
std::bind(&Engine::GetViewEmbedder, this);
@@ -163,6 +127,10 @@
});
};
+ fuchsia::ui::views::ViewRef platform_view_ref, isolate_view_ref;
+ view_ref_pair.view_ref.Clone(&platform_view_ref);
+ view_ref_pair.view_ref.Clone(&isolate_view_ref);
+
// Setup the callback that will instantiate the platform view.
flutter::Shell::CreateCallback<flutter::PlatformView>
on_create_platform_view = fml::MakeCopyable(
@@ -173,6 +141,10 @@
session_listener_request = std::move(session_listener_request),
on_session_listener_error_callback =
std::move(on_session_listener_error_callback),
+ on_session_metrics_change_callback =
+ std::move(on_session_metrics_change_callback),
+ on_session_size_change_hint_callback =
+ std::move(on_session_size_change_hint_callback),
on_enable_wireframe_callback =
std::move(on_enable_wireframe_callback),
on_create_view_callback = std::move(on_create_view_callback),
@@ -190,6 +162,8 @@
std::move(parent_environment_service_provider), // services
std::move(session_listener_request), // session listener
std::move(on_session_listener_error_callback),
+ std::move(on_session_metrics_change_callback),
+ std::move(on_session_size_change_hint_callback),
std::move(on_enable_wireframe_callback),
std::move(on_create_view_callback),
std::move(on_destroy_view_callback),
@@ -198,17 +172,53 @@
product_config);
});
+ // Session can be terminated on the raster thread, but we must terminate
+ // ourselves on the platform thread.
+ //
+ // This handles the fidl error callback when the Session connection is
+ // broken. The SessionListener interface also has an OnError method, which is
+ // invoked on the platform thread (in PlatformView).
+ fml::closure on_session_error_callback =
+ [dispatcher = async_get_default_dispatcher(),
+ weak = weak_factory_.GetWeakPtr()]() {
+ async::PostTask(dispatcher, [weak]() {
+ if (weak) {
+ weak->Terminate();
+ }
+ });
+ };
+
+ // Get the task runners from the managed threads. The current thread will be
+ // used as the "platform" thread.
+ const flutter::TaskRunners task_runners(
+ thread_label_, // Dart thread labels
+ CreateFMLTaskRunner(async_get_default_dispatcher()), // platform
+ CreateFMLTaskRunner(threads_[0]->dispatcher()), // raster
+ CreateFMLTaskRunner(threads_[1]->dispatcher()), // ui
+ CreateFMLTaskRunner(threads_[2]->dispatcher()) // io
+ );
+
// Setup the callback that will instantiate the rasterizer.
flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
- fml::MakeCopyable([this](flutter::Shell& shell) mutable {
- FML_DCHECK(session_connection_);
- FML_DCHECK(surface_producer_);
- FML_DCHECK(scene_update_context_);
-
- std::unique_ptr<flutter_runner::CompositorContext> compositor_context =
- std::make_unique<flutter_runner::CompositorContext>(
- session_connection_.value(), surface_producer_.value(),
- scene_update_context_.value());
+ fml::MakeCopyable([thread_label = thread_label_, //
+ view_token = std::move(view_token), //
+ view_ref_pair = std::move(view_ref_pair), //
+ session = std::move(session), //
+ on_session_error_callback, //
+ vsync_event = vsync_event_.get() //
+ ](flutter::Shell& shell) mutable {
+ std::unique_ptr<flutter_runner::CompositorContext> compositor_context;
+ {
+ TRACE_DURATION("flutter", "CreateCompositorContext");
+ compositor_context =
+ std::make_unique<flutter_runner::CompositorContext>(
+ thread_label, // debug label
+ std::move(view_token), // scenic view we attach our tree to
+ std::move(view_ref_pair), // scenic view ref/view ref control
+ std::move(session), // scenic session
+ on_session_error_callback, // session did encounter error
+ vsync_event); // vsync event handle
+ }
return std::make_unique<flutter::Rasterizer>(
/*task_runners=*/shell.GetTaskRunners(),
@@ -216,9 +226,18 @@
/*is_gpu_disabled_sync_switch=*/shell.GetIsGpuDisabledSyncSwitch());
});
- settings.root_isolate_create_callback =
+ UpdateNativeThreadLabelNames(thread_label_, task_runners);
+
+ settings_.verbose_logging = true;
+
+ settings_.advisory_script_uri = thread_label_;
+
+ settings_.advisory_script_entrypoint = thread_label_;
+
+ settings_.root_isolate_create_callback =
std::bind(&Engine::OnMainIsolateStart, this);
- settings.root_isolate_shutdown_callback =
+
+ settings_.root_isolate_shutdown_callback =
std::bind([weak = weak_factory_.GetWeakPtr(),
runner = task_runners.GetPlatformTaskRunner()]() {
runner->PostTask([weak = std::move(weak)] {
@@ -228,7 +247,7 @@
});
});
- auto vm = flutter::DartVMRef::Create(settings);
+ auto vm = flutter::DartVMRef::Create(settings_);
if (!isolate_snapshot) {
isolate_snapshot = vm->GetVMData()->GetIsolateSnapshot();
@@ -237,13 +256,13 @@
{
TRACE_EVENT0("flutter", "CreateShell");
shell_ = flutter::Shell::Create(
- std::move(task_runners), // host task runners
- flutter::PlatformData(), // default window data
- std::move(settings), // shell launch settings
- std::move(isolate_snapshot), // isolate snapshot
- std::move(on_create_platform_view), // platform view create callback
- std::move(on_create_rasterizer), // rasterizer create callback
- std::move(vm) // vm reference
+ task_runners, // host task runners
+ flutter::PlatformData(), // default window data
+ settings_, // shell launch settings
+ std::move(isolate_snapshot), // isolate snapshot
+ on_create_platform_view, // platform view create callback
+ on_create_rasterizer, // rasterizer create callback
+ std::move(vm) // vm reference
);
}
@@ -320,7 +339,7 @@
// Launch the engine in the appropriate configuration.
auto run_configuration = flutter::RunConfiguration::InferFromSettings(
- shell_->GetSettings(), shell_->GetTaskRunners().GetIOTaskRunner());
+ settings_, task_runners.GetIOTaskRunner());
auto on_run_failure = [weak = weak_factory_.GetWeakPtr()]() {
// The engine could have been killed by the caller right after the
@@ -357,11 +376,11 @@
Engine::~Engine() {
shell_.reset();
- for (auto& thread : threads_) {
- thread.Quit();
+ for (const auto& thread : threads_) {
+ thread->Quit();
}
- for (auto& thread : threads_) {
- thread.Join();
+ for (const auto& thread : threads_) {
+ thread->Join();
}
}
@@ -466,41 +485,105 @@
// collected this object.
}
-void Engine::DebugWireframeSettingsChanged(bool enabled) {
- if (!shell_ || !scene_update_context_) {
+void Engine::OnSessionMetricsDidChange(
+ const fuchsia::ui::gfx::Metrics& metrics) {
+ if (!shell_) {
return;
}
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
- [this, enabled]() { scene_update_context_->EnableWireframe(enabled); });
-}
+ [rasterizer = shell_->GetRasterizer(), metrics]() {
+ if (rasterizer) {
+ auto compositor_context =
+ reinterpret_cast<flutter_runner::CompositorContext*>(
+ rasterizer->compositor_context());
-void Engine::CreateView(int64_t view_id, bool hit_testable, bool focusable) {
- if (!shell_ || !scene_update_context_) {
- return;
- }
-
- shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
- [this, view_id, hit_testable, focusable]() {
- scene_update_context_->CreateView(view_id, hit_testable, focusable);
+ compositor_context->OnSessionMetricsDidChange(metrics);
+ }
});
}
-void Engine::DestroyView(int64_t view_id) {
- if (!shell_ || !scene_update_context_) {
+void Engine::OnDebugWireframeSettingsChanged(bool enabled) {
+ if (!shell_) {
return;
}
shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
- [this, view_id]() { scene_update_context_->DestroyView(view_id); });
+ [rasterizer = shell_->GetRasterizer(), enabled]() {
+ if (rasterizer) {
+ auto compositor_context =
+ reinterpret_cast<flutter_runner::CompositorContext*>(
+ rasterizer->compositor_context());
+
+ compositor_context->OnWireframeEnabled(enabled);
+ }
+ });
+}
+
+void Engine::OnCreateView(int64_t view_id, bool hit_testable, bool focusable) {
+ if (!shell_) {
+ return;
+ }
+
+ shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
+ [rasterizer = shell_->GetRasterizer(), view_id, hit_testable,
+ focusable]() {
+ if (rasterizer) {
+ auto compositor_context =
+ reinterpret_cast<flutter_runner::CompositorContext*>(
+ rasterizer->compositor_context());
+ compositor_context->OnCreateView(view_id, hit_testable, focusable);
+ }
+ });
+}
+
+void Engine::OnDestroyView(int64_t view_id) {
+ if (!shell_) {
+ return;
+ }
+
+ shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
+ [rasterizer = shell_->GetRasterizer(), view_id]() {
+ if (rasterizer) {
+ auto compositor_context =
+ reinterpret_cast<flutter_runner::CompositorContext*>(
+ rasterizer->compositor_context());
+ compositor_context->OnDestroyView(view_id);
+ }
+ });
}
flutter::ExternalViewEmbedder* Engine::GetViewEmbedder() {
- if (!scene_update_context_) {
- return nullptr;
+ // GetEmbedder should be called only after rasterizer is created.
+ FML_DCHECK(shell_);
+ FML_DCHECK(shell_->GetRasterizer());
+
+ auto rasterizer = shell_->GetRasterizer();
+ auto compositor_context =
+ reinterpret_cast<flutter_runner::CompositorContext*>(
+ rasterizer->compositor_context());
+ flutter::ExternalViewEmbedder* view_embedder =
+ compositor_context->GetViewEmbedder();
+ return view_embedder;
+}
+
+void Engine::OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor) {
+ if (!shell_) {
+ return;
}
- return &scene_update_context_.value();
+ shell_->GetTaskRunners().GetRasterTaskRunner()->PostTask(
+ [rasterizer = shell_->GetRasterizer(), width_change_factor,
+ height_change_factor]() {
+ if (rasterizer) {
+ auto compositor_context = reinterpret_cast<CompositorContext*>(
+ rasterizer->compositor_context());
+
+ compositor_context->OnSessionSizeChangeHint(width_change_factor,
+ height_change_factor);
+ }
+ });
}
#if !defined(DART_PRODUCT)
diff --git a/shell/platform/fuchsia/flutter/engine.h b/shell/platform/fuchsia/flutter/engine.h
index fdd7f68..5ed4139 100644
--- a/shell/platform/fuchsia/flutter/engine.h
+++ b/shell/platform/fuchsia/flutter/engine.h
@@ -15,15 +15,11 @@
#include <lib/zx/event.h>
#include "flutter/flow/embedded_views.h"
-#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
#include "flutter/shell/common/shell.h"
-
#include "flutter_runner_product_configuration.h"
#include "isolate_configurator.h"
-#include "session_connection.h"
#include "thread.h"
-#include "vulkan_surface_producer.h"
namespace flutter_runner {
@@ -59,22 +55,15 @@
private:
Delegate& delegate_;
-
const std::string thread_label_;
- std::array<Thread, 3> threads_;
-
- std::optional<SessionConnection> session_connection_;
- std::optional<VulkanSurfaceProducer> surface_producer_;
- std::optional<flutter::SceneUpdateContext> scene_update_context_;
-
+ flutter::Settings settings_;
+ std::array<std::unique_ptr<Thread>, 3> threads_;
std::unique_ptr<IsolateConfigurator> isolate_configurator_;
std::unique_ptr<flutter::Shell> shell_;
-
- fuchsia::intl::PropertyProviderPtr intl_property_provider_;
-
zx::event vsync_event_;
-
fml::WeakPtrFactory<Engine> weak_factory_;
+ // A stub for the FIDL protocol fuchsia.intl.PropertyProvider.
+ fuchsia::intl::PropertyProviderPtr intl_property_provider_;
void OnMainIsolateStart();
@@ -82,9 +71,15 @@
void Terminate();
- void DebugWireframeSettingsChanged(bool enabled);
- void CreateView(int64_t view_id, bool hit_testable, bool focusable);
- void DestroyView(int64_t view_id);
+ void OnSessionMetricsDidChange(const fuchsia::ui::gfx::Metrics& metrics);
+ void OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor);
+
+ void OnDebugWireframeSettingsChanged(bool enabled);
+
+ void OnCreateView(int64_t view_id, bool hit_testable, bool focusable);
+
+ void OnDestroyView(int64_t view_id);
flutter::ExternalViewEmbedder* GetViewEmbedder();
diff --git a/shell/platform/fuchsia/flutter/engine_flutter_runner.gni b/shell/platform/fuchsia/flutter/engine_flutter_runner.gni
new file mode 100644
index 0000000..630575b
--- /dev/null
+++ b/shell/platform/fuchsia/flutter/engine_flutter_runner.gni
@@ -0,0 +1,150 @@
+# Copyright 2013 The Flutter Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_fuchsia)
+
+import("//build/fuchsia/sdk.gni")
+
+# Builds a flutter_runner
+#
+# Parameters:
+#
+# output_name (required):
+# The name of the resulting binary.
+#
+# extra_deps (required):
+# Any additional dependencies.
+#
+# product (required):
+# Whether to link against a Product mode Dart VM.
+#
+# extra_defines (optional):
+# Any additional preprocessor defines.
+template("flutter_runner") {
+ assert(defined(invoker.output_name), "flutter_runner must define output_name")
+ assert(defined(invoker.extra_deps), "flutter_runner must define extra_deps")
+ assert(defined(invoker.product), "flutter_runner must define product")
+
+ invoker_output_name = invoker.output_name
+ extra_deps = invoker.extra_deps
+
+ extra_defines = []
+ if (defined(invoker.extra_defines)) {
+ extra_defines += invoker.extra_defines
+ }
+
+ executable(target_name) {
+ output_name = invoker_output_name
+
+ defines = extra_defines
+
+ libs = []
+
+ sources = [
+ "accessibility_bridge.cc",
+ "accessibility_bridge.h",
+ "component.cc",
+ "component.h",
+ "compositor_context.cc",
+ "compositor_context.h",
+ "engine.cc",
+ "engine.h",
+ "flutter_runner_product_configuration.cc",
+ "flutter_runner_product_configuration.h",
+ "fuchsia_intl.cc",
+ "fuchsia_intl.h",
+ "isolate_configurator.cc",
+ "isolate_configurator.h",
+ "logging.h",
+ "loop.cc",
+ "loop.h",
+ "main.cc",
+ "platform_view.cc",
+ "platform_view.h",
+ "runner.cc",
+ "runner.h",
+ "session_connection.cc",
+ "session_connection.h",
+ "surface.cc",
+ "surface.h",
+ "task_observers.cc",
+ "task_observers.h",
+ "task_runner_adapter.cc",
+ "task_runner_adapter.h",
+ "thread.cc",
+ "thread.h",
+ "unique_fdio_ns.h",
+ "vsync_recorder.cc",
+ "vsync_recorder.h",
+ "vsync_waiter.cc",
+ "vsync_waiter.h",
+ "vulkan_surface.cc",
+ "vulkan_surface.h",
+ "vulkan_surface_pool.cc",
+ "vulkan_surface_pool.h",
+ "vulkan_surface_producer.cc",
+ "vulkan_surface_producer.h",
+ ]
+
+ # The use of these dependencies is temporary and will be moved behind the
+ # embedder API.
+ flutter_deps = [
+ "../flutter:fuchsia_legacy_gpu_configuration",
+ "//flutter/assets",
+ "//flutter/common",
+ "//flutter/flow:flow_fuchsia_legacy",
+ "//flutter/fml",
+ "//flutter/lib/ui:ui_fuchsia_legacy",
+ "//flutter/runtime:runtime_fuchsia_legacy",
+ "//flutter/shell/common:common_fuchsia_legacy",
+ "//flutter/vulkan",
+ ]
+
+ _fuchsia_platform = "//flutter/shell/platform/fuchsia"
+
+ # TODO(kaushikiska) evaluate if all of these are needed.
+ fuchsia_deps = [
+ "${_fuchsia_platform}/dart-pkg/fuchsia",
+ "${_fuchsia_platform}/dart-pkg/zircon",
+ "${_fuchsia_platform}/runtime/dart/utils",
+ ]
+
+ deps = [
+ "$fuchsia_sdk_root/fidl:fuchsia.accessibility.semantics",
+ "$fuchsia_sdk_root/fidl:fuchsia.fonts",
+ "$fuchsia_sdk_root/fidl:fuchsia.images",
+ "$fuchsia_sdk_root/fidl:fuchsia.intl",
+ "$fuchsia_sdk_root/fidl:fuchsia.io",
+ "$fuchsia_sdk_root/fidl:fuchsia.sys",
+ "$fuchsia_sdk_root/fidl:fuchsia.ui.app",
+ "$fuchsia_sdk_root/fidl:fuchsia.ui.scenic",
+ "$fuchsia_sdk_root/pkg:async-cpp",
+ "$fuchsia_sdk_root/pkg:async-default",
+ "$fuchsia_sdk_root/pkg:async-loop",
+ "$fuchsia_sdk_root/pkg:async-loop-cpp",
+ "$fuchsia_sdk_root/pkg:fdio",
+ "$fuchsia_sdk_root/pkg:fidl_cpp",
+ "$fuchsia_sdk_root/pkg:scenic_cpp",
+ "$fuchsia_sdk_root/pkg:sys_cpp",
+ "$fuchsia_sdk_root/pkg:syslog",
+ "$fuchsia_sdk_root/pkg:trace",
+ "$fuchsia_sdk_root/pkg:trace-engine",
+ "$fuchsia_sdk_root/pkg:trace-provider-so",
+ "$fuchsia_sdk_root/pkg:vfs_cpp",
+ "$fuchsia_sdk_root/pkg:zx",
+ "//third_party/skia",
+ "//flutter/third_party/tonic",
+ ] + fuchsia_deps + flutter_deps + extra_deps
+
+ # The flags below are needed so that Dart's CPU profiler can walk the
+ # C++ stack.
+ cflags = [ "-fno-omit-frame-pointer" ]
+
+ if (!invoker.product) {
+ # This flag is needed so that the call to dladdr() in Dart's native symbol
+ # resolver can report good symbol information for the CPU profiler.
+ ldflags = [ "-rdynamic" ]
+ }
+ }
+}
diff --git a/shell/platform/fuchsia/flutter/platform_view.cc b/shell/platform/fuchsia/flutter/platform_view.cc
index 81441b4..df2b454 100644
--- a/shell/platform/fuchsia/flutter/platform_view.cc
+++ b/shell/platform/fuchsia/flutter/platform_view.cc
@@ -6,7 +6,6 @@
#include "platform_view.h"
-#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <sstream>
#include "flutter/fml/logging.h"
@@ -23,6 +22,41 @@
namespace flutter_runner {
+namespace {
+
+inline fuchsia::ui::gfx::vec3 Add(const fuchsia::ui::gfx::vec3& a,
+ const fuchsia::ui::gfx::vec3& b) {
+ return {.x = a.x + b.x, .y = a.y + b.y, .z = a.z + b.z};
+}
+
+inline fuchsia::ui::gfx::vec3 Subtract(const fuchsia::ui::gfx::vec3& a,
+ const fuchsia::ui::gfx::vec3& b) {
+ return {.x = a.x - b.x, .y = a.y - b.y, .z = a.z - b.z};
+}
+
+inline fuchsia::ui::gfx::BoundingBox InsetBy(
+ const fuchsia::ui::gfx::BoundingBox& box,
+ const fuchsia::ui::gfx::vec3& inset_from_min,
+ const fuchsia::ui::gfx::vec3& inset_from_max) {
+ return {.min = Add(box.min, inset_from_min),
+ .max = Subtract(box.max, inset_from_max)};
+}
+
+inline fuchsia::ui::gfx::BoundingBox ViewPropertiesLayoutBox(
+ const fuchsia::ui::gfx::ViewProperties& view_properties) {
+ return InsetBy(view_properties.bounding_box, view_properties.inset_from_min,
+ view_properties.inset_from_max);
+}
+
+inline fuchsia::ui::gfx::vec3 Max(const fuchsia::ui::gfx::vec3& v,
+ float min_val) {
+ return {.x = std::max(v.x, min_val),
+ .y = std::max(v.y, min_val),
+ .z = std::max(v.z, min_val)};
+}
+
+} // end namespace
+
static constexpr char kFlutterPlatformChannel[] = "flutter/platform";
static constexpr char kTextInputChannel[] = "flutter/textinput";
static constexpr char kKeyEventChannel[] = "flutter/keyevent";
@@ -55,6 +89,8 @@
fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>
session_listener_request,
fit::closure session_listener_error_callback,
+ OnMetricsUpdate session_metrics_did_change_callback,
+ OnSizeChangeHint session_size_change_hint_callback,
OnEnableWireframe wireframe_enabled_callback,
OnCreateView on_create_view_callback,
OnDestroyView on_destroy_view_callback,
@@ -67,6 +103,8 @@
session_listener_binding_(this, std::move(session_listener_request)),
session_listener_error_callback_(
std::move(session_listener_error_callback)),
+ metrics_changed_callback_(std::move(session_metrics_did_change_callback)),
+ size_change_hint_callback_(std::move(session_size_change_hint_callback)),
wireframe_enabled_callback_(std::move(wireframe_enabled_callback)),
on_create_view_callback_(std::move(on_create_view_callback)),
on_destroy_view_callback_(std::move(on_destroy_view_callback)),
@@ -114,6 +152,64 @@
this, std::placeholders::_1);
}
+void PlatformView::OnPropertiesChanged(
+ const fuchsia::ui::gfx::ViewProperties& view_properties) {
+ fuchsia::ui::gfx::BoundingBox layout_box =
+ ViewPropertiesLayoutBox(view_properties);
+
+ fuchsia::ui::gfx::vec3 logical_size =
+ Max(Subtract(layout_box.max, layout_box.min), 0.f);
+
+ metrics_.size.width = logical_size.x;
+ metrics_.size.height = logical_size.y;
+ metrics_.size.depth = logical_size.z;
+ metrics_.padding.left = view_properties.inset_from_min.x;
+ metrics_.padding.top = view_properties.inset_from_min.y;
+ metrics_.padding.front = view_properties.inset_from_min.z;
+ metrics_.padding.right = view_properties.inset_from_max.x;
+ metrics_.padding.bottom = view_properties.inset_from_max.y;
+ metrics_.padding.back = view_properties.inset_from_max.z;
+
+ FlushViewportMetrics();
+}
+
+// TODO(SCN-975): Re-enable.
+// void PlatformView::ConnectSemanticsProvider(
+// fuchsia::ui::viewsv1token::ViewToken token) {
+// semantics_bridge_.SetupEnvironment(
+// token.value, parent_environment_service_provider_.get());
+// }
+
+void PlatformView::UpdateViewportMetrics(
+ const fuchsia::ui::gfx::Metrics& metrics) {
+ metrics_.scale = metrics.scale_x;
+ metrics_.scale_z = metrics.scale_z;
+
+ FlushViewportMetrics();
+}
+
+void PlatformView::FlushViewportMetrics() {
+ const auto scale = metrics_.scale;
+ const auto scale_z = metrics_.scale_z;
+
+ SetViewportMetrics({
+ scale, // device_pixel_ratio
+ metrics_.size.width * scale, // physical_width
+ metrics_.size.height * scale, // physical_height
+ metrics_.size.depth * scale_z, // physical_depth
+ metrics_.padding.top * scale, // physical_padding_top
+ metrics_.padding.right * scale, // physical_padding_right
+ metrics_.padding.bottom * scale, // physical_padding_bottom
+ metrics_.padding.left * scale, // physical_padding_left
+ metrics_.view_inset.front * scale_z, // physical_view_inset_front
+ metrics_.view_inset.back * scale_z, // physical_view_inset_back
+ metrics_.view_inset.top * scale, // physical_view_inset_top
+ metrics_.view_inset.right * scale, // physical_view_inset_right
+ metrics_.view_inset.bottom * scale, // physical_view_inset_bottom
+ metrics_.view_inset.left * scale // physical_view_inset_left
+ });
+}
+
// |fuchsia::ui::input::InputMethodEditorClient|
void PlatformView::DidUpdateState(
fuchsia::ui::input::TextInputState state,
@@ -206,40 +302,27 @@
void PlatformView::OnScenicEvent(
std::vector<fuchsia::ui::scenic::Event> events) {
TRACE_EVENT0("flutter", "PlatformView::OnScenicEvent");
- bool should_update_metrics = false;
for (const auto& event : events) {
switch (event.Which()) {
case fuchsia::ui::scenic::Event::Tag::kGfx:
switch (event.gfx().Which()) {
case fuchsia::ui::gfx::Event::Tag::kMetrics: {
- const fuchsia::ui::gfx::Metrics& metrics =
- event.gfx().metrics().metrics;
- const float new_view_pixel_ratio = metrics.scale_x;
-
- // Avoid metrics update when possible -- it is computationally
- // expensive.
- if (view_pixel_ratio_ != new_view_pixel_ratio) {
- view_pixel_ratio_ = new_view_pixel_ratio;
- should_update_metrics = true;
+ if (!fidl::Equals(event.gfx().metrics().metrics, scenic_metrics_)) {
+ scenic_metrics_ = std::move(event.gfx().metrics().metrics);
+ metrics_changed_callback_(scenic_metrics_);
+ UpdateViewportMetrics(scenic_metrics_);
}
break;
}
+ case fuchsia::ui::gfx::Event::Tag::kSizeChangeHint: {
+ size_change_hint_callback_(
+ event.gfx().size_change_hint().width_change_factor,
+ event.gfx().size_change_hint().height_change_factor);
+ break;
+ }
case fuchsia::ui::gfx::Event::Tag::kViewPropertiesChanged: {
- const fuchsia::ui::gfx::BoundingBox& bounding_box =
- event.gfx().view_properties_changed().properties.bounding_box;
- const float new_view_width =
- std::max(bounding_box.max.x - bounding_box.min.x, 0.0f);
- const float new_view_height =
- std::max(bounding_box.max.y - bounding_box.min.y, 0.0f);
-
- // Avoid metrics update when possible -- it is computationally
- // expensive.
- if (view_width_ != new_view_width ||
- view_height_ != new_view_width) {
- view_width_ = new_view_width;
- view_height_ = new_view_height;
- should_update_metrics = true;
- }
+ OnPropertiesChanged(
+ std::move(event.gfx().view_properties_changed().properties));
break;
}
case fuchsia::ui::gfx::Event::Tag::kViewConnected:
@@ -289,26 +372,6 @@
}
}
}
-
- if (should_update_metrics) {
- SetViewportMetrics({
- view_pixel_ratio_, // device_pixel_ratio
- view_width_ * view_pixel_ratio_, // physical_width
- view_height_ * view_pixel_ratio_, // physical_height
- 0.0f, // physical_padding_top
- 0.0f, // physical_padding_right
- 0.0f, // physical_padding_bottom
- 0.0f, // physical_padding_left
- 0.0f, // physical_view_inset_top
- 0.0f, // physical_view_inset_right
- 0.0f, // physical_view_inset_bottom
- 0.0f, // physical_view_inset_left
- 0.0f, // p_physical_system_gesture_inset_top
- 0.0f, // p_physical_system_gesture_inset_right
- 0.0f, // p_physical_system_gesture_inset_bottom
- 0.0f, // p_physical_system_gesture_inset_left
- });
- }
}
void PlatformView::OnChildViewConnected(scenic::ResourceId view_holder_id) {
@@ -388,9 +451,8 @@
pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase);
pointer_data.kind = GetKindFromPointerType(pointer.type);
pointer_data.device = pointer.pointer_id;
- // Pointer events are in logical pixels, so scale to physical.
- pointer_data.physical_x = pointer.x * view_pixel_ratio_;
- pointer_data.physical_y = pointer.y * view_pixel_ratio_;
+ pointer_data.physical_x = pointer.x * metrics_.scale;
+ pointer_data.physical_y = pointer.y * metrics_.scale;
// Buttons are single bit values starting with kMousePrimaryButton = 1.
pointer_data.buttons = static_cast<uint64_t>(pointer.buttons);
diff --git a/shell/platform/fuchsia/flutter/platform_view.h b/shell/platform/fuchsia/flutter/platform_view.h
index b6dd8e1..45e1e1f 100644
--- a/shell/platform/fuchsia/flutter/platform_view.h
+++ b/shell/platform/fuchsia/flutter/platform_view.h
@@ -5,6 +5,7 @@
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_PLATFORM_VIEW_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_PLATFORM_VIEW_H_
+#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
#include <lib/fit/function.h>
@@ -13,6 +14,7 @@
#include <set>
#include "flutter/fml/macros.h"
+#include "flutter/lib/ui/window/viewport_metrics.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/platform/fuchsia/flutter/accessibility_bridge.h"
#include "flutter_runner_product_configuration.h"
@@ -22,6 +24,9 @@
namespace flutter_runner {
+using OnMetricsUpdate = fit::function<void(const fuchsia::ui::gfx::Metrics&)>;
+using OnSizeChangeHint =
+ fit::function<void(float width_change_factor, float height_change_factor)>;
using OnEnableWireframe = fit::function<void(bool)>;
using OnCreateView = fit::function<void(int64_t, bool, bool)>;
using OnDestroyView = fit::function<void(int64_t)>;
@@ -48,15 +53,25 @@
fidl::InterfaceRequest<fuchsia::ui::scenic::SessionListener>
session_listener_request,
fit::closure on_session_listener_error_callback,
+ OnMetricsUpdate session_metrics_did_change_callback,
+ OnSizeChangeHint session_size_change_hint_callback,
OnEnableWireframe wireframe_enabled_callback,
OnCreateView on_create_view_callback,
OnDestroyView on_destroy_view_callback,
OnGetViewEmbedder on_get_view_embedder_callback,
zx_handle_t vsync_event_handle,
FlutterRunnerProductConfiguration product_config);
+ PlatformView(flutter::PlatformView::Delegate& delegate,
+ std::string debug_label,
+ flutter::TaskRunners task_runners,
+ fidl::InterfaceHandle<fuchsia::sys::ServiceProvider>
+ parent_environment_service_provider,
+ zx_handle_t vsync_event_handle);
~PlatformView();
+ void UpdateViewportMetrics(const fuchsia::ui::gfx::Metrics& metrics);
+
// |flutter::PlatformView|
// |flutter_runner::AccessibilityBridge::Delegate|
void SetSemanticsEnabled(bool enabled) override;
@@ -77,6 +92,8 @@
fidl::Binding<fuchsia::ui::scenic::SessionListener> session_listener_binding_;
fit::closure session_listener_error_callback_;
+ OnMetricsUpdate metrics_changed_callback_;
+ OnSizeChangeHint size_change_hint_callback_;
OnEnableWireframe wireframe_enabled_callback_;
OnCreateView on_create_view_callback_;
OnDestroyView on_destroy_view_callback_;
@@ -88,7 +105,8 @@
fuchsia::ui::input::ImeServicePtr text_sync_service_;
fuchsia::sys::ServiceProviderPtr parent_environment_service_provider_;
-
+ flutter::LogicalMetrics metrics_;
+ fuchsia::ui::gfx::Metrics scenic_metrics_;
// last_text_state_ is the last state of the text input as reported by the IME
// or initialized by Flutter. We set it to null if Flutter doesn't want any
// input, since then there is no text input state at all.
@@ -106,14 +124,16 @@
std::set<std::string /* channel */> unregistered_channels_;
zx_handle_t vsync_event_handle_ = 0;
- float view_width_ = 0.0f; // Width in logical pixels.
- float view_height_ = 0.0f; // Height in logical pixels.
- float view_pixel_ratio_ = 0.0f; // Logical / physical pixel ratio.
-
FlutterRunnerProductConfiguration product_config_;
void RegisterPlatformMessageHandlers();
+ void FlushViewportMetrics();
+
+ // Called when the view's properties have changed.
+ void OnPropertiesChanged(
+ const fuchsia::ui::gfx::ViewProperties& view_properties);
+
// |fuchsia::ui::input::InputMethodEditorClient|
void DidUpdateState(
fuchsia::ui::input::TextInputState state,
diff --git a/shell/platform/fuchsia/flutter/platform_view_unittest.cc b/shell/platform/fuchsia/flutter/platform_view_unittest.cc
index 7a1929d..89a5658 100644
--- a/shell/platform/fuchsia/flutter/platform_view_unittest.cc
+++ b/shell/platform/fuchsia/flutter/platform_view_unittest.cc
@@ -4,7 +4,7 @@
#include "flutter/shell/platform/fuchsia/flutter/platform_view.h"
-#include <fuchsia/ui/views/cpp/fidl.h>
+#include <gtest/gtest.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/default.h>
@@ -15,11 +15,11 @@
#include <memory>
#include <vector>
-#include "flutter/flow/embedded_views.h"
+#include "flutter/flow/scene_update_context.h"
#include "flutter/lib/ui/window/platform_message.h"
#include "flutter/lib/ui/window/window.h"
+#include "fuchsia/ui/views/cpp/fidl.h"
#include "gtest/gtest.h"
-
#include "task_runner_adapter.h"
namespace flutter_runner_test::flutter_runner_a11y_test {
@@ -41,33 +41,6 @@
FML_DISALLOW_COPY_AND_ASSIGN(PlatformViewTests);
};
-class MockExternalViewEmbedder : public flutter::ExternalViewEmbedder {
- public:
- MockExternalViewEmbedder() = default;
- ~MockExternalViewEmbedder() override = default;
-
- SkCanvas* GetRootCanvas() override { return nullptr; }
- std::vector<SkCanvas*> GetCurrentCanvases() override {
- return std::vector<SkCanvas*>();
- }
-
- void CancelFrame() override {}
- void BeginFrame(
- SkISize frame_size,
- GrDirectContext* context,
- double device_pixel_ratio,
- fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger) override {}
- void SubmitFrame(GrDirectContext* context,
- std::unique_ptr<flutter::SurfaceFrame> frame) override {
- return;
- }
-
- void PrerollCompositeEmbeddedView(
- int view_id,
- std::unique_ptr<flutter::EmbeddedViewParams> params) override {}
- SkCanvas* CompositeEmbeddedView(int view_id) override { return nullptr; }
-};
-
class MockPlatformViewDelegate : public flutter::PlatformView::Delegate {
public:
// |flutter::PlatformView::Delegate|
@@ -126,6 +99,30 @@
int32_t semantics_features_ = 0;
};
+class MockSurfaceProducer
+ : public flutter::SceneUpdateContext::SurfaceProducer {
+ public:
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ ProduceSurface(const SkISize& size,
+ const flutter::LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) override {
+ return nullptr;
+ }
+
+ bool HasRetainedNode(const flutter::LayerRasterCacheKey& key) const override {
+ return false;
+ }
+
+ scenic::EntityNode* GetRetainedNode(
+ const flutter::LayerRasterCacheKey& key) override {
+ return nullptr;
+ }
+
+ void SubmitSurface(
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ surface) override {}
+};
+
TEST_F(PlatformViewTests, ChangesAccessibilitySettings) {
sys::testing::ServiceDirectoryProvider services_provider(dispatcher());
@@ -150,6 +147,8 @@
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // on_session_listener_error_callback
+ nullptr, // session_metrics_did_change_callback
+ nullptr, // session_size_change_hint_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_destroy_view_callback,
@@ -204,6 +203,8 @@
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // on_session_listener_error_callback
+ nullptr, // session_metrics_did_change_callback
+ nullptr, // session_size_change_hint_callback
EnableWireframeCallback, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_destroy_view_callback,
@@ -269,6 +270,8 @@
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // on_session_listener_error_callback
+ nullptr, // session_metrics_did_change_callback
+ nullptr, // session_size_change_hint_callback
nullptr, // on_enable_wireframe_callback,
CreateViewCallback, // on_create_view_callback,
nullptr, // on_destroy_view_callback,
@@ -336,6 +339,8 @@
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // on_session_listener_error_callback
+ nullptr, // session_metrics_did_change_callback
+ nullptr, // session_size_change_hint_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
DestroyViewCallback, // on_destroy_view_callback,
@@ -390,8 +395,11 @@
);
// Test get view embedder callback function.
- MockExternalViewEmbedder view_embedder;
- auto GetViewEmbedderCallback = [&view_embedder]() { return &view_embedder; };
+ MockSurfaceProducer surfaceProducer;
+ flutter::SceneUpdateContext scene_update_context(nullptr, &surfaceProducer);
+ flutter::ExternalViewEmbedder* view_embedder =
+ reinterpret_cast<flutter::ExternalViewEmbedder*>(&scene_update_context);
+ auto GetViewEmbedderCallback = [view_embedder]() { return view_embedder; };
auto platform_view = flutter_runner::PlatformView(
delegate, // delegate
@@ -402,6 +410,8 @@
nullptr, // parent_environment_service_provider_handle
nullptr, // session_listener_request
nullptr, // on_session_listener_error_callback
+ nullptr, // session_metrics_did_change_callback
+ nullptr, // session_size_change_hint_callback
nullptr, // on_enable_wireframe_callback,
nullptr, // on_create_view_callback,
nullptr, // on_destroy_view_callback,
@@ -416,7 +426,7 @@
RunLoopUntilIdle();
- EXPECT_EQ(&view_embedder, delegate.get_view_embedder());
+ EXPECT_EQ(view_embedder, delegate.get_view_embedder());
}
} // namespace flutter_runner_test::flutter_runner_a11y_test
diff --git a/shell/platform/fuchsia/flutter/session_connection.cc b/shell/platform/fuchsia/flutter/session_connection.cc
index c87368a..133dc9a 100644
--- a/shell/platform/fuchsia/flutter/session_connection.cc
+++ b/shell/platform/fuchsia/flutter/session_connection.cc
@@ -5,8 +5,8 @@
#include "session_connection.h"
#include "flutter/fml/make_copyable.h"
-#include "flutter/fml/trace_event.h"
-
+#include "lib/fidl/cpp/optional.h"
+#include "lib/ui/scenic/cpp/commands.h"
#include "vsync_recorder.h"
#include "vsync_waiter.h"
@@ -14,11 +14,23 @@
SessionConnection::SessionConnection(
std::string debug_label,
+ fuchsia::ui::views::ViewToken view_token,
+ scenic::ViewRefPair view_ref_pair,
fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
fml::closure session_error_callback,
on_frame_presented_event on_frame_presented_callback,
zx_handle_t vsync_event_handle)
- : session_wrapper_(session.Bind(), nullptr),
+ : debug_label_(std::move(debug_label)),
+ session_wrapper_(session.Bind(), nullptr),
+ root_view_(&session_wrapper_,
+ std::move(view_token),
+ std::move(view_ref_pair.control_ref),
+ std::move(view_ref_pair.view_ref),
+ debug_label),
+ root_node_(&session_wrapper_),
+ surface_producer_(
+ std::make_unique<VulkanSurfaceProducer>(&session_wrapper_)),
+ scene_update_context_(&session_wrapper_, surface_producer_.get()),
on_frame_presented_callback_(std::move(on_frame_presented_callback)),
vsync_event_handle_(vsync_event_handle) {
session_wrapper_.set_error_handler(
@@ -51,7 +63,11 @@
} // callback
);
- session_wrapper_.SetDebugName(debug_label);
+ session_wrapper_.SetDebugName(debug_label_);
+
+ root_view_.AddChild(root_node_);
+ root_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask |
+ fuchsia::ui::gfx::kSizeChangeHintEventMask);
// Get information to finish initialization and only then allow Present()s.
session_wrapper_.RequestPresentationTimes(
@@ -75,7 +91,8 @@
SessionConnection::~SessionConnection() = default;
-void SessionConnection::Present() {
+void SessionConnection::Present(
+ flutter::CompositorContext::ScopedFrame* frame) {
TRACE_EVENT0("gfx", "SessionConnection::Present");
TRACE_FLOW_BEGIN("gfx", "SessionConnection::PresentSession",
@@ -97,6 +114,21 @@
present_session_pending_ = true;
ToggleSignal(vsync_event_handle_, false);
}
+
+ if (frame) {
+ // Execute paint tasks and signal fences.
+ auto surfaces_to_submit = scene_update_context_.ExecutePaintTasks(*frame);
+
+ // Tell the surface producer that a present has occurred so it can perform
+ // book-keeping on buffer caches.
+ surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit));
+ }
+}
+
+void SessionConnection::OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor) {
+ surface_producer_->OnSessionSizeChangeHint(width_change_factor,
+ height_change_factor);
}
fml::TimePoint SessionConnection::CalculateNextLatchPoint(
@@ -128,6 +160,17 @@
return minimum_latch_point_to_target;
}
+void SessionConnection::set_enable_wireframe(bool enable) {
+ session_wrapper_.Enqueue(
+ scenic::NewSetEnableDebugViewBoundsCmd(root_view_.id(), enable));
+}
+
+void SessionConnection::EnqueueClearOps() {
+ // We are going to be sending down a fresh node hierarchy every frame. So just
+ // enqueue a detach op on the imported root node.
+ session_wrapper_.Enqueue(scenic::NewDetachChildrenCmd(root_node_.id()));
+}
+
void SessionConnection::PresentSession() {
TRACE_EVENT0("gfx", "SessionConnection::PresentSession");
@@ -189,6 +232,10 @@
VsyncRecorder::GetInstance().UpdateNextPresentationInfo(
std::move(info));
});
+
+ // Prepare for the next frame. These ops won't be processed till the next
+ // present.
+ EnqueueClearOps();
}
void SessionConnection::ToggleSignal(zx_handle_t handle, bool set) {
diff --git a/shell/platform/fuchsia/flutter/session_connection.h b/shell/platform/fuchsia/flutter/session_connection.h
index 7630d15..dcd55f1 100644
--- a/shell/platform/fuchsia/flutter/session_connection.h
+++ b/shell/platform/fuchsia/flutter/session_connection.h
@@ -5,14 +5,22 @@
#ifndef FLUTTER_SHELL_PLATFORM_FUCHSIA_SESSION_CONNECTION_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_SESSION_CONNECTION_H_
-#include <fuchsia/scenic/scheduling/cpp/fidl.h>
+#include <fuchsia/ui/gfx/cpp/fidl.h>
#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include <fuchsia/ui/views/cpp/fidl.h>
#include <lib/fidl/cpp/interface_handle.h>
+#include <lib/fidl/cpp/optional.h>
+#include <lib/fit/function.h>
+#include <lib/ui/scenic/cpp/resources.h>
#include <lib/ui/scenic/cpp/session.h>
+#include <lib/ui/scenic/cpp/view_ref_pair.h>
+#include "flutter/flow/compositor_context.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/closure.h"
#include "flutter/fml/macros.h"
+#include "flutter/fml/trace_event.h"
+#include "vulkan_surface_producer.h"
namespace flutter_runner {
@@ -21,9 +29,11 @@
// The component residing on the raster thread that is responsible for
// maintaining the Scenic session connection and presenting node updates.
-class SessionConnection final : public flutter::SessionWrapper {
+class SessionConnection final {
public:
SessionConnection(std::string debug_label,
+ fuchsia::ui::views::ViewToken view_token,
+ scenic::ViewRefPair view_ref_pair,
fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session,
fml::closure session_error_callback,
on_frame_presented_event on_frame_presented_callback,
@@ -31,8 +41,36 @@
~SessionConnection();
- scenic::Session* get() override { return &session_wrapper_; }
- void Present() override;
+ bool has_metrics() const { return scene_update_context_.has_metrics(); }
+
+ const fuchsia::ui::gfx::MetricsPtr& metrics() const {
+ return scene_update_context_.metrics();
+ }
+
+ void set_metrics(const fuchsia::ui::gfx::Metrics& metrics) {
+ fuchsia::ui::gfx::Metrics metrics_copy;
+ metrics.Clone(&metrics_copy);
+ scene_update_context_.set_metrics(
+ fidl::MakeOptional(std::move(metrics_copy)));
+ }
+
+ void set_enable_wireframe(bool enable);
+
+ flutter::SceneUpdateContext& scene_update_context() {
+ return scene_update_context_;
+ }
+
+ scenic::ContainerNode& root_node() { return root_node_; }
+ scenic::View* root_view() { return &root_view_; }
+
+ void Present(flutter::CompositorContext::ScopedFrame* frame);
+
+ void OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor);
+
+ VulkanSurfaceProducer* vulkan_surface_producer() {
+ return surface_producer_.get();
+ }
static fml::TimePoint CalculateNextLatchPoint(
fml::TimePoint present_requested_time,
@@ -44,8 +82,14 @@
future_presentation_infos);
private:
+ const std::string debug_label_;
scenic::Session session_wrapper_;
+ scenic::View root_view_;
+ scenic::EntityNode root_node_;
+
+ std::unique_ptr<VulkanSurfaceProducer> surface_producer_;
+ flutter::SceneUpdateContext scene_update_context_;
on_frame_presented_event on_frame_presented_callback_;
zx_handle_t vsync_event_handle_;
@@ -78,6 +122,8 @@
bool present_session_pending_ = false;
+ void EnqueueClearOps();
+
void PresentSession();
static void ToggleSignal(zx_handle_t handle, bool raise);
diff --git a/shell/platform/fuchsia/flutter/tests/session_connection_unittests.cc b/shell/platform/fuchsia/flutter/tests/session_connection_unittests.cc
index 5a54632..87efa11 100644
--- a/shell/platform/fuchsia/flutter/tests/session_connection_unittests.cc
+++ b/shell/platform/fuchsia/flutter/tests/session_connection_unittests.cc
@@ -2,16 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <fuchsia/scenic/scheduling/cpp/fidl.h>
-#include <fuchsia/ui/policy/cpp/fidl.h>
-#include <fuchsia/ui/scenic/cpp/fidl.h>
+#include "gtest/gtest.h"
+
#include <lib/async-loop/default.h>
#include <lib/sys/cpp/component_context.h>
+#include <lib/ui/scenic/cpp/view_token_pair.h>
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <fuchsia/ui/policy/cpp/fidl.h>
#include "flutter/shell/platform/fuchsia/flutter/logging.h"
#include "flutter/shell/platform/fuchsia/flutter/runner.h"
#include "flutter/shell/platform/fuchsia/flutter/session_connection.h"
-#include "gtest/gtest.h"
using namespace flutter_runner;
@@ -28,8 +30,12 @@
loop_.StartThread("SessionConnectionTestThread", &fidl_thread_));
auto session_listener_request = session_listener_.NewRequest();
+ auto [view_token, view_holder_token] = scenic::ViewTokenPair::New();
+ view_token_ = std::move(view_token);
scenic_->CreateSession(session_.NewRequest(), session_listener_.Bind());
+ presenter_->PresentOrReplaceView(std::move(view_holder_token), nullptr);
+
FML_CHECK(zx::event::create(0, &vsync_event_) == ZX_OK);
// Ensure Scenic has had time to wake up before the test logic begins.
@@ -54,6 +60,7 @@
fidl::InterfaceHandle<fuchsia::ui::scenic::Session> session_;
fidl::InterfaceHandle<fuchsia::ui::scenic::SessionListener> session_listener_;
+ fuchsia::ui::views::ViewToken view_token_;
zx::event vsync_event_;
thrd_t fidl_thread_;
};
@@ -69,11 +76,12 @@
};
flutter_runner::SessionConnection session_connection(
- "debug label", std::move(session_), on_session_error_callback,
+ "debug label", std::move(view_token_), scenic::ViewRefPair::New(),
+ std::move(session_), on_session_error_callback,
on_frame_presented_callback, vsync_event_.get());
for (int i = 0; i < 200; ++i) {
- session_connection.Present();
+ session_connection.Present(nullptr);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
@@ -91,11 +99,12 @@
};
flutter_runner::SessionConnection session_connection(
- "debug label", std::move(session_), on_session_error_callback,
+ "debug label", std::move(view_token_), scenic::ViewRefPair::New(),
+ std::move(session_), on_session_error_callback,
on_frame_presented_callback, vsync_event_.get());
for (int i = 0; i < 200; ++i) {
- session_connection.Present();
+ session_connection.Present(nullptr);
if (i % 10 == 9) {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
diff --git a/shell/platform/fuchsia/flutter/vulkan_surface.h b/shell/platform/fuchsia/flutter/vulkan_surface.h
index bff2713..e6b7eb4 100644
--- a/shell/platform/fuchsia/flutter/vulkan_surface.h
+++ b/shell/platform/fuchsia/flutter/vulkan_surface.h
@@ -5,7 +5,6 @@
#pragma once
#include <lib/async/cpp/wait.h>
-#include <lib/ui/scenic/cpp/resources.h>
#include <lib/zx/event.h>
#include <lib/zx/vmo.h>
@@ -13,46 +12,17 @@
#include <memory>
#include "flutter/flow/raster_cache_key.h"
+#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
#include "flutter/vulkan/vulkan_command_buffer.h"
#include "flutter/vulkan/vulkan_handle.h"
#include "flutter/vulkan/vulkan_proc_table.h"
#include "flutter/vulkan/vulkan_provider.h"
+#include "lib/ui/scenic/cpp/resources.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace flutter_runner {
-class SurfaceProducerSurface {
- public:
- virtual ~SurfaceProducerSurface() = default;
-
- virtual size_t AdvanceAndGetAge() = 0;
-
- virtual bool FlushSessionAcquireAndReleaseEvents() = 0;
-
- virtual bool IsValid() const = 0;
-
- virtual SkISize GetSize() const = 0;
-
- virtual void SignalWritesFinished(
- const std::function<void(void)>& on_writes_committed) = 0;
-
- virtual scenic::Image* GetImage() = 0;
-
- virtual sk_sp<SkSurface> GetSkiaSurface() const = 0;
-};
-
-class SurfaceProducer {
- public:
- virtual ~SurfaceProducer() = default;
-
- virtual std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
- const SkISize& size) = 0;
-
- virtual void SubmitSurface(
- std::unique_ptr<SurfaceProducerSurface> surface) = 0;
-};
-
// A |VkImage| and its relevant metadata.
struct VulkanImage {
VulkanImage() = default;
@@ -74,7 +44,8 @@
const SkISize& size,
VulkanImage* out_vulkan_image);
-class VulkanSurface final : public SurfaceProducerSurface {
+class VulkanSurface final
+ : public flutter::SceneUpdateContext::SurfaceProducerSurface {
public:
VulkanSurface(vulkan::VulkanProvider& vulkan_provider,
sk_sp<GrDirectContext> context,
@@ -83,16 +54,16 @@
~VulkanSurface() override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
size_t AdvanceAndGetAge() override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
bool FlushSessionAcquireAndReleaseEvents() override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
bool IsValid() const override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
SkISize GetSize() const override;
// Note: It is safe for the caller to collect the surface in the
@@ -100,10 +71,10 @@
void SignalWritesFinished(
const std::function<void(void)>& on_writes_committed) override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
scenic::Image* GetImage() override;
- // |SurfaceProducerSurface|
+ // |flutter::SceneUpdateContext::SurfaceProducerSurface|
sk_sp<SkSurface> GetSkiaSurface() const override;
const vulkan::VulkanHandle<VkImage>& GetVkImage() {
@@ -148,6 +119,41 @@
// if the swap was not successful.
bool BindToImage(sk_sp<GrDirectContext> context, VulkanImage vulkan_image);
+ // Flutter may retain a |VulkanSurface| for a |flutter::Layer| subtree to
+ // improve the performance. The |retained_key_| identifies which layer subtree
+ // this |VulkanSurface| is retained for. The key has two parts. One is the
+ // pointer to the root of that layer subtree: |retained_key_.id()|. Another is
+ // the transformation matrix: |retained_key_.matrix()|. We need the matrix
+ // part because a different matrix would invalidate the pixels (raster cache)
+ // in this |VulkanSurface|.
+ const flutter::LayerRasterCacheKey& GetRetainedKey() const {
+ return retained_key_;
+ }
+
+ // For better safety in retained rendering, Flutter uses a retained
+ // |EntityNode| associated with the retained surface instead of using the
+ // retained surface directly. Hence Flutter can't modify the surface during
+ // retained rendering. However, the node itself is modifiable to be able
+ // to adjust its position.
+ scenic::EntityNode* GetRetainedNode() {
+ used_in_retained_rendering_ = true;
+ return retained_node_.get();
+ }
+
+ // Check whether the retained surface (and its associated |EntityNode|) is
+ // used in the current frame or not. If unused, the |VulkanSurfacePool| will
+ // try to recycle the surface. This flag is reset after each frame.
+ bool IsUsedInRetainedRendering() const { return used_in_retained_rendering_; }
+ void ResetIsUsedInRetainedRendering() { used_in_retained_rendering_ = false; }
+
+ // Let this surface own the retained EntityNode associated with it (see
+ // |GetRetainedNode|), and set the retained key (see |GetRetainedKey|).
+ void SetRetainedInfo(const flutter::LayerRasterCacheKey& key,
+ std::unique_ptr<scenic::EntityNode> node) {
+ retained_key_ = key;
+ retained_node_ = std::move(node);
+ }
+
private:
static constexpr int kSizeHistorySize = 4;
@@ -196,6 +202,11 @@
size_t age_ = 0;
bool valid_ = false;
+ flutter::LayerRasterCacheKey retained_key_ = {0, SkMatrix::Scale(1, 1)};
+ std::unique_ptr<scenic::EntityNode> retained_node_ = nullptr;
+
+ std::atomic<bool> used_in_retained_rendering_ = {false};
+
FML_DISALLOW_COPY_AND_ASSIGN(VulkanSurface);
};
diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc b/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc
index 1b85a95..cb40dd2 100644
--- a/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc
+++ b/shell/platform/fuchsia/flutter/vulkan_surface_pool.cc
@@ -112,7 +112,8 @@
}
void VulkanSurfacePool::SubmitSurface(
- std::unique_ptr<SurfaceProducerSurface> p_surface) {
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ p_surface) {
TRACE_EVENT0("flutter", "VulkanSurfacePool::SubmitSurface");
// This cast is safe because |VulkanSurface| is the only implementation of
@@ -125,14 +126,43 @@
return;
}
- uintptr_t surface_key = reinterpret_cast<uintptr_t>(vulkan_surface.get());
- auto insert_iterator = pending_surfaces_.insert(std::make_pair(
- surface_key, // key
- std::move(vulkan_surface) // value
- ));
- if (insert_iterator.second) {
- insert_iterator.first->second->SignalWritesFinished(std::bind(
- &VulkanSurfacePool::RecyclePendingSurface, this, surface_key));
+ const flutter::LayerRasterCacheKey& retained_key =
+ vulkan_surface->GetRetainedKey();
+
+ // TODO(https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=44141): Re-enable
+ // retained surfaces after we find out why textures are being prematurely
+ // recycled.
+ const bool kUseRetainedSurfaces = false;
+ if (kUseRetainedSurfaces && retained_key.id() != 0) {
+ // Add the surface to |retained_surfaces_| if its retained key has a valid
+ // layer id (|retained_key.id()|).
+ //
+ // We have to add the entry to |retained_surfaces_| map early when it's
+ // still pending (|is_pending| = true). Otherwise (if we add the surface
+ // later when |SignalRetainedReady| is called), Flutter would fail to find
+ // the retained node before the painting is done (which could take multiple
+ // frames). Flutter would then create a new |VulkanSurface| for the layer
+ // upon the failed lookup. The new |VulkanSurface| would invalidate this
+ // surface, and before the new |VulkanSurface| is done painting, another
+ // newer |VulkanSurface| is likely to be created to replace the new
+ // |VulkanSurface|. That would make the retained rendering much less useful
+ // in improving the performance.
+ auto insert_iterator = retained_surfaces_.insert(std::make_pair(
+ retained_key, RetainedSurface({true, std::move(vulkan_surface)})));
+ if (insert_iterator.second) {
+ insert_iterator.first->second.vk_surface->SignalWritesFinished(std::bind(
+ &VulkanSurfacePool::SignalRetainedReady, this, retained_key));
+ }
+ } else {
+ uintptr_t surface_key = reinterpret_cast<uintptr_t>(vulkan_surface.get());
+ auto insert_iterator = pending_surfaces_.insert(std::make_pair(
+ surface_key, // key
+ std::move(vulkan_surface) // value
+ ));
+ if (insert_iterator.second) {
+ insert_iterator.first->second->SignalWritesFinished(std::bind(
+ &VulkanSurfacePool::RecyclePendingSurface, this, surface_key));
+ }
}
}
@@ -183,6 +213,25 @@
TraceStats();
}
+void VulkanSurfacePool::RecycleRetainedSurface(
+ const flutter::LayerRasterCacheKey& key) {
+ auto it = retained_surfaces_.find(key);
+ if (it == retained_surfaces_.end()) {
+ return;
+ }
+
+ // The surface should not be pending.
+ FML_DCHECK(!it->second.is_pending);
+
+ auto surface_to_recycle = std::move(it->second.vk_surface);
+ retained_surfaces_.erase(it);
+ RecycleSurface(std::move(surface_to_recycle));
+}
+
+void VulkanSurfacePool::SignalRetainedReady(flutter::LayerRasterCacheKey key) {
+ retained_surfaces_[key].is_pending = false;
+}
+
void VulkanSurfacePool::AgeAndCollectOldBuffers() {
TRACE_EVENT0("flutter", "VulkanSurfacePool::AgeAndCollectOldBuffers");
@@ -219,6 +268,25 @@
}
}
+ // Recycle retained surfaces that are not used and not pending in this frame.
+ //
+ // It's safe to recycle any retained surfaces that are not pending no matter
+ // whether they're used or not. Hence if there's memory pressure, feel free to
+ // recycle all retained surfaces that are not pending.
+ std::vector<flutter::LayerRasterCacheKey> recycle_keys;
+ for (auto& [key, retained_surface] : retained_surfaces_) {
+ if (retained_surface.is_pending ||
+ retained_surface.vk_surface->IsUsedInRetainedRendering()) {
+ // Reset the flag for the next frame
+ retained_surface.vk_surface->ResetIsUsedInRetainedRendering();
+ } else {
+ recycle_keys.push_back(key);
+ }
+ }
+ for (auto& key : recycle_keys) {
+ RecycleRetainedSurface(key);
+ }
+
TraceStats();
}
@@ -252,9 +320,15 @@
void VulkanSurfacePool::TraceStats() {
// Resources held in cached buffers.
size_t cached_surfaces_bytes = 0;
+ size_t retained_surfaces_bytes = 0;
+
for (const auto& surface : available_surfaces_) {
cached_surfaces_bytes += surface->GetAllocationSize();
}
+ for (const auto& retained_entry : retained_surfaces_) {
+ retained_surfaces_bytes +=
+ retained_entry.second.vk_surface->GetAllocationSize();
+ }
// Resources held by Skia.
int skia_resources = 0;
@@ -268,13 +342,13 @@
"Created", trace_surfaces_created_, //
"Reused", trace_surfaces_reused_, //
"PendingInCompositor", pending_surfaces_.size(), //
- "Retained", 0, //
+ "Retained", retained_surfaces_.size(), //
"SkiaCacheResources", skia_resources //
);
TRACE_COUNTER("flutter", "SurfacePoolBytes", 0u, //
"CachedBytes", cached_surfaces_bytes, //
- "RetainedBytes", 0, //
+ "RetainedBytes", retained_surfaces_bytes, //
"SkiaCacheBytes", skia_bytes, //
"SkiaCachePurgeable", skia_cache_purgeable //
);
diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_pool.h b/shell/platform/fuchsia/flutter/vulkan_surface_pool.h
index 0667db8..302be9b 100644
--- a/shell/platform/fuchsia/flutter/vulkan_surface_pool.h
+++ b/shell/platform/fuchsia/flutter/vulkan_surface_pool.h
@@ -28,7 +28,9 @@
std::unique_ptr<VulkanSurface> AcquireSurface(const SkISize& size);
- void SubmitSurface(std::unique_ptr<SurfaceProducerSurface> surface);
+ void SubmitSurface(
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ surface);
void AgeAndCollectOldBuffers();
@@ -36,7 +38,26 @@
// small as they can be.
void ShrinkToFit();
+ // For |VulkanSurfaceProducer::HasRetainedNode|.
+ bool HasRetainedNode(const flutter::LayerRasterCacheKey& key) const {
+ return retained_surfaces_.find(key) != retained_surfaces_.end();
+ }
+ // For |VulkanSurfaceProducer::GetRetainedNode|.
+ scenic::EntityNode* GetRetainedNode(const flutter::LayerRasterCacheKey& key) {
+ FML_DCHECK(HasRetainedNode(key));
+ return retained_surfaces_[key].vk_surface->GetRetainedNode();
+ }
+
private:
+ // Struct for retained_surfaces_ map.
+ struct RetainedSurface {
+ // If |is_pending| is true, the |vk_surface| is still under painting
+ // (similar to those in |pending_surfaces_|) so we can't recycle the
+ // |vk_surface| yet.
+ bool is_pending;
+ std::unique_ptr<VulkanSurface> vk_surface;
+ };
+
vulkan::VulkanProvider& vulkan_provider_;
sk_sp<GrDirectContext> context_;
scenic::Session* scenic_session_;
@@ -44,6 +65,9 @@
std::unordered_map<uintptr_t, std::unique_ptr<VulkanSurface>>
pending_surfaces_;
+ // Retained surfaces keyed by the layer that created and used the surface.
+ flutter::LayerRasterCacheKey::Map<RetainedSurface> retained_surfaces_;
+
size_t trace_surfaces_created_ = 0;
size_t trace_surfaces_reused_ = 0;
@@ -55,6 +79,13 @@
void RecyclePendingSurface(uintptr_t surface_key);
+ // Clear the |is_pending| flag of the retained surface.
+ void SignalRetainedReady(flutter::LayerRasterCacheKey key);
+
+ // Remove the corresponding surface from |retained_surfaces| and recycle it.
+ // The surface must not be pending.
+ void RecycleRetainedSurface(const flutter::LayerRasterCacheKey& key);
+
void TraceStats();
FML_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool);
diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_producer.cc b/shell/platform/fuchsia/flutter/vulkan_surface_producer.cc
index 36eeadd..1e0d03d 100644
--- a/shell/platform/fuchsia/flutter/vulkan_surface_producer.cc
+++ b/shell/platform/fuchsia/flutter/vulkan_surface_producer.cc
@@ -155,7 +155,9 @@
}
void VulkanSurfaceProducer::OnSurfacesPresented(
- std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces) {
+ std::vector<
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
+ surfaces) {
TRACE_EVENT0("flutter", "VulkanSurfaceProducer::OnSurfacesPresented");
// Do a single flush for all canvases derived from the context.
@@ -195,12 +197,11 @@
}
bool VulkanSurfaceProducer::TransitionSurfacesToExternal(
- const std::vector<std::unique_ptr<SurfaceProducerSurface>>& surfaces) {
+ const std::vector<
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>&
+ surfaces) {
for (auto& surface : surfaces) {
auto vk_surface = static_cast<VulkanSurface*>(surface.get());
- if (!vk_surface) {
- continue;
- }
vulkan::VulkanCommandBuffer* command_buffer =
vk_surface->GetCommandBuffer(logical_device_->GetCommandPool());
@@ -258,15 +259,21 @@
return true;
}
-std::unique_ptr<SurfaceProducerSurface> VulkanSurfaceProducer::ProduceSurface(
- const SkISize& size) {
+std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+VulkanSurfaceProducer::ProduceSurface(
+ const SkISize& size,
+ const flutter::LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) {
FML_DCHECK(valid_);
last_produce_time_ = async::Now(async_get_default_dispatcher());
- return surface_pool_->AcquireSurface(size);
+ auto surface = surface_pool_->AcquireSurface(size);
+ surface->SetRetainedInfo(layer_key, std::move(entity_node));
+ return surface;
}
void VulkanSurfaceProducer::SubmitSurface(
- std::unique_ptr<SurfaceProducerSurface> surface) {
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ surface) {
FML_DCHECK(valid_ && surface != nullptr);
surface_pool_->SubmitSurface(std::move(surface));
}
diff --git a/shell/platform/fuchsia/flutter/vulkan_surface_producer.h b/shell/platform/fuchsia/flutter/vulkan_surface_producer.h
index 2caaf64..403ecd1 100644
--- a/shell/platform/fuchsia/flutter/vulkan_surface_producer.h
+++ b/shell/platform/fuchsia/flutter/vulkan_surface_producer.h
@@ -8,8 +8,8 @@
#include <lib/async/default.h>
#include <lib/syslog/global.h>
+#include "flutter/flow/scene_update_context.h"
#include "flutter/fml/macros.h"
-#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/vulkan/vulkan_application.h"
#include "flutter/vulkan/vulkan_device.h"
#include "flutter/vulkan/vulkan_proc_table.h"
@@ -22,8 +22,9 @@
namespace flutter_runner {
-class VulkanSurfaceProducer final : public SurfaceProducer,
- public vulkan::VulkanProvider {
+class VulkanSurfaceProducer final
+ : public flutter::SceneUpdateContext::SurfaceProducer,
+ public vulkan::VulkanProvider {
public:
VulkanSurfaceProducer(scenic::Session* scenic_session);
@@ -31,15 +32,39 @@
bool IsValid() const { return valid_; }
- // |SurfaceProducer|
- std::unique_ptr<SurfaceProducerSurface> ProduceSurface(
- const SkISize& size) override;
+ // |flutter::SceneUpdateContext::SurfaceProducer|
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ ProduceSurface(const SkISize& size,
+ const flutter::LayerRasterCacheKey& layer_key,
+ std::unique_ptr<scenic::EntityNode> entity_node) override;
- // |SurfaceProducer|
- void SubmitSurface(std::unique_ptr<SurfaceProducerSurface> surface) override;
+ // |flutter::SceneUpdateContext::SurfaceProducer|
+ void SubmitSurface(
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>
+ surface) override;
+
+ // |flutter::SceneUpdateContext::HasRetainedNode|
+ bool HasRetainedNode(const flutter::LayerRasterCacheKey& key) const override {
+ return surface_pool_->HasRetainedNode(key);
+ }
+
+ // |flutter::SceneUpdateContext::GetRetainedNode|
+ scenic::EntityNode* GetRetainedNode(
+ const flutter::LayerRasterCacheKey& key) override {
+ return surface_pool_->GetRetainedNode(key);
+ }
void OnSurfacesPresented(
- std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces);
+ std::vector<
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
+ surfaces);
+
+ void OnSessionSizeChangeHint(float width_change_factor,
+ float height_change_factor) {
+ FX_LOGF(INFO, LOG_TAG,
+ "VulkanSurfaceProducer:OnSessionSizeChangeHint %f, %f",
+ width_change_factor, height_change_factor);
+ }
GrDirectContext* gr_context() { return context_.get(); }
@@ -51,7 +76,9 @@
}
bool TransitionSurfacesToExternal(
- const std::vector<std::unique_ptr<SurfaceProducerSurface>>& surfaces);
+ const std::vector<
+ std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>&
+ surfaces);
// Note: the order here is very important. The proctable must be destroyed
// last because it contains the function pointers for VkDestroyDevice and
diff --git a/testing/dart/window_hooks_integration_test.dart b/testing/dart/window_hooks_integration_test.dart
index 21eda23..186ca92 100644
--- a/testing/dart/window_hooks_integration_test.dart
+++ b/testing/dart/window_hooks_integration_test.dart
@@ -46,6 +46,7 @@
double? oldDPR;
Size? oldSize;
+ double? oldDepth;
WindowPadding? oldPadding;
WindowPadding? oldInsets;
WindowPadding? oldSystemGestureInsets;
@@ -53,6 +54,7 @@
void setUp() {
oldDPR = window.devicePixelRatio;
oldSize = window.physicalSize;
+ oldDepth = window.physicalDepth;
oldPadding = window.viewPadding;
oldInsets = window.viewInsets;
oldSystemGestureInsets = window.systemGestureInsets;
@@ -74,6 +76,7 @@
oldDPR!, // DPR
oldSize!.width, // width
oldSize!.height, // height
+ oldDepth!, // depth
oldPadding!.top, // padding top
oldPadding!.right, // padding right
oldPadding!.bottom, // padding bottom
@@ -158,6 +161,7 @@
0.1234, // DPR
0.0, // width
0.0, // height
+ 0.0, // depth
0.0, // padding top
0.0, // padding right
0.0, // padding bottom
@@ -374,6 +378,7 @@
1.0, // DPR
800.0, // width
600.0, // height
+ 100.0, // depth
50.0, // padding top
0.0, // padding right
40.0, // padding bottom
@@ -391,12 +396,14 @@
expectEquals(window.viewInsets.bottom, 0.0);
expectEquals(window.viewPadding.bottom, 40.0);
expectEquals(window.padding.bottom, 40.0);
+ expectEquals(window.physicalDepth, 100.0);
expectEquals(window.systemGestureInsets.bottom, 0.0);
_updateWindowMetrics(
1.0, // DPR
800.0, // width
600.0, // height
+ 100.0, // depth
50.0, // padding top
0.0, // padding right
40.0, // padding bottom
@@ -414,6 +421,7 @@
expectEquals(window.viewInsets.bottom, 400.0);
expectEquals(window.viewPadding.bottom, 40.0);
expectEquals(window.padding.bottom, 0.0);
+ expectEquals(window.physicalDepth, 100.0);
expectEquals(window.systemGestureInsets.bottom, 44.0);
});
}