From 21f6aa5270289a7dc07da3dfab423f5a42e70330 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Fri, 18 Nov 2016 12:54:54 -0800 Subject: [PATCH] Composite child views in proper paint order (#3243) We push a bit up the tree during preroll to learn whether there system composited layers below each layer. During update scene, we squash down to paint tasks, which we execute after publishing the new scene. --- content_handler/rasterizer.cc | 48 ++----- flow/BUILD.gn | 7 +- flow/compositor_context.cc | 6 +- flow/compositor_context.h | 4 +- flow/layers/child_scene_layer.cc | 71 ++++------ flow/layers/child_scene_layer.h | 2 +- flow/layers/clip_path_layer.cc | 18 +++ flow/layers/clip_path_layer.h | 5 + flow/layers/clip_rect_layer.cc | 18 +++ flow/layers/clip_rect_layer.h | 5 + flow/layers/clip_rrect_layer.cc | 18 +++ flow/layers/clip_rrect_layer.h | 5 + flow/layers/container_layer.cc | 41 +++++- flow/layers/container_layer.h | 15 ++- flow/layers/layer.cc | 14 +- flow/layers/layer.h | 18 +-- flow/layers/layer_tree.cc | 12 +- flow/layers/layer_tree.h | 2 +- flow/layers/opacity_layer.cc | 21 +++ flow/layers/opacity_layer.h | 5 + flow/layers/picture_layer.cc | 5 +- flow/layers/transform_layer.cc | 19 +++ flow/layers/transform_layer.h | 6 + flow/scene_update_context.cc | 127 ++++++++++++++++++ flow/scene_update_context.h | 89 ++++++++++++ shell/common/diagnostic/diagnostic_server.cc | 2 +- .../common/platform_view_service_protocol.cc | 7 +- shell/gpu/gpu_rasterizer.cc | 4 +- .../platform/android/platform_view_android.cc | 8 +- 29 files changed, 473 insertions(+), 129 deletions(-) create mode 100644 flow/scene_update_context.cc create mode 100644 flow/scene_update_context.h diff --git a/content_handler/rasterizer.cc b/content_handler/rasterizer.cc index f98ece99b5a..17dc6f75112 100644 --- a/content_handler/rasterizer.cc +++ b/content_handler/rasterizer.cc @@ -12,11 +12,6 @@ namespace flutter_runner { -namespace { -constexpr uint32_t kContentImageResourceId = 1; -constexpr uint32_t kRootNodeId = mozart::kSceneRootNodeId; -} // namespace - Rasterizer::Rasterizer() {} Rasterizer::~Rasterizer() {} @@ -35,10 +30,14 @@ void Rasterizer::Draw(std::unique_ptr layer_tree, } const SkISize& frame_size = layer_tree->frame_size(); + auto update = mozart::SceneUpdate::New(); + // TODO(abarth): Support incremental updates. + update->clear_resources = true; + update->clear_nodes = true; if (frame_size.isEmpty()) { - update->nodes.insert(kRootNodeId, mozart::Node::New()); + update->nodes.insert(mozart::kSceneRootNodeId, mozart::Node::New()); // Publish the updated scene contents. // TODO(jeffbrown): We should set the metadata's presentation_time here too. scene_->Update(std::move(update)); @@ -49,39 +48,15 @@ void Rasterizer::Draw(std::unique_ptr layer_tree, return; } - // Get a surface to draw the contents. - mozart::ImagePtr image; - sk_sp surface = - mozart::MakeSkSurface(frame_size, buffer_producer_.get(), &image); - - FTL_CHECK(surface); - flow::CompositorContext::ScopedFrame frame = - compositor_context_.AcquireFrame(nullptr, *surface->getCanvas()); + compositor_context_.AcquireFrame(nullptr, nullptr); layer_tree->Preroll(frame); - // Update the scene contents. - mozart::RectF bounds; - bounds.width = frame_size.width(); - bounds.height = frame_size.height(); - - auto content_resource = mozart::Resource::New(); - content_resource->set_image(mozart::ImageResource::New()); - content_resource->get_image()->image = std::move(image); - update->resources.insert(kContentImageResourceId, - std::move(content_resource)); - + flow::SceneUpdateContext context(update.get(), buffer_producer_.get()); auto root_node = mozart::Node::New(); - root_node->hit_test_behavior = mozart::HitTestBehavior::New(); - root_node->op = mozart::NodeOp::New(); - root_node->op->set_image(mozart::ImageNodeOp::New()); - root_node->op->get_image()->content_rect = bounds.Clone(); - root_node->op->get_image()->image_resource_id = kContentImageResourceId; - - layer_tree->UpdateScene(update.get(), root_node.get()); - - update->nodes.insert(kRootNodeId, std::move(root_node)); + layer_tree->UpdateScene(context, root_node.get()); + update->nodes.insert(mozart::kSceneRootNodeId, std::move(root_node)); // Publish the updated scene contents. // TODO(jeffbrown): We should set the metadata's presentation_time here too. @@ -94,10 +69,7 @@ void Rasterizer::Draw(std::unique_ptr layer_tree, // We do this after publishing to take advantage of pipelining. // The image buffer's fence is signalled automatically when the surface // goes out of scope. - SkCanvas* canvas = surface->getCanvas(); - canvas->clear(SK_ColorBLACK); - layer_tree->Paint(frame); - canvas->flush(); + context.ExecutePaintTasks(frame); callback(); } diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 03057da4417..c2c1d06ab6e 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -4,6 +4,8 @@ source_set("flow") { sources = [ + "bitmap_image.cc", + "bitmap_image.h", "compositor_context.cc", "compositor_context.h", "instrumentation.cc", @@ -36,8 +38,8 @@ source_set("flow") { "layers/transform_layer.h", "raster_cache.cc", "raster_cache.h", - "bitmap_image.cc", - "bitmap_image.h", + "scene_update_context.cc", + "scene_update_context.h", "texture_image.h", ] @@ -57,6 +59,7 @@ source_set("flow") { "texture_image_none.cc", ] public_deps = [ + "//apps/mozart/lib/skia", "//apps/mozart/services/composition", ] } else { diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 91d2f8a8023..b5b1c2daf3b 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -30,18 +30,18 @@ void CompositorContext::EndFrame(ScopedFrame& frame, CompositorContext::ScopedFrame CompositorContext::AcquireFrame( GrContext* gr_context, - SkCanvas& canvas, + SkCanvas* canvas, bool instrumentation_enabled) { return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled); } CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, GrContext* gr_context, - SkCanvas& canvas, + SkCanvas* canvas, bool instrumentation_enabled) : context_(context), gr_context_(gr_context), - canvas_(&canvas), + canvas_(canvas), instrumentation_enabled_(instrumentation_enabled) { context_.BeginFrame(*this, instrumentation_enabled_); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index f16f3c46029..a981f75847b 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -38,7 +38,7 @@ class CompositorContext { ScopedFrame(CompositorContext& context, GrContext* gr_context, - SkCanvas& canvas, + SkCanvas* canvas, bool instrumentation_enabled); friend class CompositorContext; @@ -51,7 +51,7 @@ class CompositorContext { ~CompositorContext(); ScopedFrame AcquireFrame(GrContext* gr_context, - SkCanvas& canvas, + SkCanvas* canvas, bool instrumentation_enabled = true); void OnGrContextDestroyed(); diff --git a/flow/layers/child_scene_layer.cc b/flow/layers/child_scene_layer.cc index 1f0233c878e..aedff4172b4 100644 --- a/flow/layers/child_scene_layer.cc +++ b/flow/layers/child_scene_layer.cc @@ -4,72 +4,47 @@ #include "flutter/flow/layers/child_scene_layer.h" +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" + namespace flow { -namespace { - -mozart::TransformPtr GetTransformFromSkMatrix(const SkMatrix& input) { - // Expand 3x3 to 4x4. - auto output = mozart::Transform::New(); - output->matrix.resize(16u); - output->matrix[0] = input[0]; - output->matrix[1] = input[1]; - output->matrix[2] = 0.f; - output->matrix[3] = input[2]; - output->matrix[4] = input[3]; - output->matrix[5] = input[4]; - output->matrix[6] = 0.f; - output->matrix[7] = input[5]; - output->matrix[8] = 0.f; - output->matrix[9] = 0.f; - output->matrix[10] = 1.f; - output->matrix[11] = 0.f; - output->matrix[12] = input[6]; - output->matrix[13] = input[7]; - output->matrix[14] = 0.f; - output->matrix[15] = input[8]; - return output; -} - -// TODO(abarth): We need to figure out how to allocate these ids sensibly. -static uint32_t next_id = 10; - -} // namespace ChildSceneLayer::ChildSceneLayer() : device_pixel_ratio_(1.0f) {} ChildSceneLayer::~ChildSceneLayer() {} void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - transform_ = matrix; + set_needs_system_composite(true); + transform_.setIdentity(); transform_.preTranslate(offset_.x(), offset_.y()); float inverse_device_pixel_ratio = 1.f / device_pixel_ratio_; transform_.preScale(inverse_device_pixel_ratio, inverse_device_pixel_ratio); } void ChildSceneLayer::Paint(PaintContext& context) { - TRACE_EVENT0("flutter", "ChildSceneLayer::Paint"); + FTL_DCHECK(false) << "Failed to composite child scene."; } -void ChildSceneLayer::UpdateScene(mozart::SceneUpdate* update, +void ChildSceneLayer::UpdateScene(SceneUpdateContext& context, mozart::Node* container) { - uint32_t id = next_id++; + FTL_DCHECK(needs_system_composite()); - auto child_resource = mozart::Resource::New(); - child_resource->set_scene(mozart::SceneResource::New()); - child_resource->get_scene()->scene_token = mozart::SceneToken::New(); - child_resource->get_scene()->scene_token->value = scene_token_; - update->resources.insert(id, std::move(child_resource)); + auto resource = mozart::Resource::New(); + resource->set_scene(mozart::SceneResource::New()); + resource->get_scene()->scene_token = mozart::SceneToken::New(); + resource->get_scene()->scene_token->value = scene_token_; - auto child_node = mozart::Node::New(); - child_node->op = mozart::NodeOp::New(); - child_node->op->set_scene(mozart::SceneNodeOp::New()); - child_node->op->get_scene()->scene_resource_id = id; - child_node->content_clip = mozart::RectF::New(); - child_node->content_clip->width = physical_size_.width(); - child_node->content_clip->height = physical_size_.height(); - child_node->content_transform = GetTransformFromSkMatrix(transform_); - update->nodes.insert(id, std::move(child_node)); - container->child_node_ids.push_back(id); + auto node = mozart::Node::New(); + node->op = mozart::NodeOp::New(); + node->op->set_scene(mozart::SceneNodeOp::New()); + node->op->get_scene()->scene_resource_id = + context.AddResource(std::move(resource)); + node->content_clip = mozart::RectF::New(); + node->content_clip->width = physical_size_.width(); + node->content_clip->height = physical_size_.height(); + node->content_transform = mozart::Transform::From(transform_); + + context.AddChildNode(container, std::move(node)); } } // namespace flow diff --git a/flow/layers/child_scene_layer.h b/flow/layers/child_scene_layer.h index 649a2a83661..ffd18b2a0ef 100644 --- a/flow/layers/child_scene_layer.h +++ b/flow/layers/child_scene_layer.h @@ -29,7 +29,7 @@ class ChildSceneLayer : public Layer { void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; - void UpdateScene(mozart::SceneUpdate* update, + void UpdateScene(SceneUpdateContext& context, mozart::Node* container) override; private: diff --git a/flow/layers/clip_path_layer.cc b/flow/layers/clip_path_layer.cc index ae63e38bc1b..693e568bcf3 100644 --- a/flow/layers/clip_path_layer.cc +++ b/flow/layers/clip_path_layer.cc @@ -4,6 +4,11 @@ #include "flutter/flow/layers/clip_path_layer.h" +#if defined(OS_FUCHSIA) +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" +#endif // defined(OS_FUCHSIA) + namespace flow { ClipPathLayer::ClipPathLayer() {} @@ -17,8 +22,21 @@ void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(context->child_paint_bounds); } +#if defined(OS_FUCHSIA) + +void ClipPathLayer::UpdateScene(SceneUpdateContext& context, + mozart::Node* container) { + auto node = mozart::Node::New(); + node->content_clip = mozart::RectF::From(clip_path_.getBounds()); + UpdateSceneChildrenInsideNode(context, container, std::move(node)); +} + +#endif // defined(OS_FUCHSIA) + void ClipPathLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipPathLayer::Paint"); + FTL_DCHECK(!needs_system_composite()); + SkAutoCanvasRestore save(&context.canvas, false); context.canvas.saveLayer(&paint_bounds(), nullptr); context.canvas.clipPath(clip_path_, true); diff --git a/flow/layers/clip_path_layer.h b/flow/layers/clip_path_layer.h index 185f8b7be5c..a62d66aa42a 100644 --- a/flow/layers/clip_path_layer.h +++ b/flow/layers/clip_path_layer.h @@ -20,6 +20,11 @@ class ClipPathLayer : public ContainerLayer { void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; +#if defined(OS_FUCHSIA) + void UpdateScene(SceneUpdateContext& context, + mozart::Node* container) override; +#endif // defined(OS_FUCHSIA) + private: SkPath clip_path_; diff --git a/flow/layers/clip_rect_layer.cc b/flow/layers/clip_rect_layer.cc index 66db9c7d080..411b843d506 100644 --- a/flow/layers/clip_rect_layer.cc +++ b/flow/layers/clip_rect_layer.cc @@ -4,6 +4,11 @@ #include "flutter/flow/layers/clip_rect_layer.h" +#if defined(OS_FUCHSIA) +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" +#endif // defined(OS_FUCHSIA) + namespace flow { ClipRectLayer::ClipRectLayer() {} @@ -17,8 +22,21 @@ void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(context->child_paint_bounds); } +#if defined(OS_FUCHSIA) + +void ClipRectLayer::UpdateScene(SceneUpdateContext& context, + mozart::Node* container) { + auto node = mozart::Node::New(); + node->content_clip = mozart::RectF::From(clip_rect_); + UpdateSceneChildrenInsideNode(context, container, std::move(node)); +} + +#endif // defined(OS_FUCHSIA) + void ClipRectLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipRectLayer::Paint"); + FTL_DCHECK(!needs_system_composite()); + SkAutoCanvasRestore save(&context.canvas, true); context.canvas.clipRect(paint_bounds()); PaintChildren(context); diff --git a/flow/layers/clip_rect_layer.h b/flow/layers/clip_rect_layer.h index 64d7dc43525..5b09e006366 100644 --- a/flow/layers/clip_rect_layer.h +++ b/flow/layers/clip_rect_layer.h @@ -20,6 +20,11 @@ class ClipRectLayer : public ContainerLayer { void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; +#if defined(OS_FUCHSIA) + void UpdateScene(SceneUpdateContext& context, + mozart::Node* container) override; +#endif // defined(OS_FUCHSIA) + private: SkRect clip_rect_; diff --git a/flow/layers/clip_rrect_layer.cc b/flow/layers/clip_rrect_layer.cc index 9f8f567303e..66aa9a465b7 100644 --- a/flow/layers/clip_rrect_layer.cc +++ b/flow/layers/clip_rrect_layer.cc @@ -4,6 +4,11 @@ #include "flutter/flow/layers/clip_rrect_layer.h" +#if defined(OS_FUCHSIA) +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" +#endif // defined(OS_FUCHSIA) + namespace flow { ClipRRectLayer::ClipRRectLayer() {} @@ -17,8 +22,21 @@ void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { set_paint_bounds(context->child_paint_bounds); } +#if defined(OS_FUCHSIA) + +void ClipRRectLayer::UpdateScene(SceneUpdateContext& context, + mozart::Node* container) { + auto node = mozart::Node::New(); + node->content_clip = mozart::RectF::From(clip_rrect_.getBounds()); + UpdateSceneChildrenInsideNode(context, container, std::move(node)); +} + +#endif // defined(OS_FUCHSIA) + void ClipRRectLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "ClipRRectLayer::Paint"); + FTL_DCHECK(!needs_system_composite()); + SkAutoCanvasRestore save(&context.canvas, false); context.canvas.saveLayer(&paint_bounds(), nullptr); context.canvas.clipRRect(clip_rrect_, true); diff --git a/flow/layers/clip_rrect_layer.h b/flow/layers/clip_rrect_layer.h index 5dc4d8959d4..79b8ae554cb 100644 --- a/flow/layers/clip_rrect_layer.h +++ b/flow/layers/clip_rrect_layer.h @@ -20,6 +20,11 @@ class ClipRRectLayer : public ContainerLayer { void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; +#if defined(OS_FUCHSIA) + void UpdateScene(SceneUpdateContext& context, + mozart::Node* container) override; +#endif // defined(OS_FUCHSIA) + private: SkRRect clip_rrect_; diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index d2da8a5de83..27507e9ed79 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -6,7 +6,9 @@ namespace flow { -ContainerLayer::ContainerLayer() {} +ContainerLayer::ContainerLayer() { + ctm_.setIdentity(); +} ContainerLayer::~ContainerLayer() {} @@ -27,12 +29,18 @@ void ContainerLayer::PrerollChildren(PrerollContext* context, for (auto& layer : layers_) { PrerollContext child_context = *context; layer->Preroll(&child_context, matrix); + if (layer->needs_system_composite()) + set_needs_system_composite(true); child_paint_bounds.join(child_context.child_paint_bounds); } context->child_paint_bounds = child_paint_bounds; + + if (needs_system_composite()) + ctm_ = matrix; } void ContainerLayer::PaintChildren(PaintContext& context) const { + FTL_DCHECK(!needs_system_composite()); // Intentionally not tracing here as there should be no self-time // and the trace event on this common function has a small overhead. for (auto& layer : layers_) @@ -40,11 +48,34 @@ void ContainerLayer::PaintChildren(PaintContext& context) const { } #if defined(OS_FUCHSIA) -void ContainerLayer::UpdateScene(mozart::SceneUpdate* update, + +void ContainerLayer::UpdateScene(SceneUpdateContext& context, mozart::Node* container) { - for (auto& layer : layers_) - layer->UpdateScene(update, container); + UpdateSceneChildren(context, container); } -#endif + +void ContainerLayer::UpdateSceneChildrenInsideNode(SceneUpdateContext& context, + mozart::Node* container, + mozart::NodePtr node) { + FTL_DCHECK(needs_system_composite()); + UpdateSceneChildren(context, node.get()); + context.FinalizeCurrentPaintTaskIfNeeded(node.get(), ctm()); + context.AddChildNode(container, std::move(node)); +} + +void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context, + mozart::Node* container) { + FTL_DCHECK(needs_system_composite()); + for (auto& layer : layers_) { + if (layer->needs_system_composite()) { + context.FinalizeCurrentPaintTaskIfNeeded(container, ctm()); + layer->UpdateScene(context, container); + } else { + context.AddLayerToCurrentPaintTask(layer.get()); + } + } +} + +#endif // defined(OS_FUCHSIA) } // namespace flow diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index 4eedf389ec6..0aaa0d64255 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -23,15 +23,26 @@ class ContainerLayer : public Layer { void PaintChildren(PaintContext& context) const; #if defined(OS_FUCHSIA) - void UpdateScene(mozart::SceneUpdate* update, + void UpdateScene(SceneUpdateContext& context, mozart::Node* container) override; -#endif + void UpdateSceneChildrenInsideNode(SceneUpdateContext& context, + mozart::Node* container, + mozart::NodePtr node); + void UpdateSceneChildren(SceneUpdateContext& context, + mozart::Node* container); +#endif // defined(OS_FUCHSIA) const std::vector>& layers() const { return layers_; } + protected: + // Valid only after preroll when needs_system_composite() is true. + const SkMatrix& ctm() const { return ctm_; } + private: std::vector> layers_; + SkMatrix ctm_; + FTL_DISALLOW_COPY_AND_ASSIGN(ContainerLayer); }; diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index ef9ed6de3ff..d2e0d564f41 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -8,14 +8,20 @@ namespace flow { -Layer::Layer() : parent_(nullptr), has_paint_bounds_(false), paint_bounds_() {} +Layer::Layer() + : parent_(nullptr), + needs_system_composite_(false), + has_paint_bounds_(false), + paint_bounds_() {} -Layer::~Layer() {} +Layer::~Layer() = default; -void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {} +void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + set_paint_bounds(SkRect::MakeEmpty()); +} #if defined(OS_FUCHSIA) -void Layer::UpdateScene(mozart::SceneUpdate* update, mozart::Node* container) {} +void Layer::UpdateScene(SceneUpdateContext& context, mozart::Node* container) {} #endif } // namespace flow diff --git a/flow/layers/layer.h b/flow/layers/layer.h index 52515d26c39..f55320d24ef 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -10,6 +10,7 @@ #include "flutter/flow/instrumentation.h" #include "flutter/flow/raster_cache.h" +#include "flutter/flow/scene_update_context.h" #include "flutter/glue/trace_event.h" #include "lib/ftl/build_config.h" #include "lib/ftl/logging.h" @@ -24,16 +25,9 @@ #include "third_party/skia/include/core/SkRRect.h" #include "third_party/skia/include/core/SkXfermode.h" -#if defined(OS_FUCHSIA) -namespace mozart { -class SceneUpdate; -class Node; -} // namespace mozart -#endif - namespace flow { - class ContainerLayer; + class Layer { public: Layer(); @@ -56,7 +50,7 @@ class Layer { virtual void Paint(PaintContext& context) = 0; #if defined(OS_FUCHSIA) - virtual void UpdateScene(mozart::SceneUpdate* update, + virtual void UpdateScene(SceneUpdateContext& context, mozart::Node* container); #endif @@ -64,6 +58,11 @@ class Layer { void set_parent(ContainerLayer* parent) { parent_ = parent; } + bool needs_system_composite() const { return needs_system_composite_; } + void set_needs_system_composite(bool value) { + needs_system_composite_ = value; + } + // subclasses should assume this will be true by the time Paint() is called bool has_paint_bounds() const { return has_paint_bounds_; } @@ -79,6 +78,7 @@ class Layer { private: ContainerLayer* parent_; + bool needs_system_composite_; bool has_paint_bounds_; // if false, paint_bounds_ is not valid SkRect paint_bounds_; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 1ef68497745..c40090967cf 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -32,14 +32,20 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, ignore_raster_cache ? nullptr : &frame.context().raster_cache(), frame.gr_context(), SkRect::MakeEmpty(), }; - root_layer_->Preroll(&context, SkMatrix()); + root_layer_->Preroll(&context, SkMatrix::I()); } #if defined(OS_FUCHSIA) -void LayerTree::UpdateScene(mozart::SceneUpdate* update, +void LayerTree::UpdateScene(SceneUpdateContext& context, mozart::Node* container) { TRACE_EVENT0("flutter", "LayerTree::UpdateScene"); - root_layer_->UpdateScene(update, container); + + if (root_layer_->needs_system_composite()) { + root_layer_->UpdateScene(context, container); + } else { + context.AddLayerToCurrentPaintTask(root_layer_.get()); + } + context.FinalizeCurrentPaintTaskIfNeeded(container, SkMatrix::I()); } #endif diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index fcc4d4fb4ba..7421a92dc6e 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -34,7 +34,7 @@ class LayerTree { // TODO(abarth): Integrate scene updates with the rasterization pass so that // we can draw on top of child scenes (and so that we can apply clips and // blending operations to child scene). - void UpdateScene(mozart::SceneUpdate* update, mozart::Node* container); + void UpdateScene(SceneUpdateContext& context, mozart::Node* container); #endif void Paint(CompositorContext::ScopedFrame& frame); diff --git a/flow/layers/opacity_layer.cc b/flow/layers/opacity_layer.cc index 28b3f66fccd..51a070724b7 100644 --- a/flow/layers/opacity_layer.cc +++ b/flow/layers/opacity_layer.cc @@ -4,14 +4,35 @@ #include "flutter/flow/layers/opacity_layer.h" +#if defined(OS_FUCHSIA) +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" +#endif // defined(OS_FUCHSIA) + namespace flow { OpacityLayer::OpacityLayer() {} OpacityLayer::~OpacityLayer() {} +#if defined(OS_FUCHSIA) + +void OpacityLayer::UpdateScene(SceneUpdateContext& context, + mozart::Node* container) { + auto node = mozart::Node::New(); + node->op = mozart::NodeOp::New(); + node->op->set_layer(mozart::LayerNodeOp::New()); + node->op->get_layer()->layer_rect = mozart::RectF::From(paint_bounds()); + node->op->get_layer()->blend->alpha = alpha_; + UpdateSceneChildrenInsideNode(context, container, std::move(node)); +} + +#endif // defined(OS_FUCHSIA) + void OpacityLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "OpacityLayer::Paint"); + FTL_DCHECK(!needs_system_composite()); + SkPaint paint; paint.setAlpha(alpha_); diff --git a/flow/layers/opacity_layer.h b/flow/layers/opacity_layer.h index f5991b0aab8..1ccea1023a6 100644 --- a/flow/layers/opacity_layer.h +++ b/flow/layers/opacity_layer.h @@ -19,6 +19,11 @@ class OpacityLayer : public ContainerLayer { protected: void Paint(PaintContext& context) override; +#if defined(OS_FUCHSIA) + void UpdateScene(SceneUpdateContext& context, + mozart::Node* container) override; +#endif // defined(OS_FUCHSIA) + private: int alpha_; diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 8faaabc9a97..c22a4b54fb0 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -25,8 +25,9 @@ void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { matrix, is_complex_, will_change_); } - context->child_paint_bounds = - picture_->cullRect().makeOffset(offset_.x(), offset_.y()); + SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); + set_paint_bounds(bounds); + context->child_paint_bounds = bounds; } void PictureLayer::Paint(PaintContext& context) { diff --git a/flow/layers/transform_layer.cc b/flow/layers/transform_layer.cc index 2b7448ad9b2..7817fce8c46 100644 --- a/flow/layers/transform_layer.cc +++ b/flow/layers/transform_layer.cc @@ -4,6 +4,11 @@ #include "flutter/flow/layers/transform_layer.h" +#if defined(OS_FUCHSIA) +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/nodes.fidl.h" +#endif // defined(OS_FUCHSIA) + namespace flow { TransformLayer::TransformLayer() {} @@ -15,10 +20,24 @@ void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { childMatrix.setConcat(matrix, transform_); PrerollChildren(context, childMatrix); transform_.mapRect(&context->child_paint_bounds); + set_paint_bounds(context->child_paint_bounds); } +#if defined(OS_FUCHSIA) + +void TransformLayer::UpdateScene(SceneUpdateContext& context, + mozart::Node* container) { + auto node = mozart::Node::New(); + node->content_transform = mozart::Transform::From(transform_); + UpdateSceneChildrenInsideNode(context, container, std::move(node)); +} + +#endif // defined(OS_FUCHSIA) + void TransformLayer::Paint(PaintContext& context) { TRACE_EVENT0("flutter", "TransformLayer::Paint"); + FTL_DCHECK(!needs_system_composite()); + SkAutoCanvasRestore save(&context.canvas, true); context.canvas.concat(transform_); PaintChildren(context); diff --git a/flow/layers/transform_layer.h b/flow/layers/transform_layer.h index 63439a410f9..dee5fc5796e 100644 --- a/flow/layers/transform_layer.h +++ b/flow/layers/transform_layer.h @@ -16,9 +16,15 @@ class TransformLayer : public ContainerLayer { void set_transform(const SkMatrix& transform) { transform_ = transform; } + protected: void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) override; +#if defined(OS_FUCHSIA) + void UpdateScene(SceneUpdateContext& context, + mozart::Node* container) override; +#endif // defined(OS_FUCHSIA) + private: SkMatrix transform_; diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc new file mode 100644 index 00000000000..06661e072a3 --- /dev/null +++ b/flow/scene_update_context.cc @@ -0,0 +1,127 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/flow/scene_update_context.h" + +#if defined(OS_FUCHSIA) + +#include "apps/mozart/lib/skia/skia_vmo_surface.h" +#include "apps/mozart/lib/skia/type_converters.h" +#include "apps/mozart/services/composition/scenes.fidl.h" +#include "flutter/flow/layers/layer.h" +#include "flutter/glue/trace_event.h" + +namespace flow { + +SceneUpdateContext::CurrentPaintTask::CurrentPaintTask() + : bounds(SkRect::MakeEmpty()) {} + +void SceneUpdateContext::CurrentPaintTask::Clear() { + bounds = SkRect::MakeEmpty(); + layers.clear(); +} + +SceneUpdateContext::SceneUpdateContext(mozart::SceneUpdate* update, + mozart::BufferProducer* buffer_producer) + : update_(update), buffer_producer_(buffer_producer) {} + +SceneUpdateContext::~SceneUpdateContext() = default; + +void SceneUpdateContext::AddLayerToCurrentPaintTask(Layer* layer) { + current_paint_task_.bounds.join(layer->paint_bounds()); + current_paint_task_.layers.push_back(layer); +} + +void SceneUpdateContext::FinalizeCurrentPaintTaskIfNeeded( + mozart::Node* container, + const SkMatrix& ctm) { + if (mozart::NodePtr node = FinalizeCurrentPaintTask(ctm)) + AddChildNode(container, std::move(node)); +} + +mozart::NodePtr SceneUpdateContext::FinalizeCurrentPaintTask( + const SkMatrix& ctm) { + if (current_paint_task_.layers.empty()) + return nullptr; + + const SkRect& bounds = current_paint_task_.bounds; + + SkScalar scaleX = ctm.getScaleX(); + SkScalar scaleY = ctm.getScaleY(); + + SkISize physical_size = + SkISize::Make(bounds.width() * scaleX, bounds.height() * scaleY); + + if (physical_size.isEmpty()) { + current_paint_task_.Clear(); + return nullptr; + } + + mozart::ImagePtr image; + PaintTask task; + task.surface = mozart::MakeSkSurface(physical_size, buffer_producer_, &image); + task.left = bounds.left(); + task.top = bounds.top(); + task.scaleX = scaleX; + task.scaleY = scaleY; + task.layers = std::move(current_paint_task_.layers); + + FTL_DCHECK(task.surface) << "Failed to create surface size=" + << physical_size.width() << "x" + << physical_size.height(); + + paint_tasks_.push_back(task); + + auto resource = mozart::Resource::New(); + resource->set_image(mozart::ImageResource::New()); + resource->get_image()->image = std::move(image); + + auto node = mozart::Node::New(); + node->hit_test_behavior = mozart::HitTestBehavior::New(); + node->op = mozart::NodeOp::New(); + node->op->set_image(mozart::ImageNodeOp::New()); + node->op->get_image()->content_rect = mozart::RectF::From(bounds); + node->op->get_image()->image_resource_id = AddResource(std::move(resource)); + + current_paint_task_.Clear(); + return node; +} + +uint32_t SceneUpdateContext::AddResource(mozart::ResourcePtr resource) { + uint32_t resource_id = next_resource_id_++; + update_->resources.insert(resource_id, std::move(resource)); + return resource_id; +} + +void SceneUpdateContext::AddChildNode(mozart::Node* container, + mozart::NodePtr child) { + uint32_t node_id = next_node_id_++; + update_->nodes.insert(node_id, std::move(child)); + container->child_node_ids.push_back(node_id); +} + +void SceneUpdateContext::ExecutePaintTasks( + CompositorContext::ScopedFrame& frame) { + TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks"); + + for (auto& task : paint_tasks_) { + FTL_DCHECK(task.surface); + SkCanvas* canvas = task.surface->getCanvas(); + Layer::PaintContext context = {*canvas, frame.context().frame_time(), + frame.context().engine_time()}; + + canvas->clear(SK_ColorTRANSPARENT); + canvas->scale(task.scaleX, task.scaleY); + canvas->translate(-task.left, -task.top); + for (Layer* layer : task.layers) + layer->Paint(context); + canvas->flush(); + } + + paint_tasks_.clear(); +} + +} // namespace flow + +#endif // defined(OS_FUCHSIA) diff --git a/flow/scene_update_context.h b/flow/scene_update_context.h new file mode 100644 index 00000000000..4ced4d88b76 --- /dev/null +++ b/flow/scene_update_context.h @@ -0,0 +1,89 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ +#define FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ + +#include +#include + +#include "flutter/flow/compositor_context.h" +#include "lib/ftl/build_config.h" +#include "lib/ftl/logging.h" +#include "lib/ftl/macros.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkSurface.h" + +#if defined(OS_FUCHSIA) +#include "apps/mozart/services/composition/nodes.fidl.h" +#include "apps/mozart/services/composition/resources.fidl.h" +#include "apps/mozart/services/images/image.fidl.h" +#endif // defined(OS_FUCHSIA) + +namespace mozart { +class BufferProducer; +class Node; +class SceneUpdate; +} // namespace mozart + +namespace flow { +class Layer; +class SceneUpdateContext; + +#if defined(OS_FUCHSIA) + +class SceneUpdateContext { + public: + SceneUpdateContext(mozart::SceneUpdate* update, + mozart::BufferProducer* buffer_producer); + ~SceneUpdateContext(); + + mozart::SceneUpdate* update() const { return update_; } + + void AddLayerToCurrentPaintTask(Layer* layer); + void FinalizeCurrentPaintTaskIfNeeded(mozart::Node* container, + const SkMatrix& ctm); + + uint32_t AddResource(mozart::ResourcePtr resource); + void AddChildNode(mozart::Node* container, mozart::NodePtr child); + + void ExecutePaintTasks(CompositorContext::ScopedFrame& frame); + + private: + mozart::NodePtr FinalizeCurrentPaintTask(const SkMatrix& ctm); + + struct CurrentPaintTask { + CurrentPaintTask(); + void Clear(); + + SkRect bounds; + std::vector layers; + }; + + struct PaintTask { + sk_sp surface; + SkScalar left; + SkScalar top; + SkScalar scaleX; + SkScalar scaleY; + std::vector layers; + }; + + mozart::SceneUpdate* update_; + mozart::BufferProducer* buffer_producer_; + + CurrentPaintTask current_paint_task_; + std::vector paint_tasks_; + + uint32_t next_resource_id_ = 1; + uint32_t next_node_id_ = 1; + + FTL_DISALLOW_COPY_AND_ASSIGN(SceneUpdateContext); +}; + +#endif // defined(OS_FUCHSIA) + +} // namespace flow + +#endif // FLUTTER_FLOW_MOZART_SCENE_UPDATE_CONTEXT_H_ diff --git a/shell/common/diagnostic/diagnostic_server.cc b/shell/common/diagnostic/diagnostic_server.cc index 73c76fddc6c..8c850b40c9a 100644 --- a/shell/common/diagnostic/diagnostic_server.cc +++ b/shell/common/diagnostic/diagnostic_server.cc @@ -127,7 +127,7 @@ void DiagnosticServer::SkiaPictureTask(Dart_Port port_id) { flow::CompositorContext compositor_context; flow::CompositorContext::ScopedFrame frame = compositor_context.AcquireFrame( - nullptr, *recorder.getRecordingCanvas(), false); + nullptr, recorder.getRecordingCanvas(), false); layer_tree->Raster(frame); sk_sp picture = recorder.finishRecordingAsPicture(); diff --git a/shell/common/platform_view_service_protocol.cc b/shell/common/platform_view_service_protocol.cc index 99f6e05a3f7..8effa833ac0 100644 --- a/shell/common/platform_view_service_protocol.cc +++ b/shell/common/platform_view_service_protocol.cc @@ -253,8 +253,9 @@ bool PlatformViewServiceProtocol::Screenshot(const char* method, if (bitmap.empty()) return ErrorServer(json_object, "no screenshot available"); - sk_sp png(SkImageEncoder::EncodeData( - bitmap, SkImageEncoder::Type::kPNG_Type, SkImageEncoder::kDefaultQuality)); + sk_sp png( + SkImageEncoder::EncodeData(bitmap, SkImageEncoder::Type::kPNG_Type, + SkImageEncoder::kDefaultQuality)); if (!png) return ErrorServer(json_object, "can not encode screenshot"); @@ -295,7 +296,7 @@ void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) { flow::CompositorContext compositor_context; SkCanvas* canvas = surface->getCanvas(); flow::CompositorContext::ScopedFrame frame = - compositor_context.AcquireFrame(nullptr, *canvas, false); + compositor_context.AcquireFrame(nullptr, canvas, false); canvas->clear(SK_ColorBLACK); layer_tree->Raster(frame); diff --git a/shell/gpu/gpu_rasterizer.cc b/shell/gpu/gpu_rasterizer.cc index f21ae29017c..6c683905ec8 100644 --- a/shell/gpu/gpu_rasterizer.cc +++ b/shell/gpu/gpu_rasterizer.cc @@ -130,7 +130,7 @@ void GPURasterizer::DrawToSurface(flow::LayerTree& layer_tree) { } auto compositor_frame = - compositor_context_.AcquireFrame(surface_->GetContext(), *canvas); + compositor_context_.AcquireFrame(surface_->GetContext(), canvas); canvas->clear(SK_ColorBLACK); @@ -173,7 +173,7 @@ void GPURasterizer::DrawToTraceIfNecessary(flow::LayerTree& layer_tree) { layer_tree.frame_size().height()); auto compositor_frame = compositor_context_.AcquireFrame( - nullptr, *recorder.getRecordingCanvas(), false); + nullptr, recorder.getRecordingCanvas(), false); layer_tree.Raster(compositor_frame, true /* ignore raster cache */); sk_sp picture = recorder.finishRecordingAsPicture(); diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 56936353e1d..3e5c91c0f69 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -146,8 +146,10 @@ void PlatformViewAndroid::RunBundleAndSnapshot(JNIEnv* env, jstring java_snapshot_override) { std::string bundle_path = base::android::ConvertJavaStringToUTF8(env, java_bundle_path); - std::string snapshot_override = java_snapshot_override ? - base::android::ConvertJavaStringToUTF8(env, java_snapshot_override) : ""; + std::string snapshot_override = + java_snapshot_override + ? base::android::ConvertJavaStringToUTF8(env, java_snapshot_override) + : ""; blink::Threads::UI()->PostTask( [ engine = engine_->GetWeakPtr(), bundle_path, snapshot_override ] { @@ -497,7 +499,7 @@ void PlatformViewAndroid::GetBitmapGpuTask(ftl::AutoResetWaitableEvent* latch, flow::CompositorContext compositor_context; SkCanvas* canvas = surface->getCanvas(); flow::CompositorContext::ScopedFrame frame = - compositor_context.AcquireFrame(nullptr, *canvas, false); + compositor_context.AcquireFrame(nullptr, canvas, false); canvas->clear(SK_ColorBLACK); layer_tree->Raster(frame);