mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
This reverts commit fcc4ab3230.
Fixes https://github.com/flutter/flutter/issues/41394 and other
related correctness issues.
TBR: @arbreng @jason-simmons @mehmetf
This commit is contained in:
@@ -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});
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(context);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -19,25 +19,10 @@ 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 {
|
||||
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);
|
||||
FML_NOTREACHED() << "This layer never needs painting.";
|
||||
}
|
||||
|
||||
void ChildSceneLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
#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)
|
||||
@@ -18,18 +24,29 @@ 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_);
|
||||
ContainerLayer::Preroll(context, matrix);
|
||||
SkRect child_paint_bounds = SkRect::MakeEmpty();
|
||||
PrerollChildren(context, matrix, &child_paint_bounds);
|
||||
|
||||
if (clip_path_bounds.intersect(paint_bounds())) {
|
||||
set_paint_bounds(clip_path_bounds);
|
||||
} else {
|
||||
set_paint_bounds(SkRect::MakeEmpty());
|
||||
if (child_paint_bounds.intersect(clip_path_bounds)) {
|
||||
set_paint_bounds(child_paint_bounds);
|
||||
}
|
||||
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());
|
||||
@@ -41,21 +58,10 @@ void ClipPathLayer::Paint(PaintContext& context) const {
|
||||
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
|
||||
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
|
||||
}
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(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,8 +15,12 @@ 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,21 +15,31 @@ ClipRectLayer::~ClipRectLayer() = default;
|
||||
|
||||
void ClipRectLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
SkRect previous_cull_rect = context->cull_rect;
|
||||
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 (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 (clip_rect_bounds.intersect(paint_bounds())) {
|
||||
set_paint_bounds(clip_rect_bounds);
|
||||
} else {
|
||||
set_paint_bounds(SkRect::MakeEmpty());
|
||||
if (child_paint_bounds.intersect(clip_rect_)) {
|
||||
set_paint_bounds(child_paint_bounds);
|
||||
}
|
||||
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());
|
||||
@@ -41,21 +51,10 @@ void ClipRectLayer::Paint(PaintContext& context) const {
|
||||
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
|
||||
context.internal_nodes_canvas->saveLayer(clip_rect_, nullptr);
|
||||
}
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(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,7 +16,10 @@ 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,18 +18,29 @@ 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_);
|
||||
ContainerLayer::Preroll(context, matrix);
|
||||
SkRect child_paint_bounds = SkRect::MakeEmpty();
|
||||
PrerollChildren(context, matrix, &child_paint_bounds);
|
||||
|
||||
if (clip_rrect_bounds.intersect(paint_bounds())) {
|
||||
set_paint_bounds(clip_rrect_bounds);
|
||||
} else {
|
||||
set_paint_bounds(SkRect::MakeEmpty());
|
||||
if (child_paint_bounds.intersect(clip_rrect_bounds)) {
|
||||
set_paint_bounds(child_paint_bounds);
|
||||
}
|
||||
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());
|
||||
@@ -41,21 +52,10 @@ void ClipRRectLayer::Paint(PaintContext& context) const {
|
||||
if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
|
||||
context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
|
||||
}
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(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,8 +15,12 @@ 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);
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(context);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -4,44 +4,13 @@
|
||||
|
||||
#include "flutter/flow/layers/container_layer.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "flutter/flow/layers/transform_layer.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
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() {}
|
||||
|
||||
return clamped_elevation;
|
||||
}
|
||||
ContainerLayer::~ContainerLayer() = default;
|
||||
|
||||
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));
|
||||
}
|
||||
@@ -49,29 +18,25 @@ void ContainerLayer::Add(std::shared_ptr<Layer> layer) {
|
||||
void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) {
|
||||
TRACE_EVENT0("flutter", "ContainerLayer::Preroll");
|
||||
|
||||
// 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_;
|
||||
|
||||
SkRect child_paint_bounds = SkRect::MakeEmpty();
|
||||
PrerollChildren(context, matrix, &child_paint_bounds);
|
||||
set_paint_bounds(child_paint_bounds);
|
||||
}
|
||||
|
||||
void ContainerLayer::PrerollChildren(PrerollContext* context,
|
||||
const SkMatrix& child_matrix,
|
||||
SkRect* child_paint_bounds) {
|
||||
for (auto& layer : layers_) {
|
||||
layer->Preroll(context, matrix);
|
||||
layer->Preroll(context, child_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::Paint(PaintContext& context) const {
|
||||
void ContainerLayer::PaintChildren(PaintContext& context) const {
|
||||
FML_DCHECK(needs_painting());
|
||||
|
||||
// Intentionally not tracing here as there should be no self-time
|
||||
@@ -83,45 +48,24 @@ void ContainerLayer::Paint(PaintContext& context) const {
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
#if defined(OS_FUCHSIA)
|
||||
if (should_render_as_frame()) {
|
||||
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 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)
|
||||
void ContainerLayer::UpdateScene(SceneUpdateContext& context) {
|
||||
UpdateSceneChildren(context);
|
||||
}
|
||||
|
||||
void ContainerLayer::UpdateSceneChildren(SceneUpdateContext& context) {
|
||||
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_) {
|
||||
if (layer->needs_system_composite()) {
|
||||
layer->UpdateScene(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -5,56 +5,41 @@
|
||||
#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(bool force_single_child = false);
|
||||
~ContainerLayer() override = default;
|
||||
ContainerLayer();
|
||||
~ContainerLayer() override;
|
||||
|
||||
void Add(std::shared_ptr<Layer> layer);
|
||||
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
void Paint(PaintContext& context) const override;
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
void UpdateScene(SceneUpdateContext& context) override;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
const std::vector<std::shared_ptr<Layer>>& layers() const { return layers_; }
|
||||
|
||||
protected:
|
||||
void PrerollChildren(PrerollContext* context,
|
||||
const SkMatrix& child_matrix,
|
||||
SkRect* child_paint_bounds);
|
||||
void PaintChildren(PaintContext& context) const;
|
||||
|
||||
#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(); }
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
+14
-10
@@ -7,9 +7,17 @@
|
||||
#include "flutter/flow/paint_utils.h"
|
||||
#include "third_party/skia/include/core/SkColorFilter.h"
|
||||
|
||||
namespace {
|
||||
namespace flutter {
|
||||
|
||||
uint64_t NextUniqueID() {
|
||||
Layer::Layer()
|
||||
: parent_(nullptr),
|
||||
needs_system_composite_(false),
|
||||
paint_bounds_(SkRect::MakeEmpty()),
|
||||
unique_id_(NextUniqueID()) {}
|
||||
|
||||
Layer::~Layer() = default;
|
||||
|
||||
uint64_t Layer::NextUniqueID() {
|
||||
static std::atomic<uint64_t> nextID(1);
|
||||
uint64_t id;
|
||||
do {
|
||||
@@ -18,15 +26,11 @@ uint64_t NextUniqueID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {}
|
||||
|
||||
namespace flutter {
|
||||
|
||||
Layer::Layer()
|
||||
: parent_(nullptr),
|
||||
paint_bounds_(SkRect::MakeEmpty()),
|
||||
unique_id_(NextUniqueID()),
|
||||
needs_system_composite_(false) {}
|
||||
#if defined(OS_FUCHSIA)
|
||||
void Layer::UpdateScene(SceneUpdateContext& context) {}
|
||||
#endif // defined(OS_FUCHSIA)
|
||||
|
||||
Layer::AutoSaveLayer::AutoSaveLayer(const PaintContext& paint_context,
|
||||
const SkRect& bounds,
|
||||
|
||||
+21
-23
@@ -11,7 +11,6 @@
|
||||
#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"
|
||||
@@ -28,6 +27,14 @@
|
||||
#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);
|
||||
@@ -36,7 +43,6 @@ 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;
|
||||
@@ -51,15 +57,7 @@ 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
|
||||
@@ -67,7 +65,9 @@ struct PrerollContext {
|
||||
class Layer {
|
||||
public:
|
||||
Layer();
|
||||
virtual ~Layer() = default;
|
||||
virtual ~Layer();
|
||||
|
||||
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
|
||||
|
||||
struct PaintContext {
|
||||
// When splitting the scene into multiple canvases (e.g when embedding
|
||||
@@ -89,10 +89,6 @@ 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
|
||||
@@ -122,18 +118,15 @@ 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) {}
|
||||
virtual void UpdateScene(SceneUpdateContext& context);
|
||||
#endif
|
||||
|
||||
ContainerLayer* parent() const { return parent_; }
|
||||
|
||||
void set_parent(ContainerLayer* parent) { parent_ = parent; }
|
||||
|
||||
bool needs_system_composite() const { return needs_system_composite_; }
|
||||
@@ -142,6 +135,9 @@ 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;
|
||||
}
|
||||
@@ -152,9 +148,11 @@ class Layer {
|
||||
|
||||
private:
|
||||
ContainerLayer* parent_;
|
||||
bool needs_system_composite_;
|
||||
SkRect paint_bounds_;
|
||||
uint64_t unique_id_;
|
||||
bool needs_system_composite_;
|
||||
|
||||
static uint64_t NextUniqueID();
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Layer);
|
||||
};
|
||||
|
||||
+44
-69
@@ -9,18 +9,10 @@
|
||||
#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(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),
|
||||
LayerTree::LayerTree()
|
||||
: frame_size_{},
|
||||
rasterizer_tracing_threshold_(0),
|
||||
checkerboard_raster_cache_images_(false),
|
||||
checkerboard_offscreen_layers_(false) {}
|
||||
@@ -50,13 +42,36 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
|
||||
frame.context().raster_time(),
|
||||
frame.context().ui_time(),
|
||||
frame.context().texture_registry(),
|
||||
checkerboard_offscreen_layers_,
|
||||
frame_physical_depth_,
|
||||
frame_device_pixel_ratio_};
|
||||
checkerboard_offscreen_layers_};
|
||||
|
||||
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");
|
||||
@@ -79,9 +94,7 @@ 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_,
|
||||
frame_physical_depth_,
|
||||
frame_device_pixel_ratio_};
|
||||
checkerboard_offscreen_layers_};
|
||||
|
||||
if (root_layer_->needs_painting())
|
||||
root_layer_->Paint(context);
|
||||
@@ -105,18 +118,16 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
|
||||
root_surface_transformation.reset();
|
||||
|
||||
PrerollContext preroll_context{
|
||||
nullptr, // raster_cache (don't consult the cache)
|
||||
nullptr, // gr_context (used for the raster cache)
|
||||
nullptr, // external view embedder
|
||||
unused_stack, // mutator stack
|
||||
nullptr, // SkColorSpace* dst_color_space
|
||||
kGiantRect, // SkRect cull_rect
|
||||
unused_stopwatch, // frame time (dont care)
|
||||
unused_stopwatch, // engine time (dont care)
|
||||
unused_texture_registry, // texture registry (not supported)
|
||||
false, // checkerboard_offscreen_layers
|
||||
frame_physical_depth_, // maximum depth allowed for rendering
|
||||
frame_device_pixel_ratio_ // ratio between logical and physical
|
||||
nullptr, // raster_cache (don't consult the cache)
|
||||
nullptr, // gr_context (used for the raster cache)
|
||||
nullptr, // external view embedder
|
||||
unused_stack, // mutator stack
|
||||
nullptr, // SkColorSpace* dst_color_space
|
||||
kGiantRect, // SkRect cull_rect
|
||||
unused_stopwatch, // frame time (dont care)
|
||||
unused_stopwatch, // engine time (dont care)
|
||||
unused_texture_registry, // texture registry (not supported)
|
||||
false, // checkerboard_offscreen_layers
|
||||
};
|
||||
|
||||
SkISize canvas_size = canvas->getBaseLayerSize();
|
||||
@@ -128,13 +139,11 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
|
||||
canvas, // canvas
|
||||
nullptr,
|
||||
nullptr,
|
||||
unused_stopwatch, // frame time (dont care)
|
||||
unused_stopwatch, // engine time (dont care)
|
||||
unused_texture_registry, // texture registry (not supported)
|
||||
nullptr, // raster cache
|
||||
false, // checkerboard offscreen layers
|
||||
frame_physical_depth_, // maximum depth allowed for rendering
|
||||
frame_device_pixel_ratio_ // ratio between logical and physical
|
||||
unused_stopwatch, // frame time (dont care)
|
||||
unused_stopwatch, // engine time (dont care)
|
||||
unused_texture_registry, // texture registry (not supported)
|
||||
nullptr, // raster cache
|
||||
false // checkerboard offscreen layers
|
||||
};
|
||||
|
||||
// Even if we don't have a root layer, we still need to create an empty
|
||||
@@ -150,38 +159,4 @@ 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
|
||||
|
||||
+14
-18
@@ -16,37 +16,36 @@
|
||||
#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(const SkISize& frame_size,
|
||||
float frame_physical_depth,
|
||||
float frame_device_pixel_ratio);
|
||||
LayerTree();
|
||||
|
||||
~LayerTree();
|
||||
|
||||
void Preroll(CompositorContext::ScopedFrame& frame,
|
||||
bool ignore_raster_cache = false);
|
||||
void Paint(CompositorContext::ScopedFrame& frame,
|
||||
bool ignore_raster_cache = false) const;
|
||||
sk_sp<SkPicture> Flatten(const SkRect& bounds);
|
||||
|
||||
#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);
|
||||
|
||||
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_; }
|
||||
float frame_physical_depth() const { return frame_physical_depth_; }
|
||||
float frame_device_pixel_ratio() const { return frame_device_pixel_ratio_; }
|
||||
|
||||
void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; }
|
||||
|
||||
void RecordBuildTime(fml::TimePoint begin_start);
|
||||
fml::TimePoint build_start() const { return build_start_; }
|
||||
@@ -73,13 +72,10 @@ 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,64 +4,56 @@
|
||||
|
||||
#include "flutter/flow/layers/opacity_layer.h"
|
||||
|
||||
#include "flutter/flow/layers/transform_layer.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
constexpr bool kRenderOpacityUsingSystemCompositor = true;
|
||||
#else
|
||||
constexpr bool kRenderOpacityUsingSystemCompositor = false;
|
||||
#endif
|
||||
constexpr float kOpacityElevationWhenUsingSystemCompositor = 0.01f;
|
||||
|
||||
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
|
||||
: alpha_(alpha), offset_(offset) {}
|
||||
|
||||
if (kRenderOpacityUsingSystemCompositor) {
|
||||
set_elevation(kOpacityElevationWhenUsingSystemCompositor);
|
||||
OpacityLayer::~OpacityLayer() = default;
|
||||
|
||||
void OpacityLayer::EnsureSingleChild() {
|
||||
FML_DCHECK(layers().size() > 0); // OpacityLayer should never be a leaf
|
||||
|
||||
if (layers().size() == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
for (auto& child : layers()) {
|
||||
new_child->Add(child);
|
||||
}
|
||||
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));
|
||||
if (context->raster_cache &&
|
||||
SkRect::Intersects(context->cull_rect, paint_bounds())) {
|
||||
Layer* child = layers()[0].get();
|
||||
SkMatrix ctm = child_matrix;
|
||||
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 &&
|
||||
SkRect::Intersects(context->cull_rect, paint_bounds())) {
|
||||
Layer* child = layers()[0].get();
|
||||
SkMatrix ctm = child_matrix;
|
||||
#ifndef SUPPORT_FRACTIONAL_TRANSLATION
|
||||
ctm = RasterCache::GetIntegralTransCTM(ctm);
|
||||
ctm = RasterCache::GetIntegralTransCTM(ctm);
|
||||
#endif
|
||||
context->raster_cache->Prepare(context, child, ctm);
|
||||
}
|
||||
context->raster_cache->Prepare(context, child, ctm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,27 +61,6 @@ 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_);
|
||||
|
||||
@@ -101,6 +72,9 @@ 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
|
||||
@@ -131,16 +105,7 @@ void OpacityLayer::Paint(PaintContext& context) const {
|
||||
|
||||
Layer::AutoSaveLayer save_layer =
|
||||
Layer::AutoSaveLayer::Create(context, saveLayerBounds, &paint);
|
||||
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
|
||||
PaintChildren(context);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -26,16 +26,29 @@ 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 = default;
|
||||
~OpacityLayer() override;
|
||||
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
|
||||
void Paint(PaintContext& context) const override;
|
||||
void UpdateScene(SceneUpdateContext& context) override;
|
||||
|
||||
// TODO(chinmaygarde): Once SCN-139 is addressed, introduce a new node in the
|
||||
// session scene hierarchy.
|
||||
|
||||
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,81 +5,66 @@
|
||||
#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 {
|
||||
|
||||
constexpr SkScalar kLightHeight = 600;
|
||||
constexpr SkScalar kLightRadius = 800;
|
||||
constexpr bool kRenderPhysicalShapeUsingSystemCompositor = false;
|
||||
const SkScalar kLightHeight = 600;
|
||||
const SkScalar kLightRadius = 800;
|
||||
|
||||
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)) {
|
||||
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.
|
||||
frame_rrect = SkRRect::MakeOval(rect);
|
||||
} else {
|
||||
// Scenic currently doesn't provide an easy way to create shapes from
|
||||
// arbitrary paths.
|
||||
// For shapes that cannot be represented as a rounded rectangle we
|
||||
// default to use the bounding rectangle.
|
||||
// TODO(amirh): fix this once we have a way to create a Scenic shape from
|
||||
// an SkPath.
|
||||
frame_rrect = SkRRect::MakeRect(path.getBounds());
|
||||
}
|
||||
|
||||
set_frame_properties(frame_rrect, color_, /* opacity */ 1.0f);
|
||||
SkRect rect;
|
||||
if (path.isRect(&rect)) {
|
||||
isRect_ = true;
|
||||
frameRRect_ = SkRRect::MakeRect(rect);
|
||||
} else if (path.isRRect(&frameRRect_)) {
|
||||
isRect_ = frameRRect_.isRect();
|
||||
} else if (path.isOval(&rect)) {
|
||||
// isRRect returns false for ovals, so we need to explicitly check isOval
|
||||
// as well.
|
||||
frameRRect_ = SkRRect::MakeOval(rect);
|
||||
} else {
|
||||
// Scenic currently doesn't provide an easy way to create shapes from
|
||||
// arbitrary paths.
|
||||
// For shapes that cannot be represented as a rounded rectangle we
|
||||
// default to use the bounding rectangle.
|
||||
// TODO(amirh): fix this once we have a way to create a Scenic shape from
|
||||
// an SkPath.
|
||||
frameRRect_ = SkRRect::MakeRect(path.getBounds());
|
||||
}
|
||||
set_elevation(elevation);
|
||||
}
|
||||
|
||||
PhysicalShapeLayer::~PhysicalShapeLayer() = default;
|
||||
|
||||
void PhysicalShapeLayer::Preroll(PrerollContext* context,
|
||||
const SkMatrix& matrix) {
|
||||
ContainerLayer::Preroll(context, matrix);
|
||||
context->total_elevation += elevation_;
|
||||
total_elevation_ = context->total_elevation;
|
||||
SkRect child_paint_bounds;
|
||||
PrerollChildren(context, matrix, &child_paint_bounds);
|
||||
context->total_elevation -= elevation_;
|
||||
|
||||
// Compute paint bounds based on the layer's elevation.
|
||||
set_paint_bounds(path_.getBounds());
|
||||
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);
|
||||
|
||||
// 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());
|
||||
}
|
||||
if (elevation_ == 0) {
|
||||
set_paint_bounds(path_.getBounds());
|
||||
} else {
|
||||
#if defined(OS_FUCHSIA)
|
||||
// Let the system compositor draw all shadows for us.
|
||||
set_needs_system_composite(true);
|
||||
#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.
|
||||
@@ -115,46 +100,55 @@ 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 * context->frame_device_pixel_ratio +
|
||||
bounds.width() * 0.5) /
|
||||
double tx = (kLightRadius * device_pixel_ratio_ + bounds.width() * 0.5) /
|
||||
kLightHeight;
|
||||
// tangent for y
|
||||
double ty = (kLightRadius * context->frame_device_pixel_ratio +
|
||||
bounds.height() * 0.5) /
|
||||
double ty = (kLightRadius * 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());
|
||||
|
||||
// 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);
|
||||
if (elevation_ != 0) {
|
||||
DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
|
||||
SkColorGetA(color_) != 0xff, device_pixel_ratio_);
|
||||
}
|
||||
|
||||
// Call drawPath without clip if possible for better performance.
|
||||
@@ -189,7 +183,7 @@ void PhysicalShapeLayer::Paint(PaintContext& context) const {
|
||||
context.leaf_nodes_canvas->drawPaint(paint);
|
||||
}
|
||||
|
||||
ContainerLayer::Paint(context);
|
||||
PaintChildren(context);
|
||||
|
||||
context.internal_nodes_canvas->restoreToCount(saveCount);
|
||||
}
|
||||
|
||||
@@ -13,13 +13,12 @@ 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 = default;
|
||||
|
||||
void Preroll(PrerollContext* context, const SkMatrix& matrix) override;
|
||||
void Paint(PaintContext& context) const override;
|
||||
~PhysicalShapeLayer() override;
|
||||
|
||||
static void DrawShadow(SkCanvas* canvas,
|
||||
const SkPath& path,
|
||||
@@ -28,11 +27,27 @@ 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,6 +16,8 @@ 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);
|
||||
}
|
||||
@@ -38,8 +40,6 @@ 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 (clamped to 6.0f)
|
||||
// | layers[3] +4.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(), 6.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);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user