未验证 提交 fcc4ab32 编写于 作者: D David Worsham 提交者: GitHub

[fuchsia] Wire up OpacityLayer to Scenic (#11322)

On Fuchsia, add a build flag for compositing OpacityLayers using the system
compositor vs Skia, which exposes a fastpath for opacity via Scenic.
This will only work under certain circumstances, in particular nested
OpacityLayers will not render correctly!

On Fuchsia, add a build flag for compositing PhysicalShapeLayers using
the system compositor vs Skia. Set to off by default, which restores
performant shadows on Fuchsia.

Remove the opacity exposed from ChildView, as that was added mistakenly.

Finally, we centralize the logic for switching between the
system-composited and in-process-composited paths inside of
ContainerLayer. We also centralize the logic for computing elevation
there. This allows the removal of many OS_FUCHSIA-specific code-paths.

Test: Ran workstation on Fuchsia; benchmarked before and after
Bug: 23711
Bug: 24163

* Fix broken tests
上级 c3bfbec9
......@@ -18,7 +18,7 @@ void BackdropFilterLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save = Layer::AutoSaveLayer::Create(
context,
SkCanvas::SaveLayerRec{&paint_bounds(), nullptr, filter_.get(), 0});
PaintChildren(context);
ContainerLayer::Paint(context);
}
} // namespace flutter
......@@ -19,10 +19,25 @@ ChildSceneLayer::ChildSceneLayer(zx_koid_t layer_id,
void ChildSceneLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
set_needs_system_composite(true);
// An alpha "hole punch" is required if the frame behind us is not opaque.
if (!context->is_opaque) {
set_paint_bounds(
SkRect::MakeXYWH(offset_.fX, offset_.fY, size_.fWidth, size_.fHeight));
}
}
void ChildSceneLayer::Paint(PaintContext& context) const {
FML_NOTREACHED() << "This layer never needs painting.";
TRACE_EVENT0("flutter", "ChildSceneLayer::Paint");
FML_DCHECK(needs_painting());
// If we are being rendered into our own frame using the system compositor,
// then it is neccesary to "punch a hole" in the canvas/frame behind us so
// that group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
}
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
......
......@@ -4,12 +4,6 @@
#include "flutter/flow/layers/clip_path_layer.h"
#if defined(OS_FUCHSIA)
#include "lib/ui/scenic/cpp/commands.h"
#endif // defined(OS_FUCHSIA)
namespace flutter {
ClipPathLayer::ClipPathLayer(const SkPath& clip_path, Clip clip_behavior)
......@@ -24,29 +18,18 @@ void ClipPathLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect clip_path_bounds = clip_path_.getBounds();
if (context->cull_rect.intersect(clip_path_bounds)) {
context->mutators_stack.PushClipPath(clip_path_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
ContainerLayer::Preroll(context, matrix);
if (child_paint_bounds.intersect(clip_path_bounds)) {
set_paint_bounds(child_paint_bounds);
if (clip_path_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_path_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_path_.getBounds());
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipPathLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipPathLayer::Paint");
FML_DCHECK(needs_painting());
......@@ -58,10 +41,21 @@ void ClipPathLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
}
PaintChildren(context);
ContainerLayer::Paint(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipPathLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_path_.getBounds());
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
......@@ -15,12 +15,8 @@ class ClipPathLayer : public ContainerLayer {
~ClipPathLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkPath clip_path_;
......
......@@ -15,31 +15,21 @@ ClipRectLayer::~ClipRectLayer() = default;
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect previous_cull_rect = context->cull_rect;
if (context->cull_rect.intersect(clip_rect_)) {
context->mutators_stack.PushClipRect(clip_rect_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
if (child_paint_bounds.intersect(clip_rect_)) {
set_paint_bounds(child_paint_bounds);
SkRect clip_rect_bounds = clip_rect_;
if (context->cull_rect.intersect(clip_rect_bounds)) {
context->mutators_stack.PushClipRect(clip_rect_bounds);
ContainerLayer::Preroll(context, matrix);
if (clip_rect_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_rect_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipRectLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rect_);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRectLayer::Paint");
FML_DCHECK(needs_painting());
......@@ -51,10 +41,21 @@ void ClipRectLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(clip_rect_, nullptr);
}
PaintChildren(context);
ContainerLayer::Paint(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipRectLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rect_);
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
......@@ -16,10 +16,7 @@ class ClipRectLayer : public ContainerLayer {
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkRect clip_rect_;
......
......@@ -18,29 +18,18 @@ void ClipRRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
SkRect clip_rrect_bounds = clip_rrect_.getBounds();
if (context->cull_rect.intersect(clip_rrect_bounds)) {
context->mutators_stack.PushClipRRect(clip_rrect_);
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
ContainerLayer::Preroll(context, matrix);
if (child_paint_bounds.intersect(clip_rrect_bounds)) {
set_paint_bounds(child_paint_bounds);
if (clip_rrect_bounds.intersect(paint_bounds())) {
set_paint_bounds(clip_rrect_bounds);
} else {
set_paint_bounds(SkRect::MakeEmpty());
}
context->mutators_stack.Pop();
}
context->cull_rect = previous_cull_rect;
}
#if defined(OS_FUCHSIA)
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rrect_.getBounds());
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void ClipRRectLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "ClipRRectLayer::Paint");
FML_DCHECK(needs_painting());
......@@ -52,10 +41,21 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
}
PaintChildren(context);
ContainerLayer::Paint(context);
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
context.internal_nodes_canvas->restore();
}
}
void ClipRRectLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
// TODO(liyuqian): respect clip_behavior_
SceneUpdateContext::Clip clip(context, clip_rrect_.getBounds());
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
......@@ -15,12 +15,8 @@ class ClipRRectLayer : public ContainerLayer {
~ClipRRectLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkRRect clip_rrect_;
......
......@@ -20,7 +20,7 @@ void ColorFilterLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save =
Layer::AutoSaveLayer::Create(context, paint_bounds(), &paint);
PaintChildren(context);
ContainerLayer::Paint(context);
}
} // namespace flutter
......@@ -4,13 +4,44 @@
#include "flutter/flow/layers/container_layer.h"
#include <memory>
#include "flutter/flow/layers/transform_layer.h"
namespace flutter {
ContainerLayer::ContainerLayer() {}
static float ClampElevation(float elevation,
float parent_elevation,
float max_elevation) {
// TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be
// able to have developers specify the behavior here to alternatives besides
// clamping, like normalization on some arbitrary curve.
float clamped_elevation = elevation;
if (max_elevation > -1 && (parent_elevation + elevation) > max_elevation) {
// Clamp the local z coordinate at our max bound. Take into account the
// parent z position here to fix clamping in cases where the child is
// overflowing because of its parents.
clamped_elevation = max_elevation - parent_elevation;
}
ContainerLayer::~ContainerLayer() = default;
return clamped_elevation;
}
ContainerLayer::ContainerLayer(bool force_single_child) {
// Place all "child" layers under a single child if requested.
if (force_single_child) {
single_child_ = std::make_shared<TransformLayer>(SkMatrix::I());
single_child_->set_parent(this);
layers_.push_back(single_child_);
}
}
void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
// Place all "child" layers under a single child if requested.
if (single_child_) {
single_child_->Add(std::move(layer));
return;
}
layer->set_parent(this);
layers_.push_back(std::move(layer));
}
......@@ -18,25 +49,29 @@ void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
TRACE_EVENT0("flutter", "ContainerLayer::Preroll");
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, matrix, &child_paint_bounds);
set_paint_bounds(child_paint_bounds);
}
// Track total elevation as we walk the tree, in order to deal with bounds
// overflow in z.
parent_elevation_ = context->total_elevation;
clamped_elevation_ = ClampElevation(elevation_, parent_elevation_,
context->frame_physical_depth);
context->total_elevation += clamped_elevation_;
void ContainerLayer::PrerollChildren(PrerollContext* context,
const SkMatrix& child_matrix,
SkRect* child_paint_bounds) {
SkRect child_paint_bounds = SkRect::MakeEmpty();
for (auto& layer : layers_) {
layer->Preroll(context, child_matrix);
layer->Preroll(context, matrix);
if (layer->needs_system_composite()) {
set_needs_system_composite(true);
}
child_paint_bounds->join(layer->paint_bounds());
child_paint_bounds.join(layer->paint_bounds());
}
set_paint_bounds(child_paint_bounds);
// Restore the elevation for our parent.
context->total_elevation = parent_elevation_;
}
void ContainerLayer::PaintChildren(PaintContext& context) const {
void ContainerLayer::Paint(PaintContext& context) const {
FML_DCHECK(needs_painting());
// Intentionally not tracing here as there should be no self-time
......@@ -48,24 +83,45 @@ void ContainerLayer::PaintChildren(PaintContext& context) const {
}
}
#if defined(OS_FUCHSIA)
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
UpdateSceneChildren(context);
}
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
if (should_render_as_frame()) {
FML_DCHECK(needs_system_composite());
// Paint all of the layers which need to be drawn into the container.
// These may be flattened down to a containing
for (auto& layer : layers_) {
// 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 Paint.
LayerRasterCacheKey key(unique_id(), context.Matrix());
if (context.HasRetainedNode(key)) {
const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
FML_DCHECK(context.top_entity());
FML_DCHECK(retained_node.session() == context.session());
context.top_entity()->embedder_node().AddChild(retained_node);
return;
}
SceneUpdateContext::Frame frame(context, frame_rrect_, frame_color_,
frame_opacity_, elevation(), this);
// Paint the child layers into the Frame as well as allowing them to create
// their own scene entities.
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
}
if (layer->needs_system_composite()) {
layer->UpdateScene(context);
}
}
}
} else {
// Update all of the Layers which are part of the container. This may cause
// additional scene entities to be created.
for (auto& layer : layers()) {
if (layer->needs_system_composite()) {
layer->UpdateScene(context);
}
}
}
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
......@@ -5,41 +5,56 @@
#ifndef FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
#define FLUTTER_FLOW_LAYERS_CONTAINER_LAYER_H_
#include <memory>
#include <vector>
#include "flutter/flow/layers/layer.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkRRect.h"
namespace flutter {
class ContainerLayer : public Layer {
public:
ContainerLayer();
~ContainerLayer() override;
ContainerLayer(bool force_single_child = false);
~ContainerLayer() override = default;
void Add(std::shared_ptr<Layer> layer);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
#if defined(OS_FUCHSIA)
void Paint(PaintContext& context) const override;
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
const std::vector<std::shared_ptr<Layer>>& layers() const { return layers_; }
bool should_render_as_frame() const { return !frame_rrect_.isEmpty(); }
void set_frame_properties(SkRRect frame_rrect,
SkColor frame_color,
float frame_opacity) {
frame_rrect_ = frame_rrect;
frame_color_ = frame_color;
frame_opacity_ = frame_opacity;
}
protected:
void PrerollChildren(PrerollContext* context,
const SkMatrix& child_matrix,
SkRect* child_paint_bounds);
void PaintChildren(PaintContext& context) const;
float elevation() const { return clamped_elevation_; }
float total_elevation() const {
return parent_elevation_ + clamped_elevation_;
}
void set_elevation(float elevation) {
parent_elevation_ = 0.0f;
elevation_ = elevation;
clamped_elevation_ = elevation;
}
#if defined(OS_FUCHSIA)
void UpdateSceneChildren(SceneUpdateContext& context);
#endif // defined(OS_FUCHSIA)
// For OpacityLayer to restructure to have a single child.
void ClearChildren() { layers_.clear(); }
const std::vector<std::shared_ptr<Layer>>& layers() const { return layers_; }
private:
std::vector<std::shared_ptr<Layer>> layers_;
std::shared_ptr<ContainerLayer> single_child_;
SkRRect frame_rrect_;
SkColor frame_color_;
float parent_elevation_ = 0.0f;
float elevation_ = 0.0f;
float clamped_elevation_ = 0.0f;
float frame_opacity_ = 1.0f;
FML_DISALLOW_COPY_AND_ASSIGN(ContainerLayer);
};
......
......@@ -7,17 +7,9 @@
#include "flutter/flow/paint_utils.h"
#include "third_party/skia/include/core/SkColorFilter.h"
namespace flutter {
Layer::Layer()
: parent_(nullptr),
needs_system_composite_(false),
paint_bounds_(SkRect::MakeEmpty()),
unique_id_(NextUniqueID()) {}
Layer::~Layer() = default;
namespace {
uint64_t Layer::NextUniqueID() {
uint64_t NextUniqueID() {
static std::atomic<uint64_t> nextID(1);
uint64_t id;
do {
......@@ -26,11 +18,15 @@ uint64_t Layer::NextUniqueID() {
return id;
}
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
} // anonymous namespace
#if defined(OS_FUCHSIA)
void Layer::UpdateScene(SceneUpdateContext& context) {}
#endif // defined(OS_FUCHSIA)
namespace flutter {
Layer::Layer()
: parent_(nullptr),
paint_bounds_(SkRect::MakeEmpty()),
unique_id_(NextUniqueID()),
needs_system_composite_(false) {}
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
const SkRect& bounds,
......
......@@ -11,6 +11,7 @@
#include "flutter/flow/embedded_views.h"
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/flow/scene_update_context.h"
#include "flutter/flow/texture.h"
#include "flutter/fml/build_config.h"
#include "flutter/fml/compiler_specific.h"
......@@ -27,14 +28,6 @@
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
#if defined(OS_FUCHSIA)
#include "flutter/flow/scene_update_context.h" //nogncheck
#include "lib/ui/scenic/cpp/resources.h" //nogncheck
#include "lib/ui/scenic/cpp/session.h" //nogncheck
#endif // defined(OS_FUCHSIA)
namespace flutter {
static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
......@@ -43,6 +36,7 @@ static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer };
class ContainerLayer;
class SceneUpdateContext;
struct PrerollContext {
RasterCache* raster_cache;
......@@ -57,7 +51,15 @@ struct PrerollContext {
const Stopwatch& ui_time;
TextureRegistry& texture_registry;
const bool checkerboard_offscreen_layers;
// The folllowing allow us to make use of the scene metrics during Preroll.
float frame_physical_depth;
float frame_device_pixel_ratio;
// The following allow us to track properties like elevation and opacity
// which stack with each other during Preroll.
float total_elevation = 0.0f;
bool is_opaque = true;
};
// Represents a single composited layer. Created on the UI thread but then
......@@ -65,9 +67,7 @@ struct PrerollContext {
class Layer {
public:
Layer();
virtual ~Layer();
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
virtual ~Layer() = default;
struct PaintContext {
// When splitting the scene into multiple canvases (e.g when embedding
......@@ -89,6 +89,10 @@ class Layer {
TextureRegistry& texture_registry;
const RasterCache* raster_cache;
const bool checkerboard_offscreen_layers;
// The folllowing 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
......@@ -118,15 +122,18 @@ class Layer {
const SkRect bounds_;
};
// Performs pre-paint optimizations, including bounds calculation. Called
// before |Paint|. If the |paint_bounds| calculated in this method is empty,
// then |Paint| will not be called.
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix) {}
// Paints this layer onto a canvas. Not called if |paint_bounds| is empty.
virtual void Paint(PaintContext& context) const = 0;
#if defined(OS_FUCHSIA)
// Updates the system composited scene.
virtual void UpdateScene(SceneUpdateContext& context);
#endif
virtual void UpdateScene(SceneUpdateContext& context) {}
ContainerLayer* parent() const { return parent_; }
void set_parent(ContainerLayer* parent) { parent_ = parent; }
bool needs_system_composite() const { return needs_system_composite_; }
......@@ -135,9 +142,6 @@ class Layer {
}
const SkRect& paint_bounds() const { return paint_bounds_; }
// This must be set by the time Preroll() returns otherwise the layer will
// be assumed to have empty paint bounds (paints no content).
void set_paint_bounds(const SkRect& paint_bounds) {
paint_bounds_ = paint_bounds;
}
......@@ -148,11 +152,9 @@ class Layer {
private:
ContainerLayer* parent_;
bool needs_system_composite_;
SkRect paint_bounds_;
uint64_t unique_id_;
static uint64_t NextUniqueID();
bool needs_system_composite_;
FML_DISALLOW_COPY_AND_ASSIGN(Layer);
};
......
......@@ -9,10 +9,18 @@
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
#if defined(OS_FUCHSIA)
#include <lib/ui/scenic/cpp/resources.h>
#endif
namespace flutter {
LayerTree::LayerTree()
: frame_size_{},
LayerTree::LayerTree(const SkISize& frame_size,
float frame_physical_depth,
float frame_device_pixel_ratio)
: frame_size_(frame_size),
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) {}
......@@ -42,36 +50,13 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
frame.context().raster_time(),
frame.context().ui_time(),
frame.context().texture_registry(),
checkerboard_offscreen_layers_};
checkerboard_offscreen_layers_,
frame_physical_depth_,
frame_device_pixel_ratio_};
root_layer_->Preroll(&context, frame.root_surface_transformation());
}
#if defined(OS_FUCHSIA)
void LayerTree::UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container) {
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
const auto& metrics = context.metrics();
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,
SkRRect::MakeRect(
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
SK_ColorTRANSPARENT);
if (root_layer_->needs_system_composite()) {
root_layer_->UpdateScene(context);
}
if (root_layer_->needs_painting()) {
frame.AddPaintLayer(root_layer_.get());
}
container.AddChild(transform.entity_node());
}
#endif
void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache) const {
TRACE_EVENT0("flutter", "LayerTree::Paint");
......@@ -94,7 +79,9 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
frame.context().ui_time(),
frame.context().texture_registry(),
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
checkerboard_offscreen_layers_};
checkerboard_offscreen_layers_,
frame_physical_depth_,
frame_device_pixel_ratio_};
if (root_layer_->needs_painting())
root_layer_->Paint(context);
......@@ -128,6 +115,8 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
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();
......@@ -143,7 +132,9 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
nullptr, // raster cache
false // checkerboard offscreen layers
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
......@@ -159,4 +150,38 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
return recorder.finishRecordingAsPicture();
}
void LayerTree::UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container) {
#if defined(OS_FUCHSIA)
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
// Ensure the context is aware of the view metrics.
context.set_frame_dimensions(frame_size_, frame_physical_depth_,
frame_device_pixel_ratio_);
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,
SkRRect::MakeRect(
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
SK_ColorTRANSPARENT, /* opacity */ 1.0f, /* elevation */ 0.0f);
if (root_layer_->needs_system_composite()) {
root_layer_->UpdateScene(context);
}
if (root_layer_->needs_painting()) {
frame.AddPaintLayer(root_layer_.get());
}
container.AddChild(transform.entity_node());
#endif
}
} // namespace flutter
......@@ -16,36 +16,37 @@
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkSize.h"
namespace scenic {
class ContainerNode;
} // namespace scenic
namespace flutter {
class SceneUpdateContext;
class LayerTree {
public:
LayerTree();
LayerTree(const SkISize& frame_size,
float frame_physical_depth,
float frame_device_pixel_ratio);
~LayerTree();
void Preroll(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false);
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container);
#endif
void Paint(CompositorContext::ScopedFrame& frame,
bool ignore_raster_cache = false) const;
sk_sp<SkPicture> Flatten(const SkRect& bounds);
void UpdateScene(SceneUpdateContext& context,
scenic::ContainerNode& container);
Layer* root_layer() const { return root_layer_.get(); }
void set_root_layer(std::shared_ptr<Layer> root_layer) {
root_layer_ = std::move(root_layer);
}
const SkISize& frame_size() const { return frame_size_; }
void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; }
float frame_physical_depth() const { return frame_physical_depth_; }
float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
void RecordBuildTime(fml::TimePoint begin_start);
fml::TimePoint build_start() const { return build_start_; }
......@@ -72,10 +73,13 @@ class LayerTree {
}
private:
SkISize frame_size_; // Physical pixels.
std::shared_ptr<Layer> root_layer_;
fml::TimePoint build_start_;
fml::TimePoint build_finish_;
SkISize frame_size_; // Physical pixels.
float frame_physical_depth_;
float
frame_device_pixel_ratio_; // Ratio between logical and physical pixels.
uint32_t rasterizer_tracing_threshold_;
bool checkerboard_raster_cache_images_;
bool checkerboard_offscreen_layers_;
......
......@@ -4,49 +4,56 @@
#include "flutter/flow/layers/opacity_layer.h"
#include "flutter/flow/layers/transform_layer.h"
namespace flutter {
OpacityLayer::OpacityLayer(int alpha, const SkPoint& offset)
: alpha_(alpha), offset_(offset) {}
OpacityLayer::~OpacityLayer() = default;
void OpacityLayer::EnsureSingleChild() {
FML_DCHECK(layers().size() > 0); // OpacityLayer should never be a leaf
if (layers().size() == 1) {
return;
}
#if defined(OS_FUCHSIA)
constexpr bool kRenderOpacityUsingSystemCompositor = true;
#else
constexpr bool kRenderOpacityUsingSystemCompositor = false;
#endif
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f;
// Be careful: SkMatrix's default constructor doesn't initialize the matrix to
// identity. Hence we have to explicitly call SkMatrix::setIdentity.
SkMatrix identity;
identity.setIdentity();
auto new_child = std::make_shared<flutter::TransformLayer>(identity);
OpacityLayer::OpacityLayer(int alpha, const SkPoint& offset)
: ContainerLayer(true), alpha_(alpha), offset_(offset) {
#if !defined(OS_FUCHSIA)
static_assert(!kRenderOpacityUsingSystemCompositor,
"Delegation of OpacityLayer to the system compositor is only "
"allowed on Fuchsia");
#endif
for (auto& child : layers()) {
new_child->Add(child);
if (kRenderOpacityUsingSystemCompositor) {
set_elevation(kOpacityElevationWhenUsingSystemCompositor);
}
ClearChildren();
Add(new_child);
}
void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
EnsureSingleChild();
SkMatrix child_matrix = matrix;
float parent_is_opaque = context->is_opaque;
child_matrix.postTranslate(offset_.fX, offset_.fY);
context->mutators_stack.PushTransform(
SkMatrix::MakeTrans(offset_.fX, offset_.fY));
context->mutators_stack.PushOpacity(alpha_);
context->is_opaque = parent_is_opaque && (alpha_ == 255);
ContainerLayer::Preroll(context, child_matrix);
context->is_opaque = parent_is_opaque;
context->mutators_stack.Pop();
context->mutators_stack.Pop();
// When using the system compositor, do not include the offset or use the
// raster cache, since we are rendering as a separate piece of geometry.
if (kRenderOpacityUsingSystemCompositor) {
set_needs_system_composite(true);
set_frame_properties(SkRRect::MakeRect(paint_bounds()), SK_ColorTRANSPARENT,
alpha_ / 255.0f);
// If the frame behind us is opaque, don't punch a hole in it for group
// opacity.
if (context->is_opaque) {
set_paint_bounds(SkRect());
}
} else {
set_paint_bounds(paint_bounds().makeOffset(offset_.fX, offset_.fY));
// See |EnsureSingleChild|.
FML_DCHECK(layers().size() == 1);
if (context->view_embedder == nullptr && context->raster_cache &&
if (context->raster_cache &&
SkRect::Intersects(context->cull_rect, paint_bounds())) {
Layer* child = layers()[0].get();
SkMatrix ctm = child_matrix;
......@@ -55,12 +62,34 @@ void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
#endif
context->raster_cache->Prepare(context, child, ctm);
}
}
}
void OpacityLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "OpacityLayer::Paint");
FML_DCHECK(needs_painting());
// The compositor will paint this layer (which is |Sk_ColorWHITE| scaled by
// opacity) via the model color on |SceneUpdateContext::Frame|.
//
// The child layers will be painted into the texture used by the Frame, so
// painting them here would actually cause them to be painted on the display
// twice -- once into the current canvas (which may be inside of another
// Frame) and once into the Frame's texture (which is then drawn on top of the
// current canvas).
if (kRenderOpacityUsingSystemCompositor) {
#if defined(OS_FUCHSIA)
// On Fuchsia, If we are being rendered into our own frame using the system
// compositor, then it is neccesary to "punch a hole" in the canvas/frame
// behind us so that single-pass group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
#endif
return;
}
SkPaint paint;
paint.setAlpha(alpha_);
......@@ -72,9 +101,6 @@ void OpacityLayer::Paint(PaintContext& context) const {
context.leaf_nodes_canvas->getTotalMatrix()));
#endif
// See |EnsureSingleChild|.
FML_DCHECK(layers().size() == 1);
// Embedded platform views are changing the canvas in the middle of the paint
// traversal. To make sure we paint on the right canvas, when the embedded
// platform views preview is enabled (context.view_embedded is not null) we
......@@ -105,7 +131,16 @@ void OpacityLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save_layer =
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
PaintChildren(context);
ContainerLayer::Paint(context);
}
void OpacityLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
SceneUpdateContext::Transform transform(
context, SkMatrix::MakeTrans(offset_.fX, offset_.fY));
ContainerLayer::UpdateScene(context);
#endif
}
} // namespace flutter
......@@ -26,29 +26,16 @@ class OpacityLayer : public ContainerLayer {
// to many leaf layers. Therefore we try to capture that offset here to stop
// the propagation as repainting the OpacityLayer is expensive.
OpacityLayer(int alpha, const SkPoint& offset);
~OpacityLayer() override;
~OpacityLayer() override = default;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
// TODO(chinmaygarde): Once SCN-139 is addressed, introduce a new node in the
// session scene hierarchy.
void UpdateScene(SceneUpdateContext& context) override;
private:
int alpha_;
SkPoint offset_;
// Restructure (if necessary) OpacityLayer to have only one child.
//
// This is needed to ensure that retained rendering can always be applied to
// save the costly saveLayer.
//
// If there are multiple children, this creates a new identity TransformLayer,
// sets all children to be the TransformLayer's children, and sets that
// TransformLayer as the single child of this OpacityLayer.
void EnsureSingleChild();
FML_DISALLOW_COPY_AND_ASSIGN(OpacityLayer);
};
......
......@@ -5,38 +5,43 @@
#include "flutter/flow/layers/physical_shape_layer.h"
#include "flutter/flow/paint_utils.h"
#include "include/core/SkColor.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"
namespace flutter {
const SkScalar kLightHeight = 600;
const SkScalar kLightRadius = 800;
constexpr SkScalar kLightHeight = 600;
constexpr SkScalar kLightRadius = 800;
constexpr bool kRenderPhysicalShapeUsingSystemCompositor = false;
PhysicalShapeLayer::PhysicalShapeLayer(SkColor color,
SkColor shadow_color,
SkScalar device_pixel_ratio,
float viewport_depth,
float elevation,
const SkPath& path,
Clip clip_behavior)
: color_(color),
shadow_color_(shadow_color),
device_pixel_ratio_(device_pixel_ratio),
viewport_depth_(viewport_depth),
elevation_(elevation),
path_(path),
isRect_(false),
clip_behavior_(clip_behavior) {
#if !defined(OS_FUCHSIA)
static_assert(!kRenderPhysicalShapeUsingSystemCompositor,
"Delegation of PhysicalShapeLayer to the system compositor is "
"only allowed on Fuchsia");
#endif // !defined(OS_FUCHSIA)
// If rendering as a separate frame using the system compositor, then make
// sure to set up the properties needed to do so.
if (kRenderPhysicalShapeUsingSystemCompositor) {
SkRect rect;
SkRRect frame_rrect;
if (path.isRect(&rect)) {
isRect_ = true;
frameRRect_ = SkRRect::MakeRect(rect);
} else if (path.isRRect(&frameRRect_)) {
isRect_ = frameRRect_.isRect();
frame_rrect = SkRRect::MakeRect(rect);
} else if (path.isRRect(&frame_rrect)) {
// Nothing needed here, as isRRect will fill in frameRRect_ already.
} else if (path.isOval(&rect)) {
// isRRect returns false for ovals, so we need to explicitly check isOval
// as well.
frameRRect_ = SkRRect::MakeOval(rect);
frame_rrect = SkRRect::MakeOval(rect);
} else {
// Scenic currently doesn't provide an easy way to create shapes from
// arbitrary paths.
......@@ -44,27 +49,37 @@ PhysicalShapeLayer::PhysicalShapeLayer(SkColor color,
// 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());
frame_rrect = SkRRect::MakeRect(path.getBounds());
}
}
PhysicalShapeLayer::~PhysicalShapeLayer() = default;
set_frame_properties(frame_rrect, color_, /* opacity */ 1.0f);
}
set_elevation(elevation);
}
void PhysicalShapeLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
context->total_elevation += elevation_;
total_elevation_ = context->total_elevation;
SkRect child_paint_bounds;
PrerollChildren(context, matrix, &child_paint_bounds);
context->total_elevation -= elevation_;
ContainerLayer::Preroll(context, matrix);
if (elevation_ == 0) {
// Compute paint bounds based on the layer's elevation.
set_paint_bounds(path_.getBounds());
} else {
#if defined(OS_FUCHSIA)
// Let the system compositor draw all shadows for us.
if (elevation() == 0) {
return;
}
// If elevation is non-zero, compute the proper paint_bounds to allow drawing
// a shadow.
if (kRenderPhysicalShapeUsingSystemCompositor) {
// Let the system compositor draw all shadows for us, by popping us out as
// a new frame.
set_needs_system_composite(true);
#else
// If the frame behind us is opaque, don't punch a hole in it for group
// opacity.
if (context->is_opaque) {
set_paint_bounds(SkRect());
}
} else {
// Add some margin to the paint bounds to leave space for the shadow.
// We fill this whole region and clip children to it so we don't need to
// join the child paint bounds.
......@@ -100,55 +115,46 @@ void PhysicalShapeLayer::Preroll(PrerollContext* context,
// t = tangent of AOB, i.e., multiplier for elevation to extent
SkRect bounds(path_.getBounds());
// tangent for x
double tx = (kLightRadius * device_pixel_ratio_ + bounds.width() * 0.5) /
double tx = (kLightRadius * context->frame_device_pixel_ratio +
bounds.width() * 0.5) /
kLightHeight;
// tangent for y
double ty = (kLightRadius * device_pixel_ratio_ + bounds.height() * 0.5) /
double ty = (kLightRadius * context->frame_device_pixel_ratio +
bounds.height() * 0.5) /
kLightHeight;
bounds.outset(elevation_ * tx, elevation_ * ty);
bounds.outset(elevation() * tx, elevation() * ty);
set_paint_bounds(bounds);
#endif // defined(OS_FUCHSIA)
}
}
#if defined(OS_FUCHSIA)
void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
// 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)) {
const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
FML_DCHECK(context.top_entity());
FML_DCHECK(retained_node.session() == context.session());
context.top_entity()->entity_node().AddChild(retained_node);
return;
}
// If we can't find an existing retained surface, create one.
SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_,
total_elevation_, viewport_depth_, this);
for (auto& layer : layers()) {
if (layer->needs_painting()) {
frame.AddPaintLayer(layer.get());
}
}
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void PhysicalShapeLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
FML_DCHECK(needs_painting());
if (elevation_ != 0) {
DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
SkColorGetA(color_) != 0xff, device_pixel_ratio_);
// The compositor will paint this layer (which is a solid color) via the
// color on |SceneUpdateContext::Frame|.
//
// The child layers will be painted into the texture used by the Frame, so
// painting them here would actually cause them to be painted on the display
// twice -- once into the current canvas (which may be inside of another
// Frame) and once into the Frame's texture (which is then drawn on top of the
// current canvas).
if (kRenderPhysicalShapeUsingSystemCompositor) {
#if defined(OS_FUCHSIA)
// On Fuchsia, If we are being rendered into our own frame using the system
// compositor, then it is neccesary to "punch a hole" in the canvas/frame
// behind us so that single-pass group opacity looks correct.
SkPaint paint;
paint.setColor(SK_ColorTRANSPARENT);
paint.setBlendMode(SkBlendMode::kSrc);
context.leaf_nodes_canvas->drawRect(paint_bounds(), paint);
#endif
return;
}
if (elevation() != 0) {
DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation(),
SkColorGetA(color_) != 0xff, context.frame_device_pixel_ratio);
}
// Call drawPath without clip if possible for better performance.
......@@ -183,7 +189,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const {
context.leaf_nodes_canvas->drawPaint(paint);
}
PaintChildren(context);
ContainerLayer::Paint(context);
context.internal_nodes_canvas->restoreToCount(saveCount);
}
......
......@@ -13,12 +13,13 @@ class PhysicalShapeLayer : public ContainerLayer {
public:
PhysicalShapeLayer(SkColor color,
SkColor shadow_color,
SkScalar device_pixel_ratio,
float viewport_depth,
float elevation,
const SkPath& path,
Clip clip_behavior);
~PhysicalShapeLayer() override;
~PhysicalShapeLayer() override = default;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
static void DrawShadow(SkCanvas* canvas,
const SkPath& path,
......@@ -27,27 +28,11 @@ class PhysicalShapeLayer : public ContainerLayer {
bool transparentOccluder,
SkScalar dpr);
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkColor color_;
SkColor shadow_color_;
SkScalar device_pixel_ratio_;
float viewport_depth_;
float elevation_ = 0.0f;
float total_elevation_ = 0.0f;
SkPath path_;
bool isRect_;
SkRRect frameRRect_;
Clip clip_behavior_;
friend class PhysicalShapeLayer_TotalElevation_Test;
};
} // namespace flutter
......
......@@ -16,8 +16,6 @@ TEST(PhysicalShapeLayer, TotalElevation) {
for (int i = 0; i < 4; i += 1) {
layers[i] =
std::make_shared<PhysicalShapeLayer>(dummy_color, dummy_color,
1.0f, // pixel ratio,
1.0f, // depth
(float)(i + 1), // elevation
dummy_path, Clip::none);
}
......@@ -40,6 +38,8 @@ TEST(PhysicalShapeLayer, TotalElevation) {
unused_stopwatch, // engine time (dont care)
unused_texture_registry, // texture registry (not supported)
false, // checkerboard_offscreen_layers
6.0f, // depth
1.0f, // pixel ratio
0.0f, // total elevation
};
......@@ -55,14 +55,14 @@ TEST(PhysicalShapeLayer, TotalElevation) {
// | \
// | layers[2] +3.0f
// | |
// | layers[3] +4.0f
// | layers[3] +4.0f (clamped to 6.0f)
// |
// |
// layers[1] + 2.0f
EXPECT_EQ(layers[0]->total_elevation_, 1.0f);
EXPECT_EQ(layers[1]->total_elevation_, 3.0f);
EXPECT_EQ(layers[2]->total_elevation_, 4.0f);
EXPECT_EQ(layers[3]->total_elevation_, 8.0f);
EXPECT_EQ(layers[0]->total_elevation(), 1.0f);
EXPECT_EQ(layers[1]->total_elevation(), 3.0f);
EXPECT_EQ(layers[2]->total_elevation(), 4.0f);
EXPECT_EQ(layers[3]->total_elevation(), 6.0f);
}
} // namespace flutter
......@@ -19,7 +19,7 @@ void ShaderMaskLayer::Paint(PaintContext& context) const {
Layer::AutoSaveLayer save =
Layer::AutoSaveLayer::Create(context, paint_bounds(), nullptr);
PaintChildren(context);
ContainerLayer::Paint(context);
SkPaint paint;
paint.setBlendMode(blend_mode_);
......
......@@ -40,27 +40,14 @@ void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
context->cull_rect = kGiantRect;
}
SkRect child_paint_bounds = SkRect::MakeEmpty();
PrerollChildren(context, child_matrix, &child_paint_bounds);
ContainerLayer::Preroll(context, child_matrix);
transform_.mapRect(&child_paint_bounds);
set_paint_bounds(child_paint_bounds);
transform_.mapRect(paint_bounds());
context->cull_rect = previous_cull_rect;
context->mutators_stack.Pop();
}
#if defined(OS_FUCHSIA)
void TransformLayer::UpdateScene(SceneUpdateContext& context) {
FML_DCHECK(needs_system_composite());
SceneUpdateContext::Transform transform(context, transform_);
UpdateSceneChildren(context);
}
#endif // defined(OS_FUCHSIA)
void TransformLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "TransformLayer::Paint");
FML_DCHECK(needs_painting());
......@@ -68,7 +55,17 @@ void TransformLayer::Paint(PaintContext& context) const {
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->concat(transform_);
PaintChildren(context);
ContainerLayer::Paint(context);
}
void TransformLayer::UpdateScene(SceneUpdateContext& context) {
#if defined(OS_FUCHSIA)
FML_DCHECK(needs_system_composite());
SceneUpdateContext::Transform transform(context, transform_);
ContainerLayer::UpdateScene(context);
#endif // defined(OS_FUCHSIA)
}
} // namespace flutter
......@@ -17,12 +17,8 @@ class TransformLayer : public ContainerLayer {
~TransformLayer() override;
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
void Paint(PaintContext& context) const override;
#if defined(OS_FUCHSIA)
void UpdateScene(SceneUpdateContext& context) override;
#endif // defined(OS_FUCHSIA)
private:
SkMatrix transform_;
......
......@@ -173,7 +173,9 @@ void RasterCache::Prepare(PrerollContext* context,
context->ui_time,
context->texture_registry,
context->raster_cache,
context->checkerboard_offscreen_layers};
context->checkerboard_offscreen_layers,
context->frame_physical_depth,
context->frame_device_pixel_ratio};
if (layer->needs_painting()) {
layer->Paint(paintContext);
}
......
......@@ -7,6 +7,7 @@
#include "flutter/flow/layers/layer.h"
#include "flutter/flow/matrix_decomposition.h"
#include "flutter/fml/trace_event.h"
#include "include/core/SkColor.h"
namespace flutter {
......@@ -59,14 +60,10 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node,
scenic::ShapeNode shape_node,
const SkRRect& rrect,
SkColor color,
float opacity,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers,
Layer* layer) {
// Frames always clip their children.
SetEntityNodeClipPlanes(entity_node, rrect.getBounds());
// TODO(SCN-1274): SetClip() will be deleted.
entity_node.SetClip(0u, true /* clip to self */);
// We don't need a shape if the frame is zero size.
if (rrect.isEmpty())
return;
......@@ -95,7 +92,9 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node,
// Check whether a solid color will suffice.
if (paint_layers.empty()) {
SetShapeColor(shape_node, color);
scenic::Material material(session_);
SetMaterialColor(material, color, opacity);
shape_node.SetMaterial(material);
return;
}
......@@ -103,43 +102,38 @@ void SceneUpdateContext::CreateFrame(scenic::EntityNode entity_node,
const float scale_x = ScaleX();
const float scale_y = ScaleY();
// Apply a texture to the whole shape.
SetShapeTextureAndColor(shape_node, color, scale_x, scale_y, shape_bounds,
std::move(paint_layers), layer,
std::move(entity_node));
}
void SceneUpdateContext::SetShapeTextureAndColor(
scenic::ShapeNode& shape_node,
SkColor color,
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,
color, scale_x, scale_y, shape_bounds, std::move(paint_layers), layer,
std::move(entity_node));
if (image != nullptr) {
scenic::Material material(session_);
// 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);
material.SetTexture(*image);
shape_node.SetMaterial(material);
return;
}
SetShapeColor(shape_node, color);
}
// No texture was needed, so apply a solid color to the whole shape.
if (SkColorGetA(color) != 0 && opacity != 0.0f) {
scenic::Material material(session_);
void SceneUpdateContext::SetShapeColor(scenic::ShapeNode& shape_node,
SkColor color) {
if (SkColorGetA(color) == 0)
SetMaterialColor(material, color, opacity);
shape_node.SetMaterial(material);
return;
}
}
scenic::Material material(session_);
void SceneUpdateContext::SetMaterialColor(scenic::Material& material,
SkColor color,
float opacity) {
const SkAlpha color_alpha = (SkAlpha)(SkColorGetA(color) * opacity);
material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
SkColorGetA(color));
shape_node.SetMaterial(material);
color_alpha);
}
scenic::Image* SceneUpdateContext::GenerateImageIfNeeded(
......@@ -205,7 +199,9 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
frame.context().ui_time(),
frame.context().texture_registry(),
&frame.context().raster_cache(),
false};
false,
frame_physical_depth_,
frame_device_pixel_ratio_};
canvas->restoreToCount(1);
canvas->save();
canvas->clear(task.background_color);
......@@ -284,43 +280,38 @@ SceneUpdateContext::Transform::~Transform() {
context().top_scale_y_ = previous_scale_y_;
}
SceneUpdateContext::Shape::Shape(SceneUpdateContext& context)
: Entity(context), shape_node_(context.session()) {
entity_node().AddChild(shape_node_);
SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
const SkRect& shape_bounds)
: Entity(context) {
SetEntityNodeClipPlanes(entity_node(), shape_bounds);
}
SceneUpdateContext::Frame::Frame(SceneUpdateContext& context,
const SkRRect& rrect,
SkColor color,
float local_elevation,
float world_elevation,
float depth,
float opacity,
float elevation,
Layer* layer)
: Shape(context),
: Entity(context),
opacity_node_(context.session()),
shape_node_(context.session()),
layer_(layer),
rrect_(rrect),
color_(color),
paint_bounds_(SkRect::MakeEmpty()),
layer_(layer) {
if (depth > -1 && world_elevation > depth) {
// TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be
// able to have developers specify the behavior here to alternatives besides
// clamping, like normalization on some arbitrary curve.
// Clamp the local z coordinate at our max bound. Take into account the
// parent z position here to fix clamping in cases where the child is
// overflowing because of its parents.
const float parent_elevation = world_elevation - local_elevation;
local_elevation = depth - parent_elevation;
}
if (local_elevation != 0.0) {
entity_node().SetTranslation(0.f, 0.f, -local_elevation);
}
color_(color),
opacity_(opacity) {
entity_node().SetTranslation(0.f, 0.f, -elevation);
SetEntityNodeClipPlanes(entity_node(), rrect_.getBounds());
entity_node().AddChild(opacity_node_);
entity_node().AddChild(shape_node_);
opacity_node_.SetOpacity(opacity_);
}
SceneUpdateContext::Frame::~Frame() {
context().CreateFrame(std::move(entity_node()), std::move(shape_node()),
rrect_, color_, paint_bounds_, std::move(paint_layers_),
layer_);
context().CreateFrame(std::move(entity_node()), std::move(shape_node_),
rrect_, color_, opacity_, paint_bounds_,
std::move(paint_layers_), layer_);
}
void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) {
......@@ -329,10 +320,4 @@ void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) {
paint_bounds_.join(layer->paint_bounds());
}
SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
const SkRect& shape_bounds)
: Entity(context) {
SetEntityNodeClipPlanes(entity_node(), shape_bounds);
}
} // namespace flutter
......@@ -5,6 +5,7 @@
#ifndef FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
#define FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
#if defined(OS_FUCHSIA) || defined(__Fuchsia__)
#include <memory>
#include <set>
#include <vector>
......@@ -14,10 +15,11 @@
#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"
#include <lib/ui/scenic/cpp/resources.h>
namespace flutter {
class Layer;
......@@ -89,25 +91,20 @@ class SceneUpdateContext {
float scale_x,
float scale_y,
float scale_z);
virtual ~Transform();
~Transform() override;
private:
float const previous_scale_x_;
float const previous_scale_y_;
};
class Shape : public Entity {
class Clip : public Entity {
public:
Shape(SceneUpdateContext& context);
virtual ~Shape() = default;
scenic::ShapeNode& shape_node() { return shape_node_; }
private:
scenic::ShapeNode shape_node_;
Clip(SceneUpdateContext& context, const SkRect& shape_bounds);
~Clip() override = default;
};
class Frame : public Shape {
class Frame : public Entity {
public:
// When layer is not nullptr, the frame is associated with a layer subtree
// rooted with that layer. The frame may then create a surface that will be
......@@ -115,27 +112,25 @@ class SceneUpdateContext {
Frame(SceneUpdateContext& context,
const SkRRect& rrect,
SkColor color,
float local_elevation = 0.0f,
float parent_elevation = 0.0f,
float depth = 0.0f,
float opacity = 1.0f,
float elevation = 0.0f,
Layer* layer = nullptr);
virtual ~Frame();
~Frame() override;
scenic::ContainerNode& embedder_node() override { return opacity_node_; }
void AddPaintLayer(Layer* layer);
private:
const SkRRect& rrect_;
SkColor const color_;
scenic::OpacityNodeHACK opacity_node_;
scenic::ShapeNode shape_node_;
std::vector<Layer*> paint_layers_;
SkRect paint_bounds_;
Layer* layer_;
};
class Clip : public Entity {
public:
Clip(SceneUpdateContext& context, const SkRect& shape_bounds);
~Clip() = default;
SkRRect rrect_;
SkRect paint_bounds_;
SkColor color_;
float opacity_;
};
SceneUpdateContext(scenic::Session* session,
......@@ -152,6 +147,17 @@ class SceneUpdateContext {
}
const fuchsia::ui::gfx::MetricsPtr& metrics() const { return metrics_; }
void set_frame_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
......@@ -197,6 +203,7 @@ class SceneUpdateContext {
scenic::ShapeNode shape_node,
const SkRRect& rrect,
SkColor color,
float opacity,
const SkRect& paint_bounds,
std::vector<Layer*> paint_layers,
Layer* layer);
......@@ -208,7 +215,9 @@ class SceneUpdateContext {
std::vector<Layer*> paint_layers,
Layer* layer,
scenic::EntityNode entity_node);
void SetShapeColor(scenic::ShapeNode& shape_node, SkColor color);
void SetMaterialColor(scenic::Material& material,
SkColor color,
float opacity);
scenic::Image* GenerateImageIfNeeded(SkColor color,
SkScalar scale_x,
SkScalar scale_y,
......@@ -225,6 +234,10 @@ class SceneUpdateContext {
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.
std::vector<PaintTask> paint_tasks_;
......@@ -232,5 +245,10 @@ class SceneUpdateContext {
};
} // namespace flutter
#else
namespace flutter {
class SceneUpdateContext;
}
#endif // defined(OS_FUCHSIA)
#endif // FLUTTER_FLOW_SCENE_UPDATE_CONTEXT_H_
......@@ -4,7 +4,9 @@
#include "flutter/flow/view_holder.h"
#include "flutter/flow/embedded_views.h"
#include "flutter/fml/thread_local.h"
#include "lib/ui/scenic/cpp/resources.h"
namespace {
......@@ -104,14 +106,11 @@ void ViewHolder::UpdateScene(SceneUpdateContext& context,
const SkSize& size,
bool hit_testable) {
if (pending_view_holder_token_.value) {
opacity_node_ =
std::make_unique<scenic::OpacityNodeHACK>(context.session());
entity_node_ = std::make_unique<scenic::EntityNode>(context.session());
view_holder_ = std::make_unique<scenic::ViewHolder>(
context.session(), std::move(pending_view_holder_token_),
"Flutter SceneHost");
opacity_node_->AddChild(*entity_node_);
entity_node_->Attach(*view_holder_);
ui_task_runner_->PostTask(
[bind_callback = std::move(pending_bind_callback_),
......@@ -119,20 +118,18 @@ void ViewHolder::UpdateScene(SceneUpdateContext& context,
bind_callback(view_holder_id);
});
}
FML_DCHECK(opacity_node_);
FML_DCHECK(entity_node_);
FML_DCHECK(view_holder_);
context.top_entity()->entity_node().AddChild(*opacity_node_);
context.top_entity()->embedder_node().AddChild(*entity_node_);
entity_node_->SetTranslation(offset.x(), offset.y(), -0.1f);
entity_node_->SetHitTestBehavior(
hit_testable ? fuchsia::ui::gfx::HitTestBehavior::kDefault
: fuchsia::ui::gfx::HitTestBehavior::kSuppress);
if (has_pending_opacity_) {
opacity_node_->SetOpacity(pending_opacity_);
has_pending_opacity_ = false;
}
if (has_pending_properties_) {
// TODO(dworsham): This should be derived from size and elevation. We
// should be able to Z-limit the view's box but otherwise it uses all of the
// available airspace.
view_holder_->SetViewProperties(std::move(pending_properties_));
has_pending_properties_ = false;
......@@ -151,9 +148,4 @@ void ViewHolder::SetProperties(double width,
has_pending_properties_ = true;
}
void ViewHolder::SetOpacity(double opacity) {
pending_opacity_ = std::clamp(opacity, 0.0, 1.0);
has_pending_opacity_ = true;
}
} // namespace flutter
......@@ -51,7 +51,6 @@ class ViewHolder {
double insetBottom,
double insetLeft,
bool focusable);
void SetOpacity(double opacity);
// Creates or updates the contained ViewHolder resource using the specified
// |SceneUpdateContext|.
......@@ -63,7 +62,6 @@ class ViewHolder {
private:
fml::RefPtr<fml::TaskRunner> ui_task_runner_;
std::unique_ptr<scenic::OpacityNodeHACK> opacity_node_;
std::unique_ptr<scenic::EntityNode> entity_node_;
std::unique_ptr<scenic::ViewHolder> view_holder_;
......@@ -71,9 +69,7 @@ class ViewHolder {
BindCallback pending_bind_callback_;
fuchsia::ui::gfx::ViewProperties pending_properties_;
double pending_opacity_;
bool has_pending_properties_ = false;
bool has_pending_opacity_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(ViewHolder);
};
......
......@@ -694,13 +694,6 @@ class SceneHost extends NativeFieldWrapperClass2 {
void Function(bool) viewStateChangedCallback) {
_constructor(viewHolderToken, viewConnectedCallback, viewDisconnectedCallback, viewStateChangedCallback);
}
SceneHost.fromViewHolderToken(
dynamic viewHolderToken,
void Function() viewConnectedCallback,
void Function() viewDisconnectedCallback,
void Function(bool) viewStateChangedCallback) {
_constructor(viewHolderToken, viewConnectedCallback, viewDisconnectedCallback, viewStateChangedCallback);
}
void _constructor(dynamic viewHolderToken, void Function() viewConnectedCallback, void Function() viewDisconnectedCallback, void Function(bool) viewStateChangedCallback)
native 'SceneHost_constructor';
......@@ -720,8 +713,4 @@ class SceneHost extends NativeFieldWrapperClass2 {
double insetBottom,
double insetLeft,
bool focusable) native 'SceneHost_setProperties';
/// Set the opacity of the linked scene. This opacity value is applied only
/// once, when the child scene is composited into our own.
void setOpacity(double opacity) native 'SceneHost_setOpacity';
}
......@@ -7,6 +7,8 @@
#include "flutter/fml/trace_event.h"
#include "flutter/lib/ui/painting/image.h"
#include "flutter/lib/ui/painting/picture.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/window.h"
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/tonic/converter/dart_converter.h"
......@@ -36,13 +38,19 @@ fml::RefPtr<Scene> Scene::create(std::shared_ptr<flutter::Layer> rootLayer,
Scene::Scene(std::shared_ptr<flutter::Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers)
: m_layerTree(new flutter::LayerTree()) {
m_layerTree->set_root_layer(std::move(rootLayer));
m_layerTree->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
m_layerTree->set_checkerboard_raster_cache_images(
bool checkerboardOffscreenLayers) {
auto viewport_metrics = UIDartState::Current()->window()->viewport_metrics();
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);
layer_tree_->set_checkerboard_raster_cache_images(
checkerboardRasterCacheImages);
m_layerTree->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
layer_tree_->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
}
Scene::~Scene() {}
......@@ -56,11 +64,11 @@ Dart_Handle Scene::toImage(uint32_t width,
Dart_Handle raw_image_callback) {
TRACE_EVENT0("flutter", "Scene::toImage");
if (!m_layerTree) {
if (!layer_tree_) {
return tonic::ToDart("Scene did not contain a layer tree.");
}
auto picture = m_layerTree->Flatten(SkRect::MakeWH(width, height));
auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height));
if (!picture) {
return tonic::ToDart("Could not flatten scene into a layer tree.");
}
......@@ -69,7 +77,7 @@ Dart_Handle Scene::toImage(uint32_t width,
}
std::unique_ptr<flutter::LayerTree> Scene::takeLayerTree() {
return std::move(m_layerTree);
return std::move(layer_tree_);
}
} // namespace flutter
......@@ -45,7 +45,7 @@ class Scene : public RefCountedDartWrappable<Scene> {
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers);
std::unique_ptr<flutter::LayerTree> m_layerTree;
std::unique_ptr<flutter::LayerTree> layer_tree_;
};
} // namespace flutter
......
......@@ -23,8 +23,6 @@
#include "flutter/fml/build_config.h"
#include "flutter/lib/ui/painting/matrix.h"
#include "flutter/lib/ui/painting/shader.h"
#include "flutter/lib/ui/ui_dart_state.h"
#include "flutter/lib/ui/window/window.h"
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
......@@ -176,12 +174,6 @@ fml::RefPtr<EngineLayer> SceneBuilder::pushPhysicalShape(const CanvasPath* path,
int clipBehavior) {
auto layer = std::make_shared<flutter::PhysicalShapeLayer>(
static_cast<SkColor>(color), static_cast<SkColor>(shadow_color),
static_cast<float>(UIDartState::Current()
->window()
->viewport_metrics()
.device_pixel_ratio),
static_cast<float>(
UIDartState::Current()->window()->viewport_metrics().physical_depth),
static_cast<float>(elevation), path->path(),
static_cast<flutter::Clip>(clipBehavior));
PushLayer(layer);
......
......@@ -87,8 +87,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneHost);
#define FOR_EACH_BINDING(V) \
V(SceneHost, dispose) \
V(SceneHost, setProperties) \
V(SceneHost, setOpacity)
V(SceneHost, setProperties)
FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
......@@ -205,13 +204,4 @@ void SceneHost::setProperties(double width,
});
}
void SceneHost::setOpacity(double opacity) {
gpu_task_runner_->PostTask([id = koid_, opacity]() {
auto* view_holder = flutter::ViewHolder::FromId(id);
FML_DCHECK(view_holder);
view_holder->SetOpacity(opacity);
});
}
} // namespace flutter
......@@ -49,7 +49,6 @@ class SceneHost : public RefCountedDartWrappable<SceneHost> {
double insetBottom,
double insetLeft,
bool focusable);
void setOpacity(double opacity);
private:
fml::RefPtr<fml::TaskRunner> gpu_task_runner_;
......
......@@ -39,6 +39,10 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
physical_system_gesture_inset_bottom(
p_physical_system_gesture_inset_bottom),
physical_system_gesture_inset_left(p_physical_system_gesture_inset_left) {
// 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,
......@@ -68,7 +72,12 @@ ViewportMetrics::ViewportMetrics(double p_device_pixel_ratio,
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) {}
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(const ViewportMetrics& other) = default;
......
......@@ -7,6 +7,8 @@
#include <stdint.h>
#include "flutter/fml/logging.h"
namespace flutter {
// This is the value of double.maxFinite from dart:core.
......
......@@ -607,12 +607,6 @@ class SceneHost {
void Function() viewDisconnectedCallback,
void Function(bool) viewStateChangedCallback);
SceneHost.fromViewHolderToken(
dynamic viewHolderToken,
void Function() viewConnectedCallback,
void Function() viewDisconnectedCallback,
void Function(bool) viewStateChangedCallback);
/// Releases the resources associated with the SceneHost.
///
/// After calling this function, the SceneHost cannot be used further.
......@@ -624,10 +618,4 @@ class SceneHost {
double insetRight, double insetBottom, double insetLeft, bool focusable) {
throw UnimplementedError();
}
/// Set the opacity of the linked scene. This opacity value is applied only
/// once, when the child scene is composited into our own.
void setOpacity(double opacity) {
throw UnimplementedError();
}
}
......@@ -427,12 +427,12 @@ void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
if (!layer_tree)
return;
SkISize frame_size = SkISize::Make(viewport_metrics_.physical_width,
viewport_metrics_.physical_height);
if (frame_size.isEmpty())
// Ensure frame dimensions are sane.
if (layer_tree->frame_size().isEmpty() ||
layer_tree->frame_physical_depth() <= 0.0f ||
layer_tree->frame_device_pixel_ratio() <= 0.0f)
return;
layer_tree->set_frame_size(frame_size);
animator_->Render(std::move(layer_tree));
}
......
......@@ -121,7 +121,8 @@ void ShellTest::PumpOneFrame(Shell* shell) {
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
[&latch, runtime_delegate]() {
auto layer_tree = std::make_unique<LayerTree>();
auto layer_tree = std::make_unique<LayerTree>(
SkISize::Make(1, 1), static_cast<float>(kUnsetDepth), 1.0f);
SkMatrix identity;
identity.setIdentity();
auto root_layer = std::make_shared<TransformLayer>(identity);
......
......@@ -644,6 +644,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -735,6 +736,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -826,6 +828,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1117,6 +1120,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1294,6 +1298,7 @@ TEST_F(EmbedderTest,
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1414,7 +1419,7 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1492,6 +1497,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1604,6 +1610,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1787,6 +1794,7 @@ TEST_F(EmbedderTest,
// Flutter still thinks it is 800 x 600. Only the root surface is rotated.
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
......@@ -1821,6 +1829,7 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositor) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -1863,6 +1872,7 @@ TEST_F(EmbedderTest, CanRenderSceneWithoutCustomCompositorWithTransformation) {
// Flutter still thinks it is 800 x 600.
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -1897,6 +1907,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithoutCompositor) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -1939,6 +1950,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithoutCompositorWithXform) {
// Flutter still thinks it is 800 x 600.
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -1973,6 +1985,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositor) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -2016,6 +2029,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorWithXform) {
// Flutter still thinks it is 800 x 600.
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -2126,6 +2140,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayer) {
event.struct_size = sizeof(event);
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......@@ -2245,6 +2260,7 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
// Flutter still thinks it is 800 x 600.
event.width = 800;
event.height = 600;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册