mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
e18302e7d1
commit
21f6aa5270
@ -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<flow::LayerTree> 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<flow::LayerTree> layer_tree,
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a surface to draw the contents.
|
||||
mozart::ImagePtr image;
|
||||
sk_sp<SkSurface> 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<flow::LayerTree> 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();
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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_);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<std::unique_ptr<Layer>>& layers() const { return layers_; }
|
||||
|
||||
protected:
|
||||
// Valid only after preroll when needs_system_composite() is true.
|
||||
const SkMatrix& ctm() const { return ctm_; }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Layer>> layers_;
|
||||
|
||||
SkMatrix ctm_;
|
||||
|
||||
FTL_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_);
|
||||
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
|
||||
127
flow/scene_update_context.cc
Normal file
127
flow/scene_update_context.cc
Normal file
@ -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)
|
||||
89
flow/scene_update_context.h
Normal file
89
flow/scene_update_context.h
Normal file
@ -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 <memory>
|
||||
#include <vector>
|
||||
|
||||
#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<Layer*> layers;
|
||||
};
|
||||
|
||||
struct PaintTask {
|
||||
sk_sp<SkSurface> surface;
|
||||
SkScalar left;
|
||||
SkScalar top;
|
||||
SkScalar scaleX;
|
||||
SkScalar scaleY;
|
||||
std::vector<Layer*> layers;
|
||||
};
|
||||
|
||||
mozart::SceneUpdate* update_;
|
||||
mozart::BufferProducer* buffer_producer_;
|
||||
|
||||
CurrentPaintTask current_paint_task_;
|
||||
std::vector<PaintTask> 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_
|
||||
@ -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<SkPicture> picture = recorder.finishRecordingAsPicture();
|
||||
|
||||
@ -253,8 +253,9 @@ bool PlatformViewServiceProtocol::Screenshot(const char* method,
|
||||
if (bitmap.empty())
|
||||
return ErrorServer(json_object, "no screenshot available");
|
||||
|
||||
sk_sp<SkData> png(SkImageEncoder::EncodeData(
|
||||
bitmap, SkImageEncoder::Type::kPNG_Type, SkImageEncoder::kDefaultQuality));
|
||||
sk_sp<SkData> 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);
|
||||
|
||||
@ -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<SkPicture> picture = recorder.finishRecordingAsPicture();
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user